From 67d736b55a495ec1ac46a59a006d428ced97de96 Mon Sep 17 00:00:00 2001 From: Adam Michael Date: Thu, 6 Oct 2016 21:31:57 +0000 Subject: Handles missing classes.jar in aar_import gracefully, by creating an empty jar file instead of crashing Bazel. -- MOS_MIGRATED_REVID=135405636 --- tools/zip/BUILD | 12 ++++++++ tools/zip/BUILD.tools | 6 ++++ tools/zip/embedded_jar_extractor.py | 53 ++++++++++++++++++++++++++++++++ tools/zip/embedded_jar_extractor_test.py | 50 ++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 tools/zip/embedded_jar_extractor.py create mode 100644 tools/zip/embedded_jar_extractor_test.py (limited to 'tools') diff --git a/tools/zip/BUILD b/tools/zip/BUILD index cfb986b993..4ccf9f7273 100644 --- a/tools/zip/BUILD +++ b/tools/zip/BUILD @@ -17,3 +17,15 @@ sh_test( srcs = ["zip_manifest_creator_test.sh"], data = [":zip_manifest_creator"], ) + +py_binary( + name = "embedded_jar_extractor", + srcs = ["embedded_jar_extractor.py"], + deps = ["//third_party/py/gflags"], +) + +py_test( + name = "embedded_jar_extractor_test", + srcs = ["embedded_jar_extractor_test.py"], + deps = [":embedded_jar_extractor"], +) diff --git a/tools/zip/BUILD.tools b/tools/zip/BUILD.tools index 58f9267f2f..542ddce946 100644 --- a/tools/zip/BUILD.tools +++ b/tools/zip/BUILD.tools @@ -10,3 +10,9 @@ sh_binary( srcs = ["zip_manifest_creator.sh"], data = [":zipper"], ) + +py_binary( + name = "embedded_jar_extractor", + srcs = ["embedded_jar_extractor.py"], + deps = ["//third_party/py/gflags"], +) diff --git a/tools/zip/embedded_jar_extractor.py b/tools/zip/embedded_jar_extractor.py new file mode 100644 index 0000000000..1111b2993e --- /dev/null +++ b/tools/zip/embedded_jar_extractor.py @@ -0,0 +1,53 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""A tool for extracting a jar file from an archive and failing gracefully. + +If the jar file is present within the archive, it is extracted into the output +directory. If not, an empty jar is created in the output directory. +""" + +import os +import sys +import zipfile + +from third_party.py import gflags + +FLAGS = gflags.FLAGS + +gflags.DEFINE_string("input_archive", None, "Input archive") +gflags.MarkFlagAsRequired("input_archive") +gflags.DEFINE_string("filename", None, "Filename of JAR to extract") +gflags.MarkFlagAsRequired("filename") +gflags.DEFINE_string("output_dir", None, "Output directory") +gflags.MarkFlagAsRequired("output_dir") + + +def ExtractEmbeddedJar(input_archive, filename, output_dir): + with zipfile.ZipFile(input_archive, "r") as archive: + if filename in archive.namelist(): + archive.extract(filename, output_dir) + else: + with zipfile.ZipFile(os.path.join(output_dir, filename), "w") as jar: + # All jar files must contain META-INF/MANIFEST.MF. + jar.writestr("META-INF/MANIFEST.MF", ("Manifest-Version: 1.0\n" + "Created-By: Bazel\n")) + + +def main(): + ExtractEmbeddedJar(FLAGS.input_archive, FLAGS.filename, FLAGS.output_dir) + +if __name__ == "__main__": + FLAGS(sys.argv) + main() diff --git a/tools/zip/embedded_jar_extractor_test.py b/tools/zip/embedded_jar_extractor_test.py new file mode 100644 index 0000000000..568e0b3366 --- /dev/null +++ b/tools/zip/embedded_jar_extractor_test.py @@ -0,0 +1,50 @@ +# Copyright 2016 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for embedded_jar_extractor.""" + +import filecmp +import os +import unittest +import zipfile + +from tools.zip import embedded_jar_extractor + + +class EmbeddedJarExtractorTest(unittest.TestCase): + """Unit tests for embedded_jar_extractor.py.""" + + def testPassingJarFile(self): + bjar = zipfile.ZipFile("b.jar", "w") + bjar.close() + azip = zipfile.ZipFile("a.zip", "w") + azip.write("b.jar") + azip.close() + if not os.path.exists("output"): + os.mkdir("output") + embedded_jar_extractor.ExtractEmbeddedJar("a.zip", "b.jar", "output") + self.assertTrue(filecmp.cmp("b.jar", "output/b.jar")) + + def testMissingJarFile(self): + azip = zipfile.ZipFile("a.zip", "w") + azip.close() + if not os.path.exists("output"): + os.mkdir("output") + embedded_jar_extractor.ExtractEmbeddedJar("a.zip", "b.jar", "output") + bjar = zipfile.ZipFile("output/b.jar", "r") + self.assertEqual(["META-INF/MANIFEST.MF"], bjar.namelist()) + + +if __name__ == "__main__": + unittest.main() -- cgit v1.2.3