aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/android
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2017-09-27 07:38:03 -0400
committerGravatar John Cater <jcater@google.com>2017-09-27 10:01:41 -0400
commitc60bfdf2b665888cbc22d8f35ea312a439e136b3 (patch)
tree7f12bc7267eb34c7cf48ec2e05b682657cde3651 /tools/android
parentec91d20a0960ad9d67d27db7c8d1ecdd425d8085 (diff)
Windows, aar_resources_extractor: longpath bugfix
Fix a bug in the Android tool aar_resources_extractor: open the compressed data and the target file as file descriptores, rather than using aar.extract. This way we can shorten the directories in the relative path of the extracted file, because we can open the target file via a junction and thus work around long path limitations. //tools/android:aar_resources_extractor_test now passes on Windows. Change-Id: I9f5c7de2279ad8769e53e015b8334a58a76cd989 PiperOrigin-RevId: 170181143
Diffstat (limited to 'tools/android')
-rw-r--r--tools/android/aar_resources_extractor.py46
-rw-r--r--tools/android/aar_resources_extractor_test.py18
2 files changed, 49 insertions, 15 deletions
diff --git a/tools/android/aar_resources_extractor.py b/tools/android/aar_resources_extractor.py
index eb0d432027..61f9f4d397 100644
--- a/tools/android/aar_resources_extractor.py
+++ b/tools/android/aar_resources_extractor.py
@@ -40,23 +40,49 @@ gflags.MarkFlagAsRequired("output_res_dir")
def ExtractResources(aar, output_res_dir):
"""Extract resource from an `aar` file to the `output_res_dir` directory."""
aar_contains_no_resources = True
- output_res_dir_abs = os.path.normpath(
- os.path.join(os.getcwd(), output_res_dir))
+ output_res_dir_abs = os.path.abspath(output_res_dir)
for name in aar.namelist():
if name.startswith("res/"):
- fullpath = os.path.normpath(os.path.join(output_res_dir_abs, name))
- if os.name == "nt" and len(fullpath) >= 260: # MAX_PATH in <windows.h>
- with junction.TempJunction(os.path.dirname(fullpath)) as juncpath:
- shortpath = os.path.join(juncpath, os.path.basename(fullpath))
- aar.extract(name, shortpath)
+ if os.name == "nt":
+ fullpath = os.path.normpath(os.path.join(output_res_dir_abs, name))
+ if name[-1] == "/":
+ # The zip entry is a directory. Create a junction to it, which also
+ # takes care of creating the directory and all of its parents in a
+ # longpath-safe manner.
+ # We must pretend to have extracted this directory, even if it's
+ # empty, therefore we mustn't rely on creating it as a parent
+ # directory of a subsequently extracted zip entry (because there may
+ # be no such subsequent entry).
+ with junction.TempJunction(fullpath.rstrip("/")) as juncpath:
+ pass
+ else:
+ # The zip entry is a file. Create a junction to its parent directory,
+ # then open the compressed entry as a file object, so we can extract
+ # the data even if the extracted file's path would be too long.
+ # The tradeoff is that we lose the permission bits of the compressed
+ # file, but Unix permissions don't mean much on Windows anyway.
+ with junction.TempJunction(os.path.dirname(fullpath)) as juncpath:
+ extracted_path = os.path.join(juncpath, os.path.basename(fullpath))
+ with aar.open(name) as src_fd:
+ with open(extracted_path, "wb") as dest_fd:
+ dest_fd.write(src_fd.read())
else:
aar.extract(name, output_res_dir)
aar_contains_no_resources = False
+
if aar_contains_no_resources:
empty_xml_filename = output_res_dir + "/res/values/empty.xml"
- os.makedirs(os.path.dirname(empty_xml_filename))
- with open(empty_xml_filename, "wb") as empty_xml:
- empty_xml.write("<resources/>")
+ if os.name == "nt":
+ # Create a junction to the parent directory, because its path might be too
+ # long. Creating the junction also creates all parent directories.
+ with junction.TempJunction(os.path.dirname(empty_xml_filename)) as junc:
+ xmlpath = os.path.join(junc, os.path.basename(empty_xml_filename))
+ with open(xmlpath, "wb") as empty_xml:
+ empty_xml.write("<resources/>")
+ else:
+ os.makedirs(os.path.dirname(empty_xml_filename))
+ with open(empty_xml_filename, "wb") as empty_xml:
+ empty_xml.write("<resources/>")
def main():
diff --git a/tools/android/aar_resources_extractor_test.py b/tools/android/aar_resources_extractor_test.py
index b59e4160cb..d5f630b352 100644
--- a/tools/android/aar_resources_extractor_test.py
+++ b/tools/android/aar_resources_extractor_test.py
@@ -23,6 +23,10 @@ import zipfile
from tools.android import aar_resources_extractor
+def _HostPath(path):
+ return os.path.normpath(path)
+
+
class AarResourcesExtractorTest(unittest.TestCase):
"""Unit tests for aar_resources_extractor.py."""
@@ -33,14 +37,16 @@ class AarResourcesExtractorTest(unittest.TestCase):
shutil.rmtree("out_dir")
def DirContents(self, d):
- return [path + "/" + f for (path, _, files) in os.walk(d)
- for f in files]
+ return [
+ _HostPath(path + "/" + f)
+ for (path, _, files) in os.walk(d) for f in files
+ ]
def testNoResources(self):
aar = zipfile.ZipFile(StringIO.StringIO(), "w")
os.makedirs("out_dir")
aar_resources_extractor.ExtractResources(aar, "out_dir")
- self.assertEqual(["out_dir/res/values/empty.xml"],
+ self.assertEqual([_HostPath("out_dir/res/values/empty.xml")],
self.DirContents("out_dir"))
with open("out_dir/res/values/empty.xml", "r") as empty_xml:
self.assertEqual("<resources/>", empty_xml.read())
@@ -51,8 +57,10 @@ class AarResourcesExtractorTest(unittest.TestCase):
aar.writestr("res/layouts/layout.xml", "some layout")
os.makedirs("out_dir")
aar_resources_extractor.ExtractResources(aar, "out_dir")
- expected_resources = ["out_dir/res/values/values.xml",
- "out_dir/res/layouts/layout.xml"]
+ expected_resources = [
+ _HostPath("out_dir/res/values/values.xml"),
+ _HostPath("out_dir/res/layouts/layout.xml")
+ ]
self.assertItemsEqual(expected_resources, self.DirContents("out_dir"))
with open("out_dir/res/values/values.xml", "r") as values_xml:
self.assertEqual("some values", values_xml.read())