diff options
-rw-r--r-- | tools/android/aar_resources_extractor.py | 46 | ||||
-rw-r--r-- | tools/android/aar_resources_extractor_test.py | 18 |
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()) |