aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party
diff options
context:
space:
mode:
authorGravatar Lukacs T. Berki <lberki@google.com>2017-04-18 14:23:19 +0200
committerGravatar Lukacs T. Berki <lberki@google.com>2017-04-18 14:35:16 +0200
commit55828e256af4fe04e95f1c342a73d649d8525435 (patch)
treee9eb87f376897af767937ef71b126dac94f60a42 /third_party
parentdf8d804acb5826a120cad9acfc78dd6f0071d864 (diff)
Vendor jarjar instead of using a binary version of it.
It appears that jarjar is not actually used except for renaming classes in the coverage collecting Java test runner as verified by `find . -name BUILD | xargs grep jarjar` Yak shaving for #2820. This is necessary because the current version of jarjar does not work with Java 8 classes because it embeds a version of ASM that doesn't support that yet. Change-Id: I6ac59b84bbbc1e85fe8e7f4f4876b98fc6129df0
Diffstat (limited to 'third_party')
-rw-r--r--third_party/java/jarjar/BUILD22
-rw-r--r--third_party/java/jarjar/COPYING202
-rw-r--r--third_party/java/jarjar/README.bazel.md6
-rw-r--r--third_party/java/jarjar/README.md184
-rw-r--r--third_party/java/jarjar/build.gradle148
-rw-r--r--third_party/java/jarjar/codequality/HEADER13
-rw-r--r--third_party/java/jarjar/codequality/checkstyle.xml188
-rw-r--r--third_party/java/jarjar/gradle.properties1
-rw-r--r--third_party/java/jarjar/gradle/buildscript.gradle11
-rw-r--r--third_party/java/jarjar/gradle/plugin.gradle20
-rw-r--r--third_party/java/jarjar/gradle/wrapper/gradle-wrapper.jarbin0 -> 51018 bytes
-rw-r--r--third_party/java/jarjar/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xthird_party/java/jarjar/gradlew164
-rw-r--r--third_party/java/jarjar/gradlew.bat90
-rw-r--r--third_party/java/jarjar/jarjar-ant/build.gradle0
-rw-r--r--third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/JarJarTask.java67
-rw-r--r--third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Keep.java13
-rw-r--r--third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/PatternElement.java38
-rw-r--r--third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Rule.java23
-rw-r--r--third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Zap.java13
-rw-r--r--third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/util/AntJarProcessor.java120
-rw-r--r--third_party/java/jarjar/jarjar-command/build.gradle0
-rw-r--r--third_party/java/jarjar/jarjar-command/src/main/java/com/tonicsystems/jarjar/Main.java147
-rw-r--r--third_party/java/jarjar/jarjar-command/src/test/resources/com/tonicsystems/jarjar/help.txt75
-rw-r--r--third_party/java/jarjar/jarjar-core/build.gradle0
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPath.java71
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathArchive.java200
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathResource.java40
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/AbstractDependencyHandler.java53
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/ClassHeaderReader.java188
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Dependency.java44
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinder.java74
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinderClassVisitor.java69
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyHandler.java32
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Pair.java57
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/TextDependencyHandler.java33
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringDumper.java111
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringReader.java114
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/JarTransformer.java132
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/Transformable.java23
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/ClassTransformer.java19
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/GetNameClassWriter.java44
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/PackageRemapper.java138
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/RemappingClassTransformer.java30
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractClassPattern.java26
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractPattern.java68
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractResourcePattern.java20
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassDelete.java31
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeep.java30
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeepTransitive.java30
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassRename.java44
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/PatternUtils.java245
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ResourceRename.java44
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/RulesFileParser.java105
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/AbstractFilterJarProcessor.java47
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassClosureJarProcessor.java143
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassFilterJarProcessor.java83
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassTransformerJarProcessor.java73
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DefaultJarProcessor.java72
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DirectoryFilterJarProcessor.java24
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessor.java48
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessorChain.java50
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ManifestFilterJarProcessor.java48
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/PathFilterJarProcessor.java36
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ResourceRenamerJarProcessor.java46
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/ClassNameUtils.java79
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/IoUtil.java60
-rw-r--r--third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/RuntimeIOException.java28
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/GenericsTest.java33
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/PackageRemapperTest.java60
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/RulesFileParserTest.java26
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/WildcardTest.java47
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/AbstractJarTransformerTest.java52
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/JarTransformerTest.java54
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/resources/Generics.classbin0 -> 575 bytes
-rw-r--r--third_party/java/jarjar/jarjar-core/src/test/resources/enumtest.jarbin0 -> 1324 bytes
-rw-r--r--third_party/java/jarjar/jarjar-gradle/build.gradle0
-rw-r--r--third_party/java/jarjar/jarjar-gradle/example/build.gradle130
-rw-r--r--third_party/java/jarjar/jarjar-gradle/example/settings.gradle2
-rw-r--r--third_party/java/jarjar/jarjar-gradle/example/src/main/java/org/anarres/jarjar/test/Main.java7
-rw-r--r--third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarArchiveTask.java32
-rw-r--r--third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarController.java60
-rw-r--r--third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarCopyAction.java137
-rw-r--r--third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarDependency.java67
-rw-r--r--third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarPlugin.java41
-rw-r--r--third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarTask.java232
-rw-r--r--third_party/java/jarjar/jarjar-gradle/src/test/java/org/anarres/gradle/plugin/jarjar/JarjarDependencyTest.java21
-rw-r--r--third_party/java/jarjar/jarjar-maven/build.gradle0
-rw-r--r--third_party/java/jarjar/jarjar-maven/src/main/java/com/tonicsystems/jarjar/JarJarMojo.java57
-rw-r--r--third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg0/Main.java21
-rw-r--r--third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg1/Cls1.java24
-rw-r--r--third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg2/Cls2.java24
-rw-r--r--third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg3/Cls3.java19
-rw-r--r--third_party/java/jarjar/settings.gradle7
-rw-r--r--third_party/java/jarjar/src/main/ghpages/index.html6
95 files changed, 5657 insertions, 5 deletions
diff --git a/third_party/java/jarjar/BUILD b/third_party/java/jarjar/BUILD
index 8f31f169c6..a13054f06d 100644
--- a/third_party/java/jarjar/BUILD
+++ b/third_party/java/jarjar/BUILD
@@ -7,13 +7,25 @@ filegroup(
srcs = glob(["**"]),
)
-java_import(
- name = "jarjar",
- jars = ["jarjar-1.4.jar"],
+java_library(
+ name = "jarjar_core",
+ srcs = glob(["jarjar-core/src/main/**/*.java"]),
+ deps = [
+ "//third_party:asm",
+ "//third_party:asm-commons",
+ "//third_party:asm-util",
+ "//third_party:jsr305",
+ "//third_party:slf4j",
+ ],
)
java_binary(
- name = "jarjar_bin",
+ name = "jarjar_command",
+ srcs = glob(["jarjar-command/src/main/**/*.java"]),
main_class = "com.tonicsystems.jarjar.Main",
- runtime_deps = [":jarjar"],
+ deps = [
+ ":jarjar_core",
+ "//third_party:jsr305",
+ "//third_party/java/jopt-simple",
+ ],
)
diff --git a/third_party/java/jarjar/COPYING b/third_party/java/jarjar/COPYING
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/third_party/java/jarjar/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/third_party/java/jarjar/README.bazel.md b/third_party/java/jarjar/README.bazel.md
new file mode 100644
index 0000000000..8a71e818ce
--- /dev/null
+++ b/third_party/java/jarjar/README.bazel.md
@@ -0,0 +1,6 @@
+This is jarjar. They don't seem to tag their releases, so I just used whatever was at HEAD. Reproduction:
+
+1. `git clone https://github.com/shevek/jarjar`
+2. `git checkout 69d2972ea10eefa66cdc2c1c283cb6ef79b3c5ba`
+3. Copy the git tree to `third_party/java/jarjar`
+4. Keep the existing `BUILD` file
diff --git a/third_party/java/jarjar/README.md b/third_party/java/jarjar/README.md
new file mode 100644
index 0000000000..6d7097c41f
--- /dev/null
+++ b/third_party/java/jarjar/README.md
@@ -0,0 +1,184 @@
+Jar Jar Links is a utility that makes it easy to repackage Java
+libraries and embed them into your own distribution. This is useful
+for two reasons:
+
+You can easily ship a single jar file with no external dependencies.
+
+You can avoid problems where your library depends on a specific
+version of a library, which may conflict with the dependencies of
+another library.
+
+How does it work?
+
+Jar Jar Links includes an Ant task that extends the built-in jar
+task. The normal zipfileset element is used to embed jar files. A
+new rule element is added which uses wildcards patterns to rename
+the embedded class files. Bytecode transformation (via ASM) is used
+to change references to the renamed classes, and special handling is
+provided for moving resource files and transforming string literals.
+
+Using with ant
+--------------
+
+In our imaginary project, the Ant "jar" target looks like:
+
+```
+<target name="jar" depends="compile">
+ <jar jarfile="dist/example.jar">
+ <fileset dir="build/main"/>
+ </jar>
+</target>
+```
+
+To use Jar Jar Links, we define a new task named "jarjar", and
+substitute it wherever we used the jar task. Because the JarJarTask
+class extends the normal Ant Jar task, you can use jarjar without
+any of its additional features, if you want:
+
+```
+<target name="jar" depends="compile">
+ <taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask"
+ classpath="lib/jarjar.jar"/>
+ <jarjar jarfile="dist/example.jar">
+ <fileset dir="build/main"/>
+ </jarjar>
+</target>
+```
+
+Just like with the "jar" task, we can include the contents of another
+jar file using the "zipfileset" element. But simply including another
+projects classes is not good enough to avoid jar hell, since the class
+names remain unchanged and can still conflict with other versions.
+
+To rename the classes, JarJarTask adds a new "rule" element. The
+rule takes a "pattern" attribute, which uses wildcards to match
+against class names, and a "result" attribute, which describes how
+to transform the matched names.
+
+In this example we include classes from jaxen.jar and add a rule
+that changes any class name starting with "org.jaxen" to start with
+"org.example.jaxen" instead (in our imaginary world we control the
+example.org domain):
+
+```
+<target name="jar" depends="compile">
+ <taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask"
+ classpath="lib/jarjar.jar"/>
+ <jarjar jarfile="dist/example.jar">
+ <fileset dir="build/main"/>
+ <zipfileset src="lib/jaxen.jar"/>
+ <rule pattern="org.jaxen.**" result="org.example.@1"/>
+ </jarjar>
+</target>
+```
+
+The ** in the pattern means to match against any valid package
+substring. To match against a single package component (by excluding
+dots (.) from the match), a single * may be used instead.
+
+The @1 in the result is a reference to the ** portion of the rule. For
+every * or ** in the rule, a numbered reference is available for use
+in the result. References are numbered from left to right, starting
+with @1, then @2, and so on.
+
+The special @0 reference refers to the entire class name.
+
+Using with gradle
+-----------------
+
+```
+ dependencies {
+ // Use jarjar.repackage in place of a dependency notation.
+ compile jarjar.repackage {
+ from 'com.google.guava:guava:18.0'
+
+ classDelete "com.google.common.base.**"
+
+ classRename "com.google.**" "org.private.google.@1"
+ }
+ }
+```
+
+See (jarjar-gradle/example/build.gradle) for some complete examples.
+
+Using from the command line
+---------------------------
+
+From the command-line
+
+```
+java -jar jarjar.jar [help]
+```
+
+Prints this help message.
+
+```
+java -jar jarjar.jar strings <cp>
+```
+
+Dumps all string literals in classpath `<cp>`. Line numbers will be
+included if the classes have debug information.
+
+```
+java -jar jarjar.jar find <level> <cp1> [<cp2>]
+```
+
+Prints dependencies on classpath `<cp2>` in classpath `<cp1>`. If `<cp2>`
+is omitted, `<cp1>` is used for both arguments.
+
+The level argument must be class or jar. The former prints dependencies
+between individual classes, while the latter only prints jar->jar
+dependencies. A "jar" in this context is actually any classpath
+component, which can be a jar file, a zip file, or a parent directory
+(see below).
+
+```
+java -jar jarjar.jar process <rulesFile> <inJar> <outJar>
+```
+
+Transform the `<inJar>` jar file, writing a new jar file to `<outJar>`. Any
+existing file named by `<outJar>` will be deleted.
+
+The transformation is defined by a set of rules in the file specified
+by the rules argument (see below). Classpath format
+
+The classpath argument is a colon or semi-colon delimited
+set (depending on platform) of directories, jar files,
+or zip files. See the following page for more details:
+http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/classpath.html
+
+Mustang-style wildcards are also supported:
+http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6268383 Rules
+file format
+
+The rules file is a text file, one rule per line. Leading and trailing
+whitespace is ignored. There are three types of rules:
+
+```
+rule <pattern> <result>
+zap <pattern>
+keep <pattern>
+```
+
+The standard rule (rule) is used to rename classes. All references to
+the renamed classes will also be updated. If a class name is matched
+by more than one rule, only the first one will apply.
+
+`<pattern>` is a class name with optional wildcards. `**` will match
+against any valid class name substring. To match a single package
+component (by excluding . from the match), a single `*` may be used
+instead.
+
+`<result>` is a class name which can optionally reference the substrings
+matched by the wildcards. A numbered reference is available for every
+`*` or `**` in the `<pattern>`, starting from left to right: @1, @2, etc. A
+special @0 reference contains the entire matched class name.
+
+The zap rule causes any matched class to be removed from the resulting
+jar file. All zap rules are processed before renaming rules.
+
+The keep rule marks all matched classes as "roots". If any keep rules
+are defined all classes which are not reachable from the roots via
+dependency analysis are discarded when writing the output jar. This
+is the last step in the process, after renaming and zapping.
+
diff --git a/third_party/java/jarjar/build.gradle b/third_party/java/jarjar/build.gradle
new file mode 100644
index 0000000000..4789994ad6
--- /dev/null
+++ b/third_party/java/jarjar/build.gradle
@@ -0,0 +1,148 @@
+buildscript {
+ apply from: file('gradle/buildscript.gradle'), to: buildscript
+}
+
+apply plugin: 'org.anarres.stdproject'
+stdproject {
+}
+
+subprojects {
+ apply plugin: 'org.anarres.stdmodule'
+ stdmodule {
+ description "Jar Jar Links is a utility that makes it easy to repackage Java libraries and embed them into your own distribution."
+ author id: 'shevek', name: 'Shevek', email: 'github@anarres.org'
+ license 'Apache-2.0'
+ }
+
+ group = "org.anarres.jarjar"
+
+ dependencies {
+ compile 'com.google.code.findbugs:jsr305:2.0.2'
+ compile 'org.slf4j:slf4j-api:1.7.12'
+ }
+
+ sourceCompatibility = 1.5
+ animalsniffer {
+ signature = "org.codehaus.mojo.signature:java15:+@signature"
+ }
+}
+
+project(':jarjar-testdata') {
+ dependencies {
+ compile 'com.google.guava:guava:17.0'
+ }
+
+ for (int i = 0; i < 4; i++) {
+ String name = "jar$i";
+ Task t = task(name, type: Jar) {
+ classifier = name
+ from(sourceSets.main.output) {
+ include "**/pkg$i/**";
+ }
+ }
+
+ artifacts {
+ archives t
+ }
+ }
+
+/*
+ assemble << {
+ println configurations.archives.dump()
+ println "\nArtifacts:\n" + configurations.archives.artifacts.dump()
+ println "\nFiles:\n" + configurations.archives.files.dump()
+ println "\nEach:\n"
+ for (Object o : configurations.archives.artifacts.files) {
+ println o.dump()
+ }
+ // println configurations.archives
+ println jar0.dump()
+ println jar0.archivePath
+ }
+*/
+
+ uploadArchives.enabled = false
+}
+
+project(':jarjar-core') {
+ dependencies {
+ compile 'org.ow2.asm:asm-commons:5.0.3'
+ compile 'org.ow2.asm:asm-util:5.0.3'
+ // compile 'org.ow2.asm:asm-commons:4.0'
+
+ // testCompile project(':jarjar-testdata')
+ }
+
+ def samplesProject = project(':jarjar-testdata')
+ test.dependsOn samplesProject.tasks['assemble']
+ test {
+ systemProperty "jar", samplesProject.jar.archivePath
+ for (int i = 0; i < 4; i++) {
+ systemProperty "jar$i", samplesProject."jar$i".archivePath
+ }
+ }
+}
+
+project(':jarjar-ant') {
+ dependencies {
+ compile project(':jarjar-core')
+ compile 'org.apache.ant:ant:1.7.0'
+
+ testCompile project(':jarjar-core').sourceSets.test.output
+ }
+}
+
+project(':jarjar-maven') {
+ dependencies {
+ compile project(':jarjar-core')
+ compile 'org.apache.maven:maven-plugin-api:2.0'
+
+ testCompile project(':jarjar-core').sourceSets.test.output
+ }
+}
+
+project(':jarjar-gradle') {
+ apply plugin: 'org.anarres.stdplugin'
+
+ stdplugin {
+ implementation "org.anarres.jarjar", "org.anarres.gradle.plugin.jarjar.JarjarPlugin"
+ }
+
+/*
+ tasks.removeAll {
+ // println it.dump();
+ // println it.name;
+ return it.name == "sourcesJar";
+ }
+
+ // apply plugin: 'java-gradle-plugin'
+ // apply plugin: 'nu.studer.plugindev'
+ // apply from: file('../gradle/plugin.gradle')
+*/
+
+ dependencies {
+ compile project(':jarjar-core')
+ compile 'org.apache.commons:commons-compress:1.9'
+ compile gradleApi()
+ compile 'oro:oro:2.0.8'
+
+ testCompile project(':jarjar-core').sourceSets.test.output
+ }
+
+ animalsniffer {
+ skip = true
+ }
+}
+
+project(':jarjar-command') {
+ dependencies {
+ compile project(':jarjar-core')
+ compile 'net.sf.jopt-simple:jopt-simple:4.8'
+
+ testCompile project(':jarjar-core').sourceSets.test.output
+ }
+
+ apply plugin: 'application'
+
+ mainClassName = "com.tonicsystems.jarjar.Main"
+}
diff --git a/third_party/java/jarjar/codequality/HEADER b/third_party/java/jarjar/codequality/HEADER
new file mode 100644
index 0000000000..169c3d19a3
--- /dev/null
+++ b/third_party/java/jarjar/codequality/HEADER
@@ -0,0 +1,13 @@
+Copyright ${year} Shevek.
+
+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.
diff --git a/third_party/java/jarjar/codequality/checkstyle.xml b/third_party/java/jarjar/codequality/checkstyle.xml
new file mode 100644
index 0000000000..47c01a2ea1
--- /dev/null
+++ b/third_party/java/jarjar/codequality/checkstyle.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
+
+<module name="Checker">
+
+ <!-- Checks that a package-info.java file exists for each package. -->
+ <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->
+ <!--
+ <module name="JavadocPackage">
+ <property name="allowLegacy" value="true"/>
+ </module>
+ -->
+
+ <!-- Checks whether files end with a new line. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
+ <module name="NewlineAtEndOfFile"/>
+
+ <!-- Checks that property files contain the same keys. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
+ <module name="Translation"/>
+
+ <!-- Checks for Size Violations. -->
+ <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <module name="FileLength"/>
+
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <module name="FileTabCharacter"/>
+
+ <!-- Miscellaneous other checks. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html -->
+ <module name="RegexpSingleline">
+ <property name="format" value="\s+$"/>
+ <property name="minimum" value="0"/>
+ <property name="maximum" value="0"/>
+ <property name="message" value="Line has trailing spaces."/>
+ <property name="severity" value="info"/>
+ </module>
+
+ <module name="TreeWalker">
+
+ <!-- Checks for Javadoc comments. -->
+ <!-- See http://checkstyle.sf.net/config_javadoc.html -->
+ <module name="JavadocMethod">
+ <property name="scope" value="package"/>
+ <property name="allowMissingParamTags" value="true"/>
+ <property name="allowMissingThrowsTags" value="true"/>
+ <property name="allowMissingReturnTag" value="true"/>
+ <property name="allowThrowsTagsForSubclasses" value="true"/>
+ <property name="allowUndeclaredRTE" value="true"/>
+ <property name="allowMissingPropertyJavadoc" value="true"/>
+ </module>
+ <module name="JavadocType">
+ <property name="scope" value="package"/>
+ </module>
+ <module name="JavadocVariable">
+ <property name="scope" value="package"/>
+ </module>
+ <module name="JavadocStyle">
+ <property name="checkEmptyJavadoc" value="true"/>
+ </module>
+
+ <!-- Checks for Naming Conventions. -->
+ <!-- See http://checkstyle.sf.net/config_naming.html -->
+ <module name="ConstantName"/>
+ <module name="LocalFinalVariableName"/>
+ <module name="LocalVariableName"/>
+ <module name="MemberName"/>
+ <module name="MethodName"/>
+ <module name="PackageName"/>
+ <module name="ParameterName"/>
+ <module name="StaticVariableName"/>
+ <module name="TypeName"/>
+
+ <!-- Checks for imports -->
+ <!-- See http://checkstyle.sf.net/config_import.html -->
+ <module name="AvoidStarImport"/>
+ <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
+ <module name="RedundantImport"/>
+ <module name="UnusedImports"/>
+
+
+ <!-- Checks for Size Violations. -->
+ <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <module name="LineLength">
+ <!-- what is a good max value? -->
+ <property name="max" value="120"/>
+ <!-- ignore lines like "$File: //depot/... $" -->
+ <property name="ignorePattern" value="\$File.*\$"/>
+ <property name="severity" value="info"/>
+ </module>
+ <module name="MethodLength"/>
+ <module name="ParameterNumber"/>
+
+
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <module name="EmptyForIteratorPad"/>
+ <module name="GenericWhitespace"/>
+ <module name="MethodParamPad"/>
+ <module name="NoWhitespaceAfter"/>
+ <module name="NoWhitespaceBefore"/>
+ <module name="OperatorWrap"/>
+ <module name="ParenPad"/>
+ <module name="TypecastParenPad"/>
+ <module name="WhitespaceAfter"/>
+ <module name="WhitespaceAround"/>
+
+ <!-- Modifier Checks -->
+ <!-- See http://checkstyle.sf.net/config_modifiers.html -->
+ <module name="ModifierOrder"/>
+ <module name="RedundantModifier"/>
+
+
+ <!-- Checks for blocks. You know, those {}'s -->
+ <!-- See http://checkstyle.sf.net/config_blocks.html -->
+ <module name="AvoidNestedBlocks"/>
+ <module name="EmptyBlock">
+ <property name="option" value="text"/>
+ </module>
+ <module name="LeftCurly"/>
+ <module name="NeedBraces"/>
+ <module name="RightCurly"/>
+
+
+ <!-- Checks for common coding problems -->
+ <!-- See http://checkstyle.sf.net/config_coding.html -->
+ <!-- <module name="AvoidInlineConditionals"/> -->
+ <module name="EmptyStatement"/>
+ <module name="EqualsHashCode"/>
+ <module name="HiddenField">
+ <property name="ignoreConstructorParameter" value="true"/>
+ <property name="ignoreSetter" value="true"/>
+ <property name="severity" value="warning"/>
+ </module>
+ <module name="IllegalInstantiation"/>
+ <module name="InnerAssignment"/>
+ <module name="MagicNumber">
+ <property name="severity" value="warning"/>
+ </module>
+ <module name="MissingSwitchDefault"/>
+ <!-- Problem with finding exception types... -->
+ <module name="RedundantThrows">
+ <property name="allowUnchecked" value="true"/>
+ <property name="suppressLoadErrors" value="true"/>
+ <property name="severity" value="info"/>
+ </module>
+ <module name="SimplifyBooleanExpression"/>
+ <module name="SimplifyBooleanReturn"/>
+
+ <!-- Checks for class design -->
+ <!-- See http://checkstyle.sf.net/config_design.html -->
+ <!-- <module name="DesignForExtension"/> -->
+ <module name="FinalClass"/>
+ <module name="HideUtilityClassConstructor"/>
+ <module name="InterfaceIsType"/>
+ <module name="VisibilityModifier"/>
+
+
+ <!-- Miscellaneous other checks. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html -->
+ <module name="ArrayTypeStyle"/>
+ <!-- <module name="FinalParameters"/> -->
+ <module name="TodoComment">
+ <property name="format" value="TODO"/>
+ <property name="severity" value="info"/>
+ </module>
+ <module name="UpperEll"/>
+
+ <module name="FileContentsHolder"/> <!-- Required by comment suppression filters -->
+
+ </module>
+
+ <!-- Enable suppression comments -->
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="CHECKSTYLE IGNORE\s+(\S+)"/>
+ <property name="onCommentFormat" value="CHECKSTYLE END IGNORE\s+(\S+)"/>
+ <property name="checkFormat" value="$1"/>
+ </module>
+ <module name="SuppressWithNearbyCommentFilter">
+ <!-- Syntax is "SUPPRESS CHECKSTYLE name" -->
+ <property name="commentFormat" value="SUPPRESS CHECKSTYLE (\w+)"/>
+ <property name="checkFormat" value="$1"/>
+ <property name="influenceFormat" value="1"/>
+ </module>
+</module>
diff --git a/third_party/java/jarjar/gradle.properties b/third_party/java/jarjar/gradle.properties
new file mode 100644
index 0000000000..aef125e083
--- /dev/null
+++ b/third_party/java/jarjar/gradle.properties
@@ -0,0 +1 @@
+version=1.0.0
diff --git a/third_party/java/jarjar/gradle/buildscript.gradle b/third_party/java/jarjar/gradle/buildscript.gradle
new file mode 100644
index 0000000000..c80830916e
--- /dev/null
+++ b/third_party/java/jarjar/gradle/buildscript.gradle
@@ -0,0 +1,11 @@
+// Executed in context of buildscript
+repositories {
+ mavenLocal()
+ mavenCentral()
+ jcenter()
+ // maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
+}
+
+dependencies {
+ classpath 'org.anarres.gradle:gradle-stdproject-plugin:1.0.2'
+}
diff --git a/third_party/java/jarjar/gradle/plugin.gradle b/third_party/java/jarjar/gradle/plugin.gradle
new file mode 100644
index 0000000000..666d0774bc
--- /dev/null
+++ b/third_party/java/jarjar/gradle/plugin.gradle
@@ -0,0 +1,20 @@
+plugindev {
+ pluginImplementationClass 'org.anarres.gradle.plugin.jarjar.JarjarPlugin'
+ pluginDescription "Jarjar Links makes it easy to repackage Java libraries."
+ pluginLicenses 'Apache-2.0'
+ pluginTags 'gradle', 'plugin', 'jarjar', 'links', 'asm'
+ authorId 'shevek'
+ authorName 'Shevek'
+ authorEmail 'github@anarres.org'
+ projectUrl "https://github.com/shevek/${rootProject.githubProjectName}"
+ projectIssuesUrl "https://github.com/shevek/${rootProject.githubProjectName}/issues"
+ projectVcsUrl "https://github.com/shevek/${rootProject.githubProjectName}.git"
+ projectInceptionYear '2014'
+ done()
+}
+
+bintray {
+ user = rootProject.hasProperty('bintrayUsername')?rootProject.bintrayUsername:''
+ key = rootProject.hasProperty('bintrayApiKey')?rootProject.bintrayApiKey:''
+ pkg.repo = 'gradle-plugins'
+}
diff --git a/third_party/java/jarjar/gradle/wrapper/gradle-wrapper.jar b/third_party/java/jarjar/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..c97a8bdb90
--- /dev/null
+++ b/third_party/java/jarjar/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/third_party/java/jarjar/gradle/wrapper/gradle-wrapper.properties b/third_party/java/jarjar/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..ca384f3642
--- /dev/null
+++ b/third_party/java/jarjar/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Mar 29 22:39:26 PDT 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip
diff --git a/third_party/java/jarjar/gradlew b/third_party/java/jarjar/gradlew
new file mode 100755
index 0000000000..91a7e269e1
--- /dev/null
+++ b/third_party/java/jarjar/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/third_party/java/jarjar/gradlew.bat b/third_party/java/jarjar/gradlew.bat
new file mode 100644
index 0000000000..aec99730b4
--- /dev/null
+++ b/third_party/java/jarjar/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/third_party/java/jarjar/jarjar-ant/build.gradle b/third_party/java/jarjar/jarjar-ant/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-ant/build.gradle
diff --git a/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/JarJarTask.java b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/JarJarTask.java
new file mode 100644
index 0000000000..2f54ad01a7
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/JarJarTask.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.transform.config.ClassDelete;
+import com.tonicsystems.jarjar.transform.config.ClassKeepTransitive;
+import com.tonicsystems.jarjar.transform.config.ClassRename;
+import com.tonicsystems.jarjar.transform.jar.DefaultJarProcessor;
+import com.tonicsystems.jarjar.util.AntJarProcessor;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import org.apache.tools.ant.BuildException;
+
+public class JarJarTask extends AntJarProcessor {
+
+ private DefaultJarProcessor processor = new DefaultJarProcessor();
+
+ @Nonnull
+ private static String checkNotNull(@CheckForNull String in, @Nonnull String msg) {
+ if (in == null)
+ throw new IllegalArgumentException(msg);
+ return in;
+ }
+
+ public void addConfiguredRule(Rule rule) {
+ processor.addClassRename(new ClassRename(
+ checkNotNull(rule.getPattern(), "The <rule> element requires the \"pattern\" attribute."),
+ checkNotNull(rule.getResult(), "The <rule> element requires the \"result\" attribute.")
+ ));
+ }
+
+ public void addConfiguredZap(Zap zap) {
+ processor.addClassDelete(new ClassDelete(
+ checkNotNull(zap.getPattern(), "The <zap> element requires a \"pattern\" attribute.")
+ ));
+ }
+
+ public void addConfiguredKeep(Keep keep) {
+ processor.addClassKeepTransitive(new ClassKeepTransitive(
+ checkNotNull(keep.getPattern(), "The <keep> element requires a \"pattern\" attribute.")
+ ));
+ }
+
+ @Override
+ public void execute() throws BuildException {
+ execute(processor);
+ }
+
+ @Override
+ protected void cleanHelper() {
+ super.cleanHelper();
+ processor = new DefaultJarProcessor();
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Keep.java b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Keep.java
new file mode 100644
index 0000000000..70f407e851
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Keep.java
@@ -0,0 +1,13 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar;
+
+/**
+ *
+ * @author shevek
+ */
+public class Keep extends PatternElement {
+}
diff --git a/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/PatternElement.java b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/PatternElement.java
new file mode 100644
index 0000000000..de6722fcd2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/PatternElement.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import javax.annotation.Nonnull;
+
+/**
+ * This object and its subclasses are also exposed to ant, so need setters for XML.
+ *
+ * @author shevek
+ */
+public abstract class PatternElement {
+
+ private String pattern;
+
+ @Nonnull
+ public String getPattern() {
+ return pattern;
+ }
+
+ public void setPattern(@Nonnull String pattern) {
+ this.pattern = pattern;
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Rule.java b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Rule.java
new file mode 100644
index 0000000000..886d431d16
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Rule.java
@@ -0,0 +1,23 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar;
+
+/**
+ *
+ * @author shevek
+ */
+public class Rule extends PatternElement {
+
+ private String result;
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+ public String getResult() {
+ return result;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Zap.java b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Zap.java
new file mode 100644
index 0000000000..36288574e3
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/Zap.java
@@ -0,0 +1,13 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar;
+
+/**
+ *
+ * @author shevek
+ */
+public class Zap extends PatternElement {
+}
diff --git a/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/util/AntJarProcessor.java b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/util/AntJarProcessor.java
new file mode 100644
index 0000000000..afa229fc88
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-ant/src/main/java/com/tonicsystems/jarjar/util/AntJarProcessor.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.util;
+
+import com.tonicsystems.jarjar.transform.Transformable;
+import com.tonicsystems.jarjar.transform.jar.JarProcessor;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Jar;
+import org.apache.tools.ant.types.ZipFileSet;
+import org.apache.tools.zip.JarMarker;
+import org.apache.tools.zip.ZipExtraField;
+import org.apache.tools.zip.ZipOutputStream;
+
+public abstract class AntJarProcessor extends Jar {
+
+ private final Transformable struct = new Transformable();
+ private JarProcessor proc;
+ private final byte[] buf = new byte[0x2000];
+
+ private final Set<String> dirs = new HashSet<String>();
+ private boolean filesOnly;
+
+ protected boolean verbose;
+
+ private static final ZipExtraField[] JAR_MARKER = new ZipExtraField[]{
+ JarMarker.getInstance()
+ };
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ @Override
+ public abstract void execute() throws BuildException;
+
+ public void execute(JarProcessor proc) throws BuildException {
+ this.proc = proc;
+ super.execute();
+ }
+
+ @Override
+ public void setFilesonly(boolean f) {
+ super.setFilesonly(f);
+ filesOnly = f;
+ }
+
+ @Override
+ protected void zipDir(File dir, ZipOutputStream zOut, String vPath, int mode)
+ throws IOException {
+ }
+
+ // TODO: Rewrite this entirely.
+ @Override
+ protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath,
+ long lastModified, File fromArchive, int mode) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ IoUtil.copy(is, baos, buf);
+ struct.data = baos.toByteArray();
+ struct.name = vPath;
+ struct.time = lastModified;
+ if (proc.process(struct) != JarProcessor.Result.DISCARD) {
+ if (mode == 0)
+ mode = ZipFileSet.DEFAULT_FILE_MODE;
+ if (!filesOnly) {
+ addParentDirs(struct.name, zOut);
+ }
+ super.zipFile(new ByteArrayInputStream(struct.data),
+ zOut, struct.name, struct.time, fromArchive, mode);
+ }
+ }
+
+ private void addParentDirs(String file, ZipOutputStream zOut) throws IOException {
+ int slash = file.lastIndexOf('/');
+ if (slash >= 0) {
+ String dir = file.substring(0, slash);
+ if (dirs.add(dir)) {
+ addParentDirs(dir, zOut);
+ super.zipDir((File) null, zOut, dir + "/", ZipFileSet.DEFAULT_DIR_MODE, JAR_MARKER);
+ }
+ }
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ cleanHelper();
+ }
+
+ @Override
+ protected void cleanUp() {
+ super.cleanUp();
+ cleanHelper();
+ }
+
+ protected void cleanHelper() {
+ verbose = false;
+ filesOnly = false;
+ dirs.clear();
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-command/build.gradle b/third_party/java/jarjar/jarjar-command/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-command/build.gradle
diff --git a/third_party/java/jarjar/jarjar-command/src/main/java/com/tonicsystems/jarjar/Main.java b/third_party/java/jarjar/jarjar-command/src/main/java/com/tonicsystems/jarjar/Main.java
new file mode 100644
index 0000000000..985af607d3
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-command/src/main/java/com/tonicsystems/jarjar/Main.java
@@ -0,0 +1,147 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.classpath.ClassPath;
+import com.tonicsystems.jarjar.transform.jar.DefaultJarProcessor;
+import com.tonicsystems.jarjar.transform.config.RulesFileParser;
+import com.tonicsystems.jarjar.dependencies.TextDependencyHandler;
+import com.tonicsystems.jarjar.dependencies.DependencyFinder;
+import com.tonicsystems.jarjar.dependencies.DependencyHandler;
+import com.tonicsystems.jarjar.strings.StringDumper;
+import com.tonicsystems.jarjar.transform.config.AbstractPattern;
+import com.tonicsystems.jarjar.transform.JarTransformer;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import joptsimple.OptionSpec;
+
+public class Main {
+
+ private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+ private static final String PATH_SEPARATOR = System.getProperty("path.separator");
+
+ public static enum Mode {
+
+ strings, find, process;
+ }
+
+ private final OptionParser parser = new OptionParser();
+ private final OptionSpec<Void> helpOption = parser.accepts("help")
+ .forHelp();
+ private final OptionSpec<Mode> modeOption = parser.accepts("mode")
+ .withRequiredArg().ofType(Mode.class).defaultsTo(Mode.process).describedAs("Mode to run (strings, find, process)");
+ private final OptionSpec<DependencyHandler.Level> levelOption = parser.accepts("level")
+ .withRequiredArg().ofType(DependencyHandler.Level.class).defaultsTo(DependencyHandler.Level.CLASS).describedAs("Level for DepHandler.");
+ private final OptionSpec<File> fromFilesOption = parser.accepts("from")
+ .withRequiredArg().ofType(File.class).withValuesSeparatedBy(PATH_SEPARATOR).describedAs("Classpath for strings, find.");
+ private final OptionSpec<File> rulesOption = parser.accepts("rules")
+ .withRequiredArg().ofType(File.class).describedAs("Rules file.");
+ private final OptionSpec<File> outputOption = parser.accepts("output")
+ .withRequiredArg().ofType(File.class).describedAs("Output JAR file.");
+ private final OptionSpec<File> filesOption = parser.nonOptions()
+ .ofType(File.class).describedAs("JAR files or directories to process.");
+
+ public void run(@Nonnull String[] args) throws Exception {
+ OptionSet options = parser.parse(args);
+ if (options.has(helpOption)) {
+ parser.printHelpOn(System.err);
+ System.exit(1);
+ }
+
+ Mode mode = options.valueOf(modeOption);
+ switch (mode) {
+ case find:
+ find(options);
+ break;
+ case process:
+ process(options);
+ break;
+ case strings:
+ strings(options);
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal mode " + mode);
+ }
+ }
+
+ private static boolean isEmpty(@CheckForNull List<?> values) {
+ if (values == null)
+ return true;
+ return values.isEmpty();
+ }
+
+ @Nonnull
+ private <T> T valueOf(@Nonnull OptionSet options, @Nonnull OptionSpec<T> option) {
+ T value = options.valueOf(option);
+ if (value == null)
+ throw new IllegalArgumentException(option + " is required.");
+ return value;
+ }
+
+ @Nonnull
+ private <T> List<T> valuesOf(@Nonnull OptionSet options, @Nonnull OptionSpec<T> option) {
+ List<T> values = options.valuesOf(option);
+ if (isEmpty(values))
+ throw new IllegalArgumentException(option + " is required.");
+ return values;
+ }
+
+ private static ClassPath newClassPath(Iterable<? extends File> files) {
+ return new ClassPath(new File(System.getProperty("user.dir")), files);
+ }
+
+ public void strings(@Nonnull OptionSet options) throws IOException {
+ List<File> files = options.valuesOf(filesOption);
+ File parent = new File(System.getProperty("user.dir"));
+ new StringDumper().run(System.out, newClassPath(files));
+ System.out.flush();
+ }
+
+ public void find(@Nonnull OptionSet options) throws IOException {
+ List<File> toFiles = valuesOf(options, filesOption);
+ List<File> fromFiles = options.valuesOf(fromFilesOption);
+ if (isEmpty(fromFiles))
+ fromFiles = toFiles;
+ DependencyHandler.Level level = valueOf(options, levelOption);
+ DependencyHandler handler = new TextDependencyHandler(System.out, level);
+ new DependencyFinder().run(handler, newClassPath(fromFiles), newClassPath(toFiles));
+ System.out.flush();
+ }
+
+ public void process(@Nonnull OptionSet options) throws IOException {
+ File outputFile = valueOf(options, outputOption);
+ File rulesFile = valueOf(options, rulesOption);
+ List<File> files = valuesOf(options, filesOption);
+
+ DefaultJarProcessor processor = new DefaultJarProcessor();
+ RulesFileParser.parse(processor, rulesFile);
+ processor.setSkipManifest(Boolean.getBoolean("skipManifest"));
+
+ JarTransformer transformer = new JarTransformer(outputFile, processor);
+ transformer.transform(newClassPath(files));
+ }
+
+ public static void main(String[] args) throws Exception {
+ Main main = new Main();
+ main.run(args);
+ // MainUtil.runMain(new Main(), args, "help");
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-command/src/test/resources/com/tonicsystems/jarjar/help.txt b/third_party/java/jarjar/jarjar-command/src/test/resources/com/tonicsystems/jarjar/help.txt
new file mode 100644
index 0000000000..8410909164
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-command/src/test/resources/com/tonicsystems/jarjar/help.txt
@@ -0,0 +1,75 @@
+Jar Jar Links - A utility to repackage and embed Java libraries
+Copyright 2007 Google Inc.
+
+Command-line usage:
+
+ java -jar jarjar.jar [help]
+
+ Prints this help message.
+
+ java -jar jarjar.jar strings <cp>
+
+ Dumps all string literals in classpath <cp>. Line numbers will be
+ included if the classes have debug information.
+
+ java -jar jarjar.jar find <level> <cp1> [<cp2>]
+
+ Prints dependencies on classpath <cp2> in classpath <cp1>. If <cp2>
+ is omitted, <cp1> is used for both arguments.
+
+ The level argument must be "class" or "jar". The former prints
+ dependencies between individual classes, while the latter only
+ prints jar->jar dependencies. A "jar" in this context is actually
+ any classpath component, which can be a jar file, a zip file, or a
+ parent directory (see below).
+
+ java -jar jarjar.jar process <rulesFile> <inJar> <outJar>
+
+ Transform the <inJar> jar file, writing a new jar file to <outJar>.
+ Any existing file named by <outJar> will be deleted.
+
+ The transformation is defined by a set of rules in the file specified
+ by the rules argument (see below).
+
+Classpath format:
+
+ The classpath argument is a colon or semi-colon delimited set
+ (depending on platform) of directories, jar files, or zip files. See
+ the following page for more details:
+ http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/classpath.html
+
+ Mustang-style wildcards are also supported:
+ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6268383
+
+Rules file format:
+
+ The rules file is a text file, one rule per line. Leading and trailing
+ whitespace is ignored. There are three types of rules:
+
+ rule <pattern> <result>
+ zap <pattern>
+ keep <pattern>
+
+ The standard rule ("rule") is used to rename classes. All references
+ to the renamed classes will also be updated. If a class name is
+ matched by more than one rule, only the first one will apply.
+
+ <pattern> is a class name with optional wildcards. "**" will
+ match against any valid class name substring. To match a single
+ package component (by excluding "." from the match), a single "*" may
+ be used instead.
+
+ <result> is a class name which can optionally reference the
+ substrings matched by the wildcards. A numbered reference is available
+ for every "*" or "**" in the <pattern>, starting from left to
+ right: "@1", "@2", etc. A special "@0" reference contains the entire
+ matched class name.
+
+ The "zap" rule causes any matched class to be removed from the resulting
+ jar file. All zap rules are processed before renaming rules.
+
+ The "keep" rule marks all matched classes as "roots". If any keep
+ rules are defined all classes which are not reachable from the roots
+ via dependency analysis are discarded when writing the output
+ jar. This is the last step in the process, after renaming and zapping.
+
diff --git a/third_party/java/jarjar/jarjar-core/build.gradle b/third_party/java/jarjar/jarjar-core/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/build.gradle
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPath.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPath.java
new file mode 100644
index 0000000000..c12929b3d2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPath.java
@@ -0,0 +1,71 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.classpath;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Iterator;
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public class ClassPath implements Iterable<ClassPathArchive> {
+
+ private final File root;
+ private final Iterable<? extends File> entries;
+
+ public ClassPath(@Nonnull File root, @Nonnull Iterable<? extends File> entries) {
+ this.root = root;
+ this.entries = entries;
+ }
+
+ public ClassPath(@Nonnull File root, @Nonnull File[] entries) {
+ this(root, Arrays.asList(entries));
+ }
+
+ @Nonnull
+ public File getRoot() {
+ return root;
+ }
+
+ @Override
+ public Iterator<ClassPathArchive> iterator() {
+ return new PathIterator();
+ }
+
+ private class PathIterator implements Iterator<ClassPathArchive> {
+
+ private final Iterator<? extends File> entryIterator;
+
+ public PathIterator() {
+ this.entryIterator = entries.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+
+ @Override
+ public ClassPathArchive next() {
+ File entryFile = entryIterator.next();
+ if (!entryFile.isAbsolute())
+ entryFile = new File(root, entryFile.getPath());
+ if (entryFile.isDirectory())
+ return new ClassPathArchive.DirectoryArchive(entryFile);
+ else
+ return new ClassPathArchive.ZipArchive(entryFile);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathArchive.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathArchive.java
new file mode 100644
index 0000000000..9c3a4bf470
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathArchive.java
@@ -0,0 +1,200 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.classpath;
+
+import com.tonicsystems.jarjar.util.ClassNameUtils;
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public abstract class ClassPathArchive implements Iterable<ClassPathResource> {
+
+ protected final File root;
+
+ public ClassPathArchive(@Nonnull File root) {
+ this.root = root;
+ }
+
+ @Nonnull
+ public String getArchiveName() {
+ return root.getPath();
+ }
+
+ public static class ZipArchive extends ClassPathArchive {
+
+ public ZipArchive(@Nonnull File root) {
+ super(root);
+ }
+
+ @Override
+ public Iterator<ClassPathResource> iterator() {
+ try {
+ return new ZipIterator(root);
+ } catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
+ }
+
+ }
+
+ private static class ZipIterator implements Iterator<ClassPathResource>, Closeable {
+
+ private final ZipFile zipFile;
+ private Enumeration<? extends ZipEntry> zipEntries;
+
+ ZipIterator(@Nonnull File file) throws IOException {
+ this.zipFile = new ZipFile(file);
+ this.zipEntries = zipFile.entries();
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (!zipEntries.hasMoreElements()) {
+ // close();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public ClassPathResource next() {
+ final ZipEntry entry = zipEntries.nextElement();
+ if (entry == null)
+ throw new NoSuchElementException();
+ return new ClassPathResource() {
+ @Override
+ public String getArchiveName() {
+ return zipFile.getName();
+ }
+
+ @Override
+ public String getName() {
+ return entry.getName();
+ }
+
+ @Override
+ public long getLastModifiedTime() {
+ return entry.getTime();
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return zipFile.getInputStream(entry);
+ }
+ };
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close() throws IOException {
+ zipFile.close();
+ }
+ }
+
+ public static class DirectoryArchive extends ClassPathArchive {
+
+ public DirectoryArchive(@Nonnull File root) {
+ super(root);
+ }
+
+ @Override
+ public Iterator<ClassPathResource> iterator() {
+ return new DirectoryIterator(root);
+ }
+
+ }
+
+ private static class DirectoryIterator implements Iterator<ClassPathResource> {
+
+ @Nonnull
+ private static void findClassFiles(@Nonnull Collection<? super File> out, @Nonnull File dir) {
+ for (File file : dir.listFiles()) {
+ if (file.isDirectory()) {
+ findClassFiles(out, file);
+ } else if (file.isFile()) {
+ if (ClassNameUtils.isClass(file.getName())) {
+ out.add(file);
+ }
+ }
+ }
+ }
+
+ private final File root;
+ private final Iterator<File> entries;
+
+ DirectoryIterator(@Nonnull File root) {
+ this.root = root;
+ List<File> files = new ArrayList<File>();
+ findClassFiles(files, root);
+ this.entries = files.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return entries.hasNext();
+ }
+
+ @Override
+ public ClassPathResource next() {
+ final File file = entries.next();
+ return new ClassPathResource() {
+ @Override
+ public String getArchiveName() {
+ return root.getPath();
+ }
+
+ @Override
+ public String getName() {
+ return file.getName();
+ }
+
+ @Override
+ public long getLastModifiedTime() {
+ return file.lastModified();
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return new BufferedInputStream(new FileInputStream(file));
+ }
+ };
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "(" + root + ")";
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathResource.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathResource.java
new file mode 100644
index 0000000000..587bfdaa13
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/classpath/ClassPathResource.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2008 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.classpath;
+
+import java.io.InputStream;
+import java.io.IOException;
+import javax.annotation.Nonnull;
+
+public abstract class ClassPathResource {
+
+ @Nonnull
+ public abstract String getArchiveName();
+
+ @Nonnull
+ public abstract String getName();
+
+ public abstract long getLastModifiedTime();
+
+ @Nonnull
+ public abstract InputStream openStream() throws IOException;
+
+ @Override
+ public String toString() {
+ return getArchiveName() + "!" + getName();
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/AbstractDependencyHandler.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/AbstractDependencyHandler.java
new file mode 100644
index 0000000000..17e38d1427
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/AbstractDependencyHandler.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.Nonnull;
+
+public abstract class AbstractDependencyHandler implements DependencyHandler {
+
+ protected final Level level;
+ private final Set<Pair<String>> seen = new HashSet<Pair<String>>();
+
+ protected AbstractDependencyHandler(Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public void handle(Dependency from, Dependency to) throws IOException {
+ Pair<String> pair;
+ if (level == Level.JAR) {
+ pair = new Pair<String>(from.getClassPath(), to.getClassPath());
+ } else {
+ pair = new Pair<String>(from.getClassName(), to.getClassName());
+ }
+ if (seen.add(pair))
+ handle(pair.getLeft(), pair.getRight());
+ }
+
+ protected abstract void handle(@Nonnull String from, @Nonnull String to) throws IOException;
+
+ @Override
+ public void handleStart() throws IOException {
+ }
+
+ @Override
+ public void handleEnd() throws IOException {
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/ClassHeaderReader.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/ClassHeaderReader.java
new file mode 100644
index 0000000000..25a8a74d28
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/ClassHeaderReader.java
@@ -0,0 +1,188 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Array;
+
+/* pp */ class ClassHeaderReader {
+
+ private int access;
+ private String thisClass;
+ private String superClass;
+ private String[] interfaces;
+
+ private InputStream in;
+ private byte[] b = new byte[0x2000];
+ private int[] items = new int[1000];
+ private int bsize = 0;
+ private MyByteArrayInputStream bin = new MyByteArrayInputStream();
+ private DataInputStream data = new DataInputStream(bin);
+
+ public int getAccess() {
+ return access;
+ }
+
+ public String getClassName() {
+ return thisClass;
+ }
+
+ public String getSuperName() {
+ return superClass;
+ }
+
+ public String[] getInterfaces() {
+ return interfaces;
+ }
+
+ public void read(InputStream in) throws IOException {
+ try {
+ this.in = in;
+ bsize = 0;
+ access = 0;
+ thisClass = superClass = null;
+ interfaces = null;
+
+ try {
+ buffer(4);
+ } catch (IOException e) {
+ // ignore
+ }
+ if (b[0] != (byte) 0xCA || b[1] != (byte) 0xFE || b[2] != (byte) 0xBA || b[3] != (byte) 0xBE)
+ throw new ClassFormatError("Bad magic number");
+
+ buffer(6);
+ readUnsignedShort(4); // minorVersion
+ readUnsignedShort(6); // majorVersion
+ // TODO: check version
+ int constant_pool_count = readUnsignedShort(8);
+ items = (int[]) resizeArray(items, constant_pool_count);
+
+ int index = 10;
+ for (int i = 1; i < constant_pool_count; i++) {
+ int size;
+ buffer(index + 3); // TODO: reduce calls to buffer
+ int tag = b[index];
+ items[i] = index + 1;
+ switch (tag) {
+ case 9: // Fieldref
+ case 10: // Methodref
+ case 11: // InterfaceMethodref
+ case 3: // Integer
+ case 4: // Float
+ case 12: // NameAndType
+ size = 4;
+ break;
+ case 5: // Long
+ case 6: // Double
+ size = 8;
+ i++;
+ break;
+ case 1: // Utf8
+ size = 2 + readUnsignedShort(index + 1);
+ break;
+ case 7: // Class
+ case 8: // String
+ size = 2;
+ break;
+ default:
+ throw new IllegalStateException("Unknown constant pool tag " + tag);
+ }
+ index += size + 1;
+ }
+ buffer(index + 8);
+ access = readUnsignedShort(index);
+ thisClass = readClass(index + 2);
+ superClass = readClass(index + 4);
+ int interfaces_count = readUnsignedShort(index + 6);
+
+ index += 8;
+ buffer(index + interfaces_count * 2);
+ interfaces = new String[interfaces_count];
+ for (int i = 0; i < interfaces_count; i++) {
+ interfaces[i] = readClass(index);
+ index += 2;
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ private String readClass(int index) throws IOException {
+ index = readUnsignedShort(index);
+ if (index == 0)
+ return null;
+ index = readUnsignedShort(items[index]);
+ bin.readFrom(b, items[index]);
+ return data.readUTF();
+ }
+
+ private int readUnsignedShort(int index) {
+ byte[] b = this.b;
+ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
+ }
+
+ private static final int CHUNK = 2048;
+
+ private void buffer(int amount) throws IOException {
+ if (amount > b.length)
+ b = (byte[]) resizeArray(b, b.length * 2);
+ if (amount > bsize) {
+ int rounded = (int) (CHUNK * Math.ceil((float) amount / CHUNK));
+ bsize += read(in, b, bsize, rounded - bsize);
+ if (amount > bsize)
+ throw new EOFException();
+ }
+ }
+
+ private static int read(InputStream in, byte[] b, int off, int len) throws IOException {
+ int total = 0;
+ while (total < len) {
+ int result = in.read(b, off + total, len - total);
+ if (result == -1)
+ break;
+ total += result;
+ }
+ return total;
+ }
+
+ private static Object resizeArray(Object array, int length) {
+ if (Array.getLength(array) < length) {
+ Object newArray = Array.newInstance(array.getClass().getComponentType(), length);
+ System.arraycopy(array, 0, newArray, 0, Array.getLength(array));
+ return newArray;
+ } else {
+ return array;
+ }
+ }
+
+ private static class MyByteArrayInputStream extends ByteArrayInputStream {
+
+ public MyByteArrayInputStream() {
+ super(new byte[0]);
+ }
+
+ public void readFrom(byte[] buf, int pos) {
+ this.buf = buf;
+ this.pos = pos;
+ this.count = buf.length;
+ }
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Dependency.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Dependency.java
new file mode 100644
index 0000000000..77f0041189
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Dependency.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import javax.annotation.Nonnull;
+
+public class Dependency {
+
+ private final String classPath;
+ private final String className;
+
+ public Dependency(@Nonnull String classPath, @Nonnull String className) {
+ this.classPath = classPath;
+ this.className = className;
+ }
+
+ @Nonnull
+ public String getClassPath() {
+ return classPath;
+ }
+
+ @Nonnull
+ public String getClassName() {
+ return className;
+ }
+
+ @Override
+ public String toString() {
+ return classPath + "!" + className;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinder.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinder.java
new file mode 100644
index 0000000000..964b23da25
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinder.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import com.tonicsystems.jarjar.classpath.ClassPath;
+import com.tonicsystems.jarjar.classpath.ClassPathArchive;
+import com.tonicsystems.jarjar.classpath.ClassPathResource;
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import org.objectweb.asm.ClassReader;
+
+public class DependencyFinder {
+
+ private File curDir = new File(System.getProperty("user.dir"));
+
+ public void setCurrentDirectory(File curDir) {
+ this.curDir = curDir;
+ }
+
+ public void run(DependencyHandler handler, ClassPath from, ClassPath to) throws IOException {
+ try {
+ ClassHeaderReader header = new ClassHeaderReader();
+ Map<String, String> classToArchiveMap = new HashMap<String, String>();
+ for (ClassPathArchive toArchive : to) {
+ for (ClassPathResource toResource : toArchive) {
+ InputStream in = toResource.openStream();
+ try {
+ header.read(in);
+ classToArchiveMap.put(header.getClassName(), toArchive.getArchiveName());
+ } catch (Exception e) {
+ System.err.println("Error reading " + toResource.getName() + ": " + e.getMessage());
+ } finally {
+ in.close();
+ }
+ }
+ }
+
+ handler.handleStart();
+ for (ClassPathArchive fromArchive : from) {
+ for (ClassPathResource fromResource : fromArchive) {
+ InputStream in = fromResource.openStream();
+ try {
+ new ClassReader(in).accept(new DependencyFinderClassVisitor(classToArchiveMap, fromArchive.getArchiveName(), handler),
+ ClassReader.SKIP_DEBUG);
+ } catch (Exception e) {
+ System.err.println("Error reading " + fromResource.getName() + ": " + e.getMessage());
+ } finally {
+ in.close();
+ }
+ }
+ }
+ handler.handleEnd();
+ } catch (RuntimeIOException e) {
+ throw (IOException) e.getCause();
+ }
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinderClassVisitor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinderClassVisitor.java
new file mode 100644
index 0000000000..968a4c5a4a
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyFinderClassVisitor.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import java.io.IOException;
+import java.util.Map;
+import org.objectweb.asm.commons.Remapper;
+import org.objectweb.asm.commons.RemappingClassAdapter;
+
+class DependencyFinderClassVisitor extends RemappingClassAdapter {
+
+ public DependencyFinderClassVisitor(Map<String, String> classToArchiveMap, String archiveName, DependencyHandler handler) throws IOException {
+ super(null, new DependencyFinderRemapper(classToArchiveMap, archiveName, handler));
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ ((DependencyFinderRemapper) remapper).setClassName(name);
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ private static class DependencyFinderRemapper extends Remapper {
+
+ private final Map<String, String> classes;
+ private final String archiveName;
+ private final DependencyHandler handler;
+ private Dependency curPathClass;
+
+ public DependencyFinderRemapper(Map<String, String> classes, String archiveName, DependencyHandler handler) throws IOException {
+ this.classes = classes;
+ this.archiveName = archiveName;
+ this.handler = handler;
+ }
+
+ public void setClassName(String name) {
+ curPathClass = new Dependency(archiveName, name);
+ }
+
+ @Override
+ public String map(String key) {
+ try {
+ if (classes.containsKey(key)) {
+ String otherSource = classes.get(key);
+ if (!archiveName.equals(otherSource)) {
+ // TODO: some escape mechanism?
+ handler.handle(curPathClass, new Dependency(otherSource, key));
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
+ return null;
+ }
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyHandler.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyHandler.java
new file mode 100644
index 0000000000..7d01748e1a
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/DependencyHandler.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import java.io.IOException;
+
+public interface DependencyHandler {
+
+ public enum Level {
+
+ CLASS, JAR;
+ }
+
+ void handleStart() throws IOException;
+
+ void handle(Dependency from, Dependency to) throws IOException;
+
+ void handleEnd() throws IOException;
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Pair.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Pair.java
new file mode 100644
index 0000000000..8682bf19fe
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/Pair.java
@@ -0,0 +1,57 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public class Pair<T> {
+
+ private final T left;
+ private final T right;
+
+ public Pair(@Nonnull T left, @Nonnull T right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ @Nonnull
+ public T getLeft() {
+ return left;
+ }
+
+ @Nonnull
+ public T getRight() {
+ return right;
+ }
+
+ @Override
+ public int hashCode() {
+ return (left.hashCode() << 8) ^ right.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (null == obj)
+ return false;
+ if (!getClass().equals(obj.getClass()))
+ return false;
+ Pair o = (Pair) obj;
+ return left.equals(o.left)
+ && right.equals(o.right);
+ }
+
+ @Override
+ public String toString() {
+ return left + " : " + right;
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/TextDependencyHandler.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/TextDependencyHandler.java
new file mode 100644
index 0000000000..205b12e281
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/dependencies/TextDependencyHandler.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.dependencies;
+
+import java.io.IOException;
+
+public class TextDependencyHandler extends AbstractDependencyHandler {
+
+ private final Appendable out;
+
+ public TextDependencyHandler(Appendable out, Level level) {
+ super(level);
+ this.out = out;
+ }
+
+ @Override
+ protected void handle(String from, String to) throws IOException {
+ out.append(from + " -> " + to + "\n");
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringDumper.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringDumper.java
new file mode 100644
index 0000000000..589764ca96
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringDumper.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.strings;
+
+import com.tonicsystems.jarjar.classpath.ClassPath;
+import com.tonicsystems.jarjar.classpath.ClassPathArchive;
+import com.tonicsystems.jarjar.classpath.ClassPathResource;
+import com.tonicsystems.jarjar.util.IoUtil;
+import com.tonicsystems.jarjar.util.RuntimeIOException;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.annotation.Nonnull;
+import org.objectweb.asm.ClassReader;
+
+public class StringDumper {
+
+ public void run(Appendable out, ClassPath classPath) throws IOException {
+ StringReader stringReader = new DumpStringReader(out);
+ for (ClassPathArchive classPathArchive : classPath) {
+ for (ClassPathResource classPathResource : classPathArchive) {
+ InputStream in = classPathResource.openStream();
+ try {
+ new ClassReader(in).accept(stringReader, 0);
+ } catch (Exception e) {
+ System.err.println("Error reading " + classPathResource + ": " + e.getMessage());
+ } finally {
+ in.close();
+ }
+ IoUtil.flush(out);
+ }
+ }
+ }
+
+ private static class DumpStringReader extends StringReader {
+
+ private final Appendable out;
+ private String className;
+
+ public DumpStringReader(@Nonnull Appendable out) {
+ this.out = out;
+ }
+
+ @Override
+ public void visitString(String className, String value, int line) {
+ if (value.length() > 0) {
+ try {
+ if (!className.equals(this.className)) {
+ this.className = className;
+ out.append(className.replace('/', '.'));
+ }
+ out.append("\t");
+ if (line >= 0)
+ out.append(line + ": ");
+ out.append(escapeStringLiteral(value));
+ out.append("\n");
+ } catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
+ }
+ }
+ };
+
+ @Nonnull
+ private static String escapeStringLiteral(@Nonnull String value) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\"");
+ for (int i = 0, size = value.length(); i < size; i++) {
+ char ch = value.charAt(i);
+ switch (ch) {
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ case '\b':
+ sb.append("\\b");
+ break;
+ case '\f':
+ sb.append("\\f");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ case '\"':
+ sb.append("\\\"");
+ break;
+ case '\\':
+ sb.append("\\\\");
+ break;
+ default:
+ sb.append(ch);
+ }
+ }
+ sb.append("\"");
+ return sb.toString();
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringReader.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringReader.java
new file mode 100644
index 0000000000..b4bf18d9b9
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/strings/StringReader.java
@@ -0,0 +1,114 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.strings;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public abstract class StringReader extends ClassVisitor {
+
+ private int line = -1;
+ private String className;
+
+ public StringReader() {
+ super(Opcodes.ASM5);
+ }
+
+ public abstract void visitString(@Nonnull String className, @Nonnull String value, @Nonnegative int line);
+
+ private void handleObject(Object value) {
+ if (value instanceof String)
+ visitString(className, (String) value, line);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ className = name;
+ line = -1;
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ handleObject(value);
+ return new FieldVisitor(Opcodes.ASM5) {
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return StringReader.this.visitAnnotation(desc, visible);
+ }
+ };
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return new AnnotationVisitor(Opcodes.ASM5) {
+ @Override
+ public void visit(String name, Object value) {
+ handleObject(value);
+ }
+
+ @Override
+ public void visitEnum(String name, String desc, String value) {
+ handleObject(value);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ return this;
+ }
+ };
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ return new MethodVisitor(Opcodes.ASM5) {
+ @Override
+ public void visitLdcInsn(Object cst) {
+ handleObject(cst);
+ }
+
+ @Override
+ public void visitLineNumber(int line, Label start) {
+ StringReader.this.line = line;
+ }
+
+ @Override
+ public void visitInvokeDynamicInsn(String name, String desc,
+ Handle bsm, Object... bsmArgs) {
+ for (Object bsmArg : bsmArgs)
+ handleObject(bsmArg);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return StringReader.this.visitAnnotation(desc, visible);
+ }
+
+ @Override
+ public AnnotationVisitor visitParameterAnnotation(int parameter,
+ String desc, boolean visible) {
+ return StringReader.this.visitAnnotation(desc, visible);
+ }
+ };
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/JarTransformer.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/JarTransformer.java
new file mode 100644
index 0000000000..2fc5b3d0a9
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/JarTransformer.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform;
+
+import com.tonicsystems.jarjar.classpath.ClassPath;
+import com.tonicsystems.jarjar.classpath.ClassPathArchive;
+import com.tonicsystems.jarjar.classpath.ClassPathResource;
+import com.tonicsystems.jarjar.transform.jar.JarProcessor;
+import com.tonicsystems.jarjar.util.IoUtil;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JarTransformer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JarTransformer.class);
+
+ public static enum DuplicatePolicy {
+
+ DISCARD, ERROR;
+ }
+ private final File outputFile;
+ private final JarProcessor processor;
+ private DuplicatePolicy duplicatePolicy = DuplicatePolicy.DISCARD;
+ private final byte[] buf = new byte[0x2000];
+ private final Set<String> dirs = new HashSet<String>();
+ private final Set<String> files = new HashSet<String>();
+
+ public JarTransformer(@Nonnull File outputFile, @Nonnull JarProcessor processor) {
+ this.outputFile = outputFile;
+ this.processor = processor;
+ }
+
+ @Nonnull
+ private Transformable newTransformable(@Nonnull ClassPathResource inputResource)
+ throws IOException {
+ Transformable struct = new Transformable();
+ struct.name = inputResource.getName();
+ struct.time = inputResource.getLastModifiedTime();
+
+ InputStream in = inputResource.openStream();
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ IoUtil.copy(in, out, buf);
+ struct.data = out.toByteArray();
+ } finally {
+ in.close();
+ }
+
+ return struct;
+ }
+
+ private void addDirs(JarOutputStream outputJarStream, String name) throws IOException {
+ int dirIdx = name.lastIndexOf('/');
+ if (dirIdx == -1)
+ return;
+ String dirName = name.substring(0, dirIdx + 1);
+ if (dirs.add(dirName)) {
+ JarEntry dirEntry = new JarEntry(dirName);
+ outputJarStream.putNextEntry(dirEntry);
+ }
+ }
+
+ public void transform(@Nonnull ClassPath inputPath) throws IOException {
+
+ SCAN:
+ {
+ for (ClassPathArchive inputArchive : inputPath) {
+ LOG.debug("Scanning archive {}", inputArchive);
+ for (ClassPathResource inputResource : inputArchive) {
+ Transformable struct = newTransformable(inputResource);
+ processor.scan(struct);
+ }
+ }
+ }
+
+ OUT:
+ {
+ Set<String> dirs = new HashSet<String>();
+
+ JarOutputStream outputJarStream = new JarOutputStream(new FileOutputStream(outputFile));
+ for (ClassPathArchive inputArchive : inputPath) {
+ LOG.info("Transforming archive {}", inputArchive);
+ for (ClassPathResource inputResource : inputArchive) {
+ Transformable struct = newTransformable(inputResource);
+ if (processor.process(struct) == JarProcessor.Result.DISCARD)
+ continue;
+
+ addDirs(outputJarStream, struct.name);
+
+ if (DuplicatePolicy.DISCARD.equals(duplicatePolicy)) {
+ if (!files.add(struct.name)) {
+ LOG.debug("Discarding duplicate {}", struct.name);
+ continue;
+ }
+ }
+
+ LOG.debug("Writing {}", struct.name);
+ JarEntry outputEntry = new JarEntry(struct.name);
+ outputEntry.setTime(struct.time);
+ outputEntry.setCompressedSize(-1);
+ outputJarStream.putNextEntry(outputEntry);
+ outputJarStream.write(struct.data);
+ }
+ }
+ outputJarStream.close();
+ }
+
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/Transformable.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/Transformable.java
new file mode 100644
index 0000000000..765724ef3d
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/Transformable.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform;
+
+public class Transformable {
+
+ public byte[] data;
+ public String name;
+ public long time;
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/ClassTransformer.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/ClassTransformer.java
new file mode 100644
index 0000000000..6e99cb95e4
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/ClassTransformer.java
@@ -0,0 +1,19 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform.asm;
+
+import javax.annotation.Nonnull;
+import org.objectweb.asm.ClassVisitor;
+
+/**
+ *
+ * @author shevek
+ */
+public interface ClassTransformer {
+
+ @Nonnull
+ public ClassVisitor transform(@Nonnull ClassVisitor v);
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/GetNameClassWriter.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/GetNameClassWriter.java
new file mode 100644
index 0000000000..d62f8a3d2c
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/GetNameClassWriter.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.asm;
+
+import javax.annotation.Nonnull;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class GetNameClassWriter extends ClassVisitor {
+
+ private String className;
+
+ /**
+ * Constructs a new GetNameClassWriter.
+ */
+ // * @param flags may include {@link ClassWriter#COMPUTE_FRAMES} * or {@link ClassWriter#COMPUTE_MAXS}.
+ public GetNameClassWriter(ClassVisitor cv) {
+ super(Opcodes.ASM5, cv);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ className = name;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Nonnull
+ public String getClassName() {
+ return className;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/PackageRemapper.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/PackageRemapper.java
new file mode 100644
index 0000000000..1b2aa028dd
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/PackageRemapper.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.asm;
+
+import com.tonicsystems.jarjar.transform.config.ClassRename;
+import com.tonicsystems.jarjar.transform.config.PatternUtils;
+import com.tonicsystems.jarjar.util.ClassNameUtils;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.objectweb.asm.commons.Remapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PackageRemapper extends Remapper {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PackageRemapper.class);
+ private static final String RESOURCE_SUFFIX = "RESOURCE";
+
+ private final List<ClassRename> patterns;
+ private final Map<String, String> typeCache = new HashMap<String, String>();
+ private final Map<String, String> pathCache = new HashMap<String, String>();
+ private final Map<Object, String> valueCache = new HashMap<Object, String>();
+
+ public PackageRemapper(@Nonnull Iterable<? extends ClassRename> patterns) {
+ this.patterns = PatternUtils.toList(patterns);
+ }
+
+ public PackageRemapper(@Nonnull ClassRename... patterns) {
+ this(Arrays.asList(patterns));
+ }
+
+ public void addRule(@Nonnull ClassRename pattern) {
+ this.patterns.add(pattern);
+ }
+
+ @Override
+ public String map(String key) {
+ String s = typeCache.get(key);
+ if (s == null) {
+ s = replaceHelper(key);
+ if (key.equals(s))
+ s = null;
+ typeCache.put(key, s);
+ }
+ return s;
+ }
+
+ public String mapPath(String path) {
+ String s = pathCache.get(path);
+ if (s == null) {
+ s = path;
+ int slash = s.lastIndexOf('/');
+ String end;
+ if (slash < 0) {
+ end = s;
+ s = RESOURCE_SUFFIX;
+ } else {
+ end = s.substring(slash + 1);
+ s = s.substring(0, slash + 1) + RESOURCE_SUFFIX;
+ }
+ boolean absolute = s.startsWith("/");
+ if (absolute)
+ s = s.substring(1);
+
+ s = replaceHelper(s);
+
+ if (absolute)
+ s = "/" + s;
+ if (s.indexOf(RESOURCE_SUFFIX) < 0)
+ return path;
+ s = s.substring(0, s.length() - RESOURCE_SUFFIX.length()) + end;
+ pathCache.put(path, s);
+ }
+ return s;
+ }
+
+ @Override
+ public Object mapValue(Object value) {
+ if (value instanceof String) {
+ String s = valueCache.get(value);
+ if (s == null) {
+ s = (String) value;
+ if (ClassNameUtils.isArrayForName(s)) {
+ String desc1 = s.replace('.', '/');
+ String desc2 = mapDesc(desc1);
+ if (!desc2.equals(desc1))
+ return desc2.replace('/', '.');
+ } else {
+ s = mapPath(s);
+ if (s.equals(value)) {
+ boolean hasDot = s.indexOf('.') >= 0;
+ boolean hasSlash = s.indexOf('/') >= 0;
+ if (!(hasDot && hasSlash)) {
+ if (hasDot) {
+ s = replaceHelper(s.replace('.', '/')).replace('/', '.');
+ } else {
+ s = replaceHelper(s);
+ }
+ }
+ }
+ }
+ valueCache.put(value, s);
+ }
+ // TODO: add back class name to verbose message
+ if (!s.equals(value))
+ if (LOG.isDebugEnabled())
+ LOG.debug("Changed \"" + value + "\" -> \"" + s + "\"");
+ return s;
+ } else {
+ return super.mapValue(value);
+ }
+ }
+
+ private String replaceHelper(String value) {
+ for (ClassRename pattern : patterns) {
+ String result = pattern.replace(value);
+ if (result != null)
+ return result;
+ }
+ return value;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/RemappingClassTransformer.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/RemappingClassTransformer.java
new file mode 100644
index 0000000000..a30341c6d0
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/asm/RemappingClassTransformer.java
@@ -0,0 +1,30 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform.asm;
+
+import javax.annotation.Nonnull;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.commons.Remapper;
+import org.objectweb.asm.commons.RemappingClassAdapter;
+
+/**
+ *
+ * @author shevek
+ */
+public class RemappingClassTransformer implements ClassTransformer {
+
+ private final Remapper remapper;
+
+ public RemappingClassTransformer(@Nonnull Remapper remapper) {
+ this.remapper = remapper;
+ }
+
+ @Override
+ public ClassVisitor transform(ClassVisitor v) {
+ return new RemappingClassAdapter(v, remapper);
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractClassPattern.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractClassPattern.java
new file mode 100644
index 0000000000..d76d9e4af7
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractClassPattern.java
@@ -0,0 +1,26 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public abstract class AbstractClassPattern extends AbstractPattern {
+
+ private static String check(String patternText) {
+ if (patternText.indexOf('/') >= 0)
+ throw new IllegalArgumentException("Class patterns cannot contain slashes");
+ return patternText.replace('.', '/');
+ }
+
+ public AbstractClassPattern(@Nonnull String patternText) {
+ super(check(patternText));
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractPattern.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractPattern.java
new file mode 100644
index 0000000000..f88a8093c1
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractPattern.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * This object and its subclasses are also exposed to ant, so need setters for XML.
+ *
+ * @author shevek
+ */
+public abstract class AbstractPattern {
+
+ private final String patternText;
+ private final Pattern pattern;
+
+ public AbstractPattern(@Nonnull String patternText) {
+ if (patternText == null)
+ throw new IllegalArgumentException("Pattern text may not be null.");
+ this.patternText = patternText;
+ this.pattern = PatternUtils.newPattern(patternText);
+ }
+
+ @Nonnull
+ public String getPatternText() {
+ return patternText;
+ }
+
+ @Nonnull
+ public Pattern getPattern() {
+ return pattern;
+ }
+
+ @CheckForNull
+ protected Matcher getMatcher(@Nonnull String value) {
+ if (!PatternUtils.isPossibleQualifiedName(value, "/"))
+ return null;
+ Matcher matcher = pattern.matcher(value);
+ if (matcher.matches())
+ return matcher;
+ return null;
+ }
+
+ public boolean matches(@Nonnull String value) {
+ return getMatcher(value) != null;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" + pattern + ")";
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractResourcePattern.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractResourcePattern.java
new file mode 100644
index 0000000000..1810a810f3
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/AbstractResourcePattern.java
@@ -0,0 +1,20 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public abstract class AbstractResourcePattern extends AbstractPattern {
+
+ public AbstractResourcePattern(@Nonnull String patternText) {
+ super(patternText);
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassDelete.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassDelete.java
new file mode 100644
index 0000000000..503d63084d
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassDelete.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Requires that any matched class is removed.
+ *
+ * @author shevek
+ */
+public class ClassDelete extends AbstractClassPattern {
+
+ public ClassDelete(@Nonnull String pattern) {
+ super(pattern);
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeep.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeep.java
new file mode 100644
index 0000000000..1d5cca4286
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeep.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Requires that any matched class is kept.
+ *
+ * @author shevek
+ */
+public class ClassKeep extends AbstractClassPattern {
+
+ public ClassKeep(@Nonnull String pattern) {
+ super(pattern);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeepTransitive.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeepTransitive.java
new file mode 100644
index 0000000000..175fe7f6b6
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassKeepTransitive.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Requires that any matched class and all classes directly or indirectly reachable from it are kept.
+ *
+ * @author shevek
+ */
+public class ClassKeepTransitive extends AbstractClassPattern {
+
+ public ClassKeepTransitive(@Nonnull String pattern) {
+ super(pattern);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassRename.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassRename.java
new file mode 100644
index 0000000000..02a500e615
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ClassRename.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Requires that any matched class is renamed.
+ *
+ * @author shevek
+ */
+public class ClassRename extends AbstractClassPattern {
+
+ // private final String replaceText;
+ private final List<Object> replace;
+
+ public ClassRename(@Nonnull String patternText, @Nonnull String replaceText) {
+ super(patternText);
+ if (replaceText == null)
+ throw new IllegalArgumentException("Result may not be null.");
+ // this.replaceText = replaceText;
+ this.replace = PatternUtils.newReplace(getPattern(), replaceText);
+ }
+
+ @CheckForNull
+ public String replace(@Nonnull String value) {
+ return PatternUtils.replace(this, replace, value);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/PatternUtils.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/PatternUtils.java
new file mode 100644
index 0000000000..cd88ed4c3e
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/PatternUtils.java
@@ -0,0 +1,245 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+public class PatternUtils {
+
+ private PatternUtils() {
+ }
+
+ private static final Pattern dstar = Pattern.compile("\\*\\*");
+ private static final Pattern star = Pattern.compile("\\*");
+ private static final Pattern estar = Pattern.compile("\\+\\??\\)\\Z");
+
+ @Nonnull
+ private static String replaceAllLiteral(@Nonnull String value, @Nonnull Pattern pattern, @Nonnull String replace) {
+ return pattern.matcher(value).replaceAll(Matcher.quoteReplacement(replace));
+ }
+
+ @Nonnull
+ public static Pattern newPattern(@Nonnull String pattern) {
+ if (pattern.equals("**"))
+ throw new IllegalArgumentException("'**' is not a valid pattern");
+ if (!isPossibleQualifiedName(pattern, "/*"))
+ throw new IllegalArgumentException("Not a valid package pattern: " + pattern);
+ if (pattern.indexOf("***") >= 0)
+ throw new IllegalArgumentException("The sequence '***' is invalid in a package pattern");
+
+ String regex = pattern;
+ regex = replaceAllLiteral(regex, dstar, "(.+?)"); // One wildcard test requires the argument to be allowably empty.
+ regex = replaceAllLiteral(regex, star, "([^/]+)");
+ regex = replaceAllLiteral(regex, estar, "*\\??)"); // Although we replaced with + above, we mean *
+ return Pattern.compile("\\A" + regex + "\\Z");
+ // this.count = this.pattern.matcher("foo").groupCount();
+ }
+
+ private static enum State {
+
+ NORMAL, ESCAPE;
+ }
+
+ @Nonnull
+ public static List<Object> newReplace(@Nonnull Pattern pattern, @Nonnull String result) {
+ List<Object> parts = new ArrayList<Object>(16);
+ // TODO: check for illegal characters
+ int max = 0;
+ State state = State.NORMAL;
+ for (int i = 0, mark = 0, len = result.length(); i < len + 1; i++) {
+ char ch = (i == len) ? '@' : result.charAt(i);
+ switch (state) {
+ case NORMAL:
+ if (ch == '@') {
+ parts.add(result.substring(mark, i).replace('.', '/'));
+ mark = i + 1;
+ state = State.ESCAPE;
+ }
+ break;
+ case ESCAPE:
+ switch (ch) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ default:
+ if (i == mark)
+ throw new IllegalArgumentException("Backslash not followed by a digit");
+ int n = Integer.parseInt(result.substring(mark, i));
+ if (n > max)
+ max = n;
+ parts.add(Integer.valueOf(n));
+ mark = i--;
+ state = State.NORMAL;
+ break;
+ }
+ break;
+ }
+ }
+
+ int count = pattern.matcher("foo").groupCount();
+ if (count < max)
+ throw new IllegalArgumentException("Result includes impossible placeholder \"@" + max + "\": " + result);
+ // System.err.println(this);
+ return parts;
+ }
+
+ public static String replace(@Nonnull AbstractPattern pattern, @Nonnull List<Object> replace, String value) {
+ Matcher matcher = pattern.getMatcher(value);
+ if (matcher == null)
+ return null;
+ StringBuilder sb = new StringBuilder();
+ for (Object part : replace) {
+ if (part instanceof String)
+ sb.append((String) part);
+ else
+ sb.append(matcher.group((Integer) part));
+ }
+ return sb.toString();
+ }
+
+ public static final String PACKAGE_INFO = "package-info";
+
+ /* pp */ static boolean isPossibleQualifiedName(@Nonnull String value, @Nonnull String extraAllowedCharacters) {
+ // package-info violates the spec for Java Identifiers.
+ // Nevertheless, expressions that end with this string are still legal.
+ // See 7.4.1.1 of the Java language spec for discussion.
+ if (value.endsWith(PACKAGE_INFO)) {
+ value = value.substring(0, value.length() - PACKAGE_INFO.length());
+ }
+ for (int i = 0, len = value.length(); i < len; i++) {
+ char c = value.charAt(i);
+ if (Character.isJavaIdentifierPart(c))
+ continue;
+ if (extraAllowedCharacters.indexOf(c) >= 0)
+ continue;
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Copies the given {@link Iterable} into a new {@link List}.
+ *
+ * @param <T> The free parameter for the element type.
+ * @param in The Iterable to copy.
+ * @return A new, mutable {@link ArrayList}.
+ */
+ @Nonnull
+ public static <T extends AbstractPattern> List<T> toList(@Nonnull Iterable<? extends T> in) {
+ List<T> out = new ArrayList<T>();
+ for (T i : in)
+ out.add(i);
+ return out;
+ }
+
+ // Adapted from http://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java-util-regex-for-glob-type-patterns
+ @Nonnull
+ public static String convertGlobToRegEx(@Nonnull String line) {
+ line = line.trim();
+ int strLen = line.length();
+ StringBuilder sb = new StringBuilder(strLen);
+ // Remove beginning and ending * globs because they're useless
+ if (line.startsWith("*")) {
+ line = line.substring(1);
+ strLen--;
+ }
+ if (line.endsWith("*")) {
+ line = line.substring(0, strLen - 1);
+ strLen--;
+ }
+ boolean escaping = false;
+ int inCurlies = 0;
+ CHAR:
+ for (char currentChar : line.toCharArray()) {
+ switch (currentChar) {
+ case '*':
+ if (escaping)
+ sb.append("\\*");
+ else
+ sb.append(".*");
+ break;
+ case '?':
+ if (escaping)
+ sb.append("\\?");
+ else
+ sb.append('.');
+ break;
+ case '.':
+ case '(':
+ case ')':
+ case '+':
+ case '|':
+ case '^':
+ case '$':
+ case '@':
+ case '%':
+ sb.append('\\');
+ sb.append(currentChar);
+ break;
+ case '\\':
+ if (escaping)
+ sb.append("\\\\");
+ else {
+ escaping = true;
+ continue CHAR;
+ }
+ break;
+ case '{':
+ if (escaping)
+ sb.append("\\{");
+ else {
+ sb.append('(');
+ inCurlies++;
+ }
+ break;
+ case '}':
+ if (escaping)
+ sb.append("\\}");
+ else if (inCurlies > 0) {
+ sb.append(')');
+ inCurlies--;
+ } else
+ sb.append("}");
+ break;
+ case ',':
+ if (escaping)
+ sb.append("\\,");
+ else if (inCurlies > 0)
+ sb.append('|');
+ else
+ sb.append(",");
+ break;
+ default:
+ sb.append(currentChar);
+ break;
+ }
+ escaping = false;
+ }
+ return sb.toString();
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ResourceRename.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ResourceRename.java
new file mode 100644
index 0000000000..91cfc4020c
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/ResourceRename.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Requires that any matched resource is renamed.
+ *
+ * @author shevek
+ */
+public class ResourceRename extends AbstractResourcePattern {
+
+ // private final String replaceText;
+ private final List<Object> replace;
+
+ public ResourceRename(@Nonnull String patternText, @Nonnull String replaceText) {
+ super(patternText);
+ if (replaceText == null)
+ throw new IllegalArgumentException("Result may not be null.");
+ // this.replaceText = replaceText;
+ this.replace = PatternUtils.newReplace(getPattern(), replaceText);
+ }
+
+ @CheckForNull
+ public String replace(@Nonnull String value) {
+ return PatternUtils.replace(this, replace, value);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/RulesFileParser.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/RulesFileParser.java
new file mode 100644
index 0000000000..59377ad9eb
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/config/RulesFileParser.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.config;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import javax.annotation.WillClose;
+
+public class RulesFileParser {
+
+ public interface Output {
+
+ public void addClassDelete(@Nonnull ClassDelete classDelete);
+
+ public void addClassRename(@Nonnull ClassRename classRename);
+
+ public void addClassKeep(@Nonnull ClassKeep classKeep);
+
+ public void addClassKeepTransitive(@Nonnull ClassKeepTransitive classKeepTransitive);
+ }
+
+ private RulesFileParser() {
+ }
+
+ @Nonnull
+ public static void parse(@Nonnull Output output, @Nonnull File file) throws IOException {
+ parse(output, new FileReader(file));
+ }
+
+ @Nonnull
+ public static void parse(@Nonnull Output output, @Nonnull String value) throws IOException {
+ parse(output, new StringReader(value));
+ }
+
+ @Nonnull
+ private static List<String> split(@Nonnull String line) {
+ StringTokenizer tok = new StringTokenizer(line);
+ List<String> out = new ArrayList<String>();
+ while (tok.hasMoreTokens()) {
+ String token = tok.nextToken();
+ if (token.startsWith("#"))
+ break;
+ out.add(token);
+ }
+ return out;
+ }
+
+ @Nonnull
+ private static void parse(@Nonnull Output output, @Nonnull @WillClose Reader r) throws IOException {
+ try {
+ BufferedReader br = new BufferedReader(r);
+ int lineNumber = 1;
+ String line;
+ while ((line = br.readLine()) != null) {
+ List<String> words = split(line);
+ if (words.isEmpty())
+ continue;
+ if (words.size() < 2)
+ throw error(lineNumber, words, "not enough words on line.");
+ String type = words.get(0);
+ if (type.equals("rule")) {
+ if (words.size() < 3)
+ throw error(lineNumber, words, "'rule' requires 2 arguments.");
+ output.addClassRename(new ClassRename(words.get(1), words.get(2)));
+ } else if (type.equals("zap")) {
+ output.addClassDelete(new ClassDelete(words.get(1)));
+ } else if (type.equals("keep")) {
+ output.addClassKeepTransitive(new ClassKeepTransitive(words.get(1)));
+ } else {
+ throw error(lineNumber, words, "Unrecognized keyword " + type);
+ }
+ lineNumber++;
+ }
+ } finally {
+ r.close();
+ }
+ }
+
+ @Nonnull
+ private static IllegalArgumentException error(@Nonnegative int lineNumber, @Nonnull List<String> words, @Nonnull String reason) {
+ throw new IllegalArgumentException("Error on line " + lineNumber + ": " + words + ": " + reason);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/AbstractFilterJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/AbstractFilterJarProcessor.java
new file mode 100644
index 0000000000..dc9ce4130a
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/AbstractFilterJarProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.Transformable;
+import java.io.IOException;
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author shevek
+ */
+public abstract class AbstractFilterJarProcessor implements JarProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractFilterJarProcessor.class);
+
+ protected abstract boolean isFiltered(@Nonnull String name);
+
+ protected boolean isVerbose() {
+ return true;
+ }
+
+ @Override
+ public Result scan(Transformable struct) throws IOException {
+ if (isFiltered(struct.name)) {
+ if (isVerbose())
+ LOG.debug("{}.scan discarded {}", getClass().getSimpleName(), struct.name);
+ return Result.DISCARD;
+ }
+ return Result.KEEP;
+ }
+
+ @Override
+ public Result process(Transformable struct) throws IOException {
+ if (isFiltered(struct.name)) {
+ if (isVerbose())
+ LOG.debug("{}.process discarded {}", getClass().getSimpleName(), struct.name);
+ return Result.DISCARD;
+ }
+ return Result.KEEP;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassClosureJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassClosureJarProcessor.java
new file mode 100644
index 0000000000..c5f9318e43
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassClosureJarProcessor.java
@@ -0,0 +1,143 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.config.PatternUtils;
+import com.tonicsystems.jarjar.transform.config.ClassKeepTransitive;
+import com.tonicsystems.jarjar.transform.Transformable;
+import com.tonicsystems.jarjar.util.ClassNameUtils;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.commons.Remapper;
+import org.objectweb.asm.commons.RemappingClassAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Keeps all classes reachable from a given set of roots.
+ *
+ * Put this early in the chain as it does not honour renames.
+ */
+public class ClassClosureJarProcessor extends AbstractFilterJarProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassClosureJarProcessor.class);
+
+ private static class DependencyCollector extends Remapper {
+
+ private final Set<String> dependencies = new HashSet<String>();
+
+ @Override
+ public String map(String key) {
+ if (key.startsWith("java/") || key.startsWith("javax/"))
+ return null;
+ dependencies.add(key);
+ return null;
+ }
+
+ @Override
+ public Object mapValue(Object value) {
+ if (value instanceof String) {
+ String s = (String) value;
+ if (ClassNameUtils.isArrayForName(s)) {
+ mapDesc(s.replace('.', '/'));
+ } else if (ClassNameUtils.isForName(s)) {
+ map(s.replace('.', '/'));
+ }
+ return value;
+ } else {
+ return super.mapValue(value);
+ }
+ }
+ }
+
+ private final List<ClassKeepTransitive> patterns;
+ private final List<String> roots = new ArrayList<String>();
+ private final Map<String, Set<String>> dependencies = new HashMap<String, Set<String>>();
+ private Set<String> closure;
+
+ public ClassClosureJarProcessor(@Nonnull Iterable<? extends ClassKeepTransitive> patterns) {
+ this.patterns = PatternUtils.toList(patterns);
+ }
+
+ public ClassClosureJarProcessor(@Nonnull ClassKeepTransitive... patterns) {
+ this(Arrays.asList(patterns));
+ }
+
+ public void addKeep(@Nonnull ClassKeepTransitive pattern) {
+ patterns.add(pattern);
+ }
+
+ private boolean isEnabled() {
+ return !patterns.isEmpty();
+ }
+
+ @Override
+ public Result scan(Transformable struct) throws IOException {
+ if (!isEnabled())
+ return Result.KEEP;
+ try {
+ if (ClassNameUtils.isClass(struct.name)) {
+ String name = struct.name.substring(0, struct.name.length() - 6);
+ for (ClassKeepTransitive pattern : patterns)
+ if (pattern.matches(name))
+ roots.add(name);
+ DependencyCollector collector = new DependencyCollector();
+ dependencies.put(name, collector.dependencies);
+ new ClassReader(new ByteArrayInputStream(struct.data)).accept(new RemappingClassAdapter(null, collector), ClassReader.EXPAND_FRAMES);
+ collector.dependencies.remove(name);
+ }
+ } catch (Exception e) {
+ LOG.warn("Error reading " + struct.name + ": " + e.getMessage());
+ }
+ return Result.KEEP;
+ }
+
+ private void addTransitiveClosure(Collection<? super String> out, Collection<String> itemDependencies) {
+ if (itemDependencies == null)
+ return;
+ for (String name : itemDependencies)
+ if (out.add(name))
+ addTransitiveClosure(out, dependencies.get(name));
+ }
+
+ @Override
+ protected boolean isFiltered(String name) {
+ if (closure == null) {
+ closure = new HashSet<String>();
+ addTransitiveClosure(closure, roots);
+ }
+ return !closure.contains(name);
+ }
+
+ @Override
+ public Result process(Transformable struct) throws IOException {
+ if (!isEnabled())
+ return Result.KEEP;
+ if (!ClassNameUtils.isClass(struct.name))
+ return Result.KEEP;
+ return super.process(struct);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassFilterJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassFilterJarProcessor.java
new file mode 100644
index 0000000000..79798ba02b
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassFilterJarProcessor.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.config.AbstractPattern;
+import com.tonicsystems.jarjar.transform.config.ClassDelete;
+import com.tonicsystems.jarjar.transform.config.ClassKeep;
+import com.tonicsystems.jarjar.util.ClassNameUtils;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Filters classes by name.
+ *
+ * Keeps all classes specified by ClassKeep (default all classes).
+ * Then removes all classes specified by ClassDelete (default no classes).
+ * Ignores non-class resources.
+ *
+ * @see ClassNameUtils#isClass(String)
+ * @author shevek
+ */
+public class ClassFilterJarProcessor extends AbstractFilterJarProcessor {
+
+ // private static final Logger LOG = LoggerFactory.getLogger(ClassFilterJarProcessor.class);
+ private final List<ClassKeep> keepPatterns = new ArrayList<ClassKeep>();
+ private final List<ClassDelete> deletePatterns = new ArrayList<ClassDelete>();
+
+ public void addClassKeep(@Nonnull ClassKeep pattern) {
+ keepPatterns.add(pattern);
+ }
+
+ public void addClassDelete(@Nonnull ClassDelete pattern) {
+ deletePatterns.add(pattern);
+ }
+
+ @CheckForNull
+ protected <T extends AbstractPattern> T getMatchingPattern(@Nonnull List<? extends T> patterns, @Nonnull String name) {
+ for (T pattern : patterns) {
+ if (pattern.matches(name)) {
+ // LOG.debug(pattern + " matches " + name);
+ return pattern;
+ }
+ }
+ // LOG.debug("No pattern matches " + name);
+ return null;
+ }
+
+ @Override
+ protected boolean isFiltered(@Nonnull String name) {
+ if (!ClassNameUtils.isClass(name))
+ return false;
+ name = name.substring(0, name.length() - 6);
+ // LOG.debug("Looking to include " + name);
+ INCLUDE:
+ {
+ if (keepPatterns.isEmpty())
+ break INCLUDE;
+ if (getMatchingPattern(keepPatterns, name) != null)
+ break INCLUDE;
+ // We have include patterns, but none matched. Filter it.
+ return true;
+ }
+ // LOG.debug("Looking to exclude " + name);
+ return getMatchingPattern(deletePatterns, name) != null;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassTransformerJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassTransformerJarProcessor.java
new file mode 100644
index 0000000000..1dfc805a84
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ClassTransformerJarProcessor.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.asm.ClassTransformer;
+import com.tonicsystems.jarjar.transform.asm.GetNameClassWriter;
+import com.tonicsystems.jarjar.transform.Transformable;
+import com.tonicsystems.jarjar.util.ClassNameUtils;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A JarProcessor which applies a list of {@link ClassTransformer ClassTransformers}
+ * to any files ending in .class.
+ */
+public class ClassTransformerJarProcessor implements JarProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClassTransformerJarProcessor.class);
+ private final List<ClassTransformer> classProcessors;
+
+ public ClassTransformerJarProcessor(@Nonnull List<ClassTransformer> classProcessors) {
+ this.classProcessors = classProcessors;
+ }
+
+ public ClassTransformerJarProcessor(@Nonnull ClassTransformer... classProcessors) {
+ this(Arrays.asList(classProcessors));
+ }
+
+ @Override
+ public Result scan(Transformable struct) throws IOException {
+ return Result.KEEP;
+ }
+
+ @Override
+ public Result process(Transformable struct) throws IOException {
+ if (ClassNameUtils.isClass(struct.name)) {
+ try {
+ ClassReader reader = new ClassReader(struct.data);
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ GetNameClassWriter namer = new GetNameClassWriter(writer);
+ ClassVisitor cv = namer;
+ for (ClassTransformer classProcessor : classProcessors)
+ cv = classProcessor.transform(cv);
+ reader.accept(cv, ClassReader.EXPAND_FRAMES);
+ struct.name = ClassNameUtils.javaNameToPath(namer.getClassName());
+ struct.data = writer.toByteArray();
+ } catch (Exception e) {
+ LOG.warn("Failed to read class " + struct.name + ": " + e);
+ }
+ }
+ return Result.KEEP;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DefaultJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DefaultJarProcessor.java
new file mode 100644
index 0000000000..c53757c334
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DefaultJarProcessor.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.asm.PackageRemapper;
+import com.tonicsystems.jarjar.transform.config.ClassDelete;
+import com.tonicsystems.jarjar.transform.config.ClassKeepTransitive;
+import com.tonicsystems.jarjar.transform.config.ClassRename;
+import com.tonicsystems.jarjar.transform.asm.RemappingClassTransformer;
+import com.tonicsystems.jarjar.transform.config.ClassKeep;
+import com.tonicsystems.jarjar.transform.config.RulesFileParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultJarProcessor extends JarProcessorChain implements RulesFileParser.Output {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultJarProcessor.class);
+ // private final Map<String, String> renames = new HashMap<String, String>();
+
+ private final ManifestFilterJarProcessor manifestFilterJarProcessor = new ManifestFilterJarProcessor();
+ private final ClassFilterJarProcessor classFilterJarProcessor = new ClassFilterJarProcessor();
+ private final ClassClosureJarProcessor classClosureFilterJarProcessor = new ClassClosureJarProcessor();
+ private final PackageRemapper packageRemapper = new PackageRemapper();
+ private final RemappingClassTransformer remappingClassTransformer = new RemappingClassTransformer(packageRemapper);
+ private final ResourceRenamerJarProcessor resourceRenamerJarProcessor = new ResourceRenamerJarProcessor(packageRemapper);
+
+ public DefaultJarProcessor() {
+ add(new DirectoryFilterJarProcessor());
+ add(manifestFilterJarProcessor);
+ add(classFilterJarProcessor);
+ add(classClosureFilterJarProcessor);
+ add(new ClassTransformerJarProcessor(remappingClassTransformer));
+ add(resourceRenamerJarProcessor);
+ }
+
+ @Override
+ public void addClassDelete(ClassDelete classDelete) {
+ classFilterJarProcessor.addClassDelete(classDelete);
+ }
+
+ @Override
+ public void addClassRename(ClassRename classRename) {
+ packageRemapper.addRule(classRename);
+ }
+
+ @Override
+ public void addClassKeep(ClassKeep classKeep) {
+ classFilterJarProcessor.addClassKeep(classKeep);
+ }
+
+ @Override
+ public void addClassKeepTransitive(ClassKeepTransitive classKeepTransitive) {
+ classClosureFilterJarProcessor.addKeep(classKeepTransitive);
+ }
+
+ public void setSkipManifest(boolean value) {
+ manifestFilterJarProcessor.setEnabled(value);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DirectoryFilterJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DirectoryFilterJarProcessor.java
new file mode 100644
index 0000000000..30fdb2a82e
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/DirectoryFilterJarProcessor.java
@@ -0,0 +1,24 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+/**
+ *
+ * @author shevek
+ */
+public class DirectoryFilterJarProcessor extends AbstractFilterJarProcessor {
+
+ @Override
+ protected boolean isFiltered(String name) {
+ return name.endsWith("/");
+ }
+
+ @Override
+ protected boolean isVerbose() {
+ return false;
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessor.java
new file mode 100644
index 0000000000..5c652dabe3
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessor.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.Transformable;
+import java.io.IOException;
+import javax.annotation.Nonnull;
+
+public interface JarProcessor {
+
+ public static enum Result {
+
+ KEEP,
+ DISCARD;
+ }
+
+ // public boolean isEnabled();
+
+ @Nonnull
+ public Result scan(@Nonnull Transformable struct) throws IOException;
+
+ /**
+ * Process the entry (e.g. rename the file)
+ * <p>
+ * Returns <code>true</code> if the processor wants to retain the entry. In this case, the entry can be removed
+ * from the jar file in a future time. Return <code>false</code> for the entries which do not have been changed and
+ * there fore are not to be deleted
+ *
+ * @param struct The archive entry to be transformed.
+ * @return <code>true</code> if he process chain can continue after this process
+ * @throws IOException if it all goes upside down
+ */
+ @Nonnull
+ public Result process(@Nonnull Transformable struct) throws IOException;
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessorChain.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessorChain.java
new file mode 100644
index 0000000000..397aba6b67
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/JarProcessorChain.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.Transformable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import javax.annotation.Nonnull;
+
+public class JarProcessorChain extends ArrayList<JarProcessor> implements JarProcessor {
+
+ public JarProcessorChain(@Nonnull Iterable<? extends JarProcessor> processors) {
+ for (JarProcessor processor : processors)
+ add(processor);
+ }
+
+ public JarProcessorChain(@Nonnull JarProcessor... processors) {
+ this(Arrays.asList(processors));
+ }
+
+ @Override
+ public Result scan(Transformable struct) throws IOException {
+ for (JarProcessor processor : this)
+ if (processor.scan(struct) == Result.DISCARD)
+ return Result.DISCARD;
+ return Result.KEEP;
+ }
+
+ @Override
+ public Result process(Transformable struct) throws IOException {
+ for (JarProcessor processor : this)
+ if (processor.process(struct) == Result.DISCARD)
+ return Result.DISCARD;
+ return Result.KEEP;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ManifestFilterJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ManifestFilterJarProcessor.java
new file mode 100644
index 0000000000..d5711fd409
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ManifestFilterJarProcessor.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import java.util.Collections;
+
+/**
+ * Excludes the manifest.
+ */
+public class ManifestFilterJarProcessor extends PathFilterJarProcessor {
+
+ public static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+
+ private boolean enabled = false;
+
+ public ManifestFilterJarProcessor() {
+ super(Collections.singleton(MANIFEST_PATH));
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ protected boolean isFiltered(String name) {
+ if (!isEnabled())
+ return false;
+ return super.isFiltered(name);
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/PathFilterJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/PathFilterJarProcessor.java
new file mode 100644
index 0000000000..c54cd7ca74
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/PathFilterJarProcessor.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import java.util.Set;
+import javax.annotation.Nonnull;
+
+/**
+ * Excludes resources by exact name.
+ */
+public class PathFilterJarProcessor extends AbstractFilterJarProcessor {
+
+ private final Set<? extends String> excludes;
+
+ public PathFilterJarProcessor(@Nonnull Set<? extends String> excludes) {
+ this.excludes = excludes;
+ }
+
+ @Override
+ protected boolean isFiltered(String name) {
+ return excludes.contains(name);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ResourceRenamerJarProcessor.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ResourceRenamerJarProcessor.java
new file mode 100644
index 0000000000..42c018da40
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/transform/jar/ResourceRenamerJarProcessor.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.transform.jar;
+
+import com.tonicsystems.jarjar.transform.asm.PackageRemapper;
+import com.tonicsystems.jarjar.transform.Transformable;
+import com.tonicsystems.jarjar.util.ClassNameUtils;
+import java.io.IOException;
+import javax.annotation.Nonnull;
+
+/**
+ * Allows any file which is NOT a JAR file.
+ */
+public class ResourceRenamerJarProcessor implements JarProcessor {
+
+ private final PackageRemapper pr;
+
+ public ResourceRenamerJarProcessor(@Nonnull PackageRemapper pr) {
+ this.pr = pr;
+ }
+
+ @Override
+ public Result scan(Transformable struct) throws IOException {
+ return Result.KEEP;
+ }
+
+ @Override
+ public Result process(Transformable struct) throws IOException {
+ if (!ClassNameUtils.isClass(struct.name))
+ struct.name = pr.mapPath(struct.name);
+ return Result.KEEP;
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/ClassNameUtils.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/ClassNameUtils.java
new file mode 100644
index 0000000000..7b133aa136
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/ClassNameUtils.java
@@ -0,0 +1,79 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.util;
+
+import java.io.File;
+import java.util.regex.Pattern;
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public class ClassNameUtils {
+
+ private static final Pattern ARRAY_FOR_NAME_PATTERN
+ = Pattern.compile("\\[L[\\p{javaJavaIdentifierPart}\\.]+?;");
+
+ /**
+ * Returns true if the given string looks like a Java array name.
+ * @param value The name to inspect.
+ * @return true if the given string looks like a Java array name.
+ */
+ // also used by KeepProcessor
+ public static boolean isArrayForName(String value) {
+ // Type type = Type.getType(value);
+ // type.getSort() == ARRAY;
+ // type.getElementType();
+ return ARRAY_FOR_NAME_PATTERN.matcher(value).matches();
+ }
+
+ // TODO: use this for package remapping too?
+ /**
+ * Returns true if the String looks like a Java type name.
+ * @param value The name to inspect.
+ * @return true if the String looks like a Java type name.
+ */
+ public static boolean isForName(@Nonnull String value) {
+ if (value.equals(""))
+ return false;
+ for (int i = 0, len = value.length(); i < len; i++) {
+ char c = value.charAt(i);
+ if (c != '.' && !Character.isJavaIdentifierPart(c))
+ return false;
+ }
+ return true;
+ }
+
+ @Nonnull
+ public static String javaNameToPath(@Nonnull String className) {
+ return className.replace('.', '/') + ClassNameUtils.EXT_CLASS;
+ }
+
+ @Nonnull
+ public static String pathToJavaName(@Nonnull String path) {
+ if (isClass(path))
+ path = path.substring(0, path.length() - EXT_CLASS.length());
+ return path.replace('/', '.');
+ }
+
+ public static final String EXT_CLASS = ".class";
+
+ public static boolean isClass(@Nonnull String name) {
+ return hasExtension(name, EXT_CLASS);
+ }
+
+ public static boolean hasExtension(@Nonnull File file, @Nonnull String ext) {
+ return hasExtension(file.getName(), ext);
+ }
+
+ public static boolean hasExtension(@Nonnull String name, @Nonnull String ext) {
+ if (name.length() < ext.length())
+ return false;
+ String actual = name.substring(name.length() - ext.length());
+ return actual.equalsIgnoreCase(ext);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/IoUtil.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/IoUtil.java
new file mode 100644
index 0000000000..53d630eecc
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/IoUtil.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2008 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.util;
+
+import java.io.*;
+import javax.annotation.Nonnull;
+import javax.annotation.WillNotClose;
+
+public class IoUtil {
+
+ private IoUtil() {
+ }
+
+ public static void copy(@Nonnull @WillNotClose InputStream is, @Nonnull @WillNotClose OutputStream out, @Nonnull byte[] buf) throws IOException {
+ for (;;) {
+ int amt = is.read(buf);
+ if (amt < 0)
+ break;
+ out.write(buf, 0, amt);
+ }
+ }
+
+ public static void copy(@Nonnull File from, @Nonnull File to, @Nonnull byte[] buf) throws IOException {
+ InputStream in = new FileInputStream(from);
+ try {
+ OutputStream out = new FileOutputStream(to);
+ try {
+ copy(in, out, buf);
+ } finally {
+ out.close();
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ public static void flush(Object o) throws IOException {
+ if (o instanceof Flushable)
+ ((Flushable) o).flush();
+ }
+
+ public static void close(Object o) throws IOException {
+ if (o instanceof Closeable)
+ ((Closeable) o).close();
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/RuntimeIOException.java b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/RuntimeIOException.java
new file mode 100644
index 0000000000..b666385161
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/main/java/com/tonicsystems/jarjar/util/RuntimeIOException.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar.util;
+
+import java.io.IOException;
+import javax.annotation.Nonnull;
+
+public class RuntimeIOException extends RuntimeException {
+
+ private static final long serialVersionUID = 0L;
+
+ public RuntimeIOException(@Nonnull IOException e) {
+ super(e);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/GenericsTest.java b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/GenericsTest.java
new file mode 100644
index 0000000000..a7079471a8
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/GenericsTest.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.transform.asm.PackageRemapper;
+import com.tonicsystems.jarjar.transform.config.ClassRename;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.commons.RemappingClassAdapter;
+
+public class GenericsTest {
+
+ @Test
+ public void testTransform() throws Exception {
+ ClassRename rule = new ClassRename("java.lang.String", "com.tonicsystems.String");
+ RemappingClassAdapter t = new RemappingClassAdapter(null, new PackageRemapper(rule));
+ ClassReader reader = new ClassReader(getClass().getResourceAsStream("/Generics.class"));
+ reader.accept(t, 0);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/PackageRemapperTest.java b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/PackageRemapperTest.java
new file mode 100644
index 0000000000..5e36533adc
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/PackageRemapperTest.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.transform.asm.PackageRemapper;
+import com.tonicsystems.jarjar.transform.config.ClassRename;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class PackageRemapperTest {
+
+ protected PackageRemapper remapper;
+
+ @Before
+ public void setUp() {
+ ClassRename rule = new ClassRename("org.**", "foo.@1");
+ remapper = new PackageRemapper(Collections.singletonList(rule));
+ }
+
+ @Test
+ public void testMapValue() {
+ assertUnchangedValue("[^\\s;/@&=,.?:+$]");
+ assertUnchangedValue("[Ljava/lang/Object;");
+ assertUnchangedValue("[Lorg/example/Object;");
+ assertUnchangedValue("[Ljava.lang.Object;");
+ assertUnchangedValue("[Lorg.example/Object;");
+ assertUnchangedValue("[L;");
+ assertUnchangedValue("[Lorg.example.Object;;");
+ assertUnchangedValue("[Lorg.example.Obj ct;");
+ assertUnchangedValue("org.example/Object");
+
+ assertEquals("[Lfoo.example.Object;", remapper.mapValue("[Lorg.example.Object;"));
+ assertEquals("foo.example.Object", remapper.mapValue("org.example.Object"));
+ assertEquals("foo/example/Object", remapper.mapValue("org/example/Object"));
+ assertEquals("foo/example.Object", remapper.mapValue("org/example.Object")); // path match
+
+ assertEquals("foo.example.package-info", remapper.mapValue("org.example.package-info"));
+ assertEquals("foo/example/package-info", remapper.mapValue("org/example/package-info"));
+ assertEquals("foo/example.package-info", remapper.mapValue("org/example.package-info"));
+ }
+
+ private void assertUnchangedValue(String value) {
+ assertEquals(value, remapper.mapValue(value));
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/RulesFileParserTest.java b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/RulesFileParserTest.java
new file mode 100644
index 0000000000..06b1c42288
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/RulesFileParserTest.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import org.junit.Test;
+
+public class RulesFileParserTest {
+
+ @Test
+ public void testSimple() throws Exception {
+ // TODO
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/WildcardTest.java b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/WildcardTest.java
new file mode 100644
index 0000000000..7253a2c4da
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/WildcardTest.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.transform.config.ResourceRename;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static org.junit.Assert.*;
+
+public class WildcardTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WildcardTest.class);
+
+ @Test
+ public void testWildcards() {
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/proxy/Mixin$Generator",
+ "foo/proxy/Mixin$Generator");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/Bar/Baz", "foo/Bar/Baz");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/", "foo/");
+ wildcard("net/sf/cglib/**", "foo/@1", "net/sf/cglib/!", null);
+ wildcard("net/sf/cglib/*", "foo/@1", "net/sf/cglib/Bar", "foo/Bar");
+ wildcard("net/sf/cglib/*/*", "foo/@2/@1", "net/sf/cglib/Bar/Baz", "foo/Baz/Bar");
+ }
+
+ private static void wildcard(String pattern, String result, String value, String expect) {
+ ResourceRename wc = new ResourceRename(pattern, result);
+ LOG.info("Compile: " + pattern + " -> " + wc);
+ String actual = wc.replace(value);
+ LOG.info("Replace: " + value + " -> " + actual + " (expected " + expect + ")");
+ assertEquals(expect, actual);
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/AbstractJarTransformerTest.java b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/AbstractJarTransformerTest.java
new file mode 100644
index 0000000000..a58eb867bd
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/AbstractJarTransformerTest.java
@@ -0,0 +1,52 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import javax.annotation.Nonnull;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author shevek
+ */
+public class AbstractJarTransformerTest {
+
+ @Nonnull
+ protected static File newJar(String propertyName) {
+ return new File(System.getProperty(propertyName));
+ }
+ protected final File jar = newJar("jar");
+ protected final File[] jars = new File[]{
+ newJar("jar0"),
+ newJar("jar1"),
+ newJar("jar2"),
+ newJar("jar3")
+ };
+
+ @Nonnull
+ protected Method getMethod(@Nonnull File file, @Nonnull String className, @Nonnull String methodName, @Nonnull Class<?>... parameterTypes) throws Exception {
+ URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()}, getClass().getClassLoader());
+ Class<?> c = loader.loadClass(className);
+ return c.getMethod("main", parameterTypes);
+ }
+
+ protected static void assertContains(@Nonnull JarFile jarFile, @Nonnull String resourceName) {
+ JarEntry jarEntry = jarFile.getJarEntry(resourceName);
+ assertNotNull("JarFile " + jarFile + " does not contain entry " + resourceName, jarEntry);
+ }
+
+ protected static void assertNotContains(@Nonnull JarFile jarFile, @Nonnull String resourceName) {
+ JarEntry jarEntry = jarFile.getJarEntry(resourceName);
+ assertNull("JarFile " + jarFile + " does contains unexpected entry " + resourceName, jarEntry);
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/JarTransformerTest.java b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/JarTransformerTest.java
new file mode 100644
index 0000000000..79a533f94e
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/java/com/tonicsystems/jarjar/transform/JarTransformerTest.java
@@ -0,0 +1,54 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.tonicsystems.jarjar.transform;
+
+import com.tonicsystems.jarjar.classpath.ClassPath;
+import com.tonicsystems.jarjar.transform.jar.DefaultJarProcessor;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.jar.JarFile;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author shevek
+ */
+public class JarTransformerTest extends AbstractJarTransformerTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JarTransformerTest.class);
+
+ private final File outputFile = new File("build/tmp/output.jar");
+ private final DefaultJarProcessor processor = new DefaultJarProcessor();
+ private final JarTransformer transformer = new JarTransformer(outputFile, processor);
+ private final ClassPath classPath = new ClassPath(new File("/"), jars);
+
+ /*
+ @Test
+ public void testTransformNoop() throws Exception {
+ processor.setSkipManifest(true);
+ processor.add(new PathFilterJarProcessor(Collections.singleton("META-INF/jarjar-testdata.properties")));
+ transformer.transform(classPath);
+ }
+ */
+ @Test
+ public void testTransformRename() throws Exception {
+ processor.setSkipManifest(true);
+ // processor.add(new PathFilterJarProcessor(Collections.singleton("META-INF/jarjar-testdata.properties")));
+ transformer.transform(classPath);
+
+ Method m = getMethod(outputFile, "org.anarres.jarjar.testdata.pkg0.Main", "main", String[].class);
+ m.invoke(null, (Object) new String[]{});
+
+ JarFile jarFile = new JarFile(outputFile);
+ assertContains(jarFile, "org/anarres/jarjar/testdata/pkg0/Main.class");
+ assertContains(jarFile, "org/anarres/jarjar/testdata/pkg1/Cls1.class");
+ assertContains(jarFile, "org/anarres/jarjar/testdata/pkg2/Cls2.class");
+ assertContains(jarFile, "org/anarres/jarjar/testdata/pkg3/Cls3.class");
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-core/src/test/resources/Generics.class b/third_party/java/jarjar/jarjar-core/src/test/resources/Generics.class
new file mode 100644
index 0000000000..827519a2e2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/resources/Generics.class
Binary files differ
diff --git a/third_party/java/jarjar/jarjar-core/src/test/resources/enumtest.jar b/third_party/java/jarjar/jarjar-core/src/test/resources/enumtest.jar
new file mode 100644
index 0000000000..df34d1650b
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-core/src/test/resources/enumtest.jar
Binary files differ
diff --git a/third_party/java/jarjar/jarjar-gradle/build.gradle b/third_party/java/jarjar/jarjar-gradle/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/build.gradle
diff --git a/third_party/java/jarjar/jarjar-gradle/example/build.gradle b/third_party/java/jarjar/jarjar-gradle/example/build.gradle
new file mode 100644
index 0000000000..4bc3010fa5
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/example/build.gradle
@@ -0,0 +1,130 @@
+buildscript {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ }
+
+ dependencies {
+ def properties = new Properties();
+ file('../../gradle.properties').withReader { properties.load(it); }
+ classpath "org.anarres.jarjar:jarjar-gradle:${properties.version}"
+ }
+}
+
+subprojects {
+ apply plugin: 'java'
+ apply plugin: 'application'
+ apply plugin: 'org.anarres.jarjar'
+
+ mainClassName = "org.anarres.jarjar.test.Main"
+
+ repositories {
+ mavenCentral()
+ maven { url 'http://repo.hortonworks.com/content/repositories/releases/' }
+ }
+
+ sourceSets {
+ main {
+ java { srcDir rootProject.file('src/main/java') }
+ }
+ }
+}
+
+project(':sub0') {
+
+ configurations {
+ upstream
+ literal {
+ extendsFrom upstream
+ resolutionStrategy {
+ // http://gradle.org/docs/current/javadoc/org/gradle/api/artifacts/ResolutionStrategy.html
+ eachDependency { DependencyResolveDetails details ->
+ println "DependencyResolveDetails " + details.dump()
+ }
+ // http://gradle.org/docs/current/javadoc/org/gradle/api/artifacts/ComponentSelectionRules.html
+ componentSelection {
+ withModule("org.apache.hive:hive-metastore") { ComponentSelection selection ->
+ selection.reject("Rejecting all hive-metastore")
+ println "ComponentSelection: " + selection.dump()
+ }
+ }
+ }
+ }
+ compile {
+ extendsFrom literal
+ }
+ }
+
+ dependencies {
+ upstream('org.apache.hive:hive-exec:0.13.0.2.1.5.0-695') {
+ exclude group: 'net.hydromatic', module: 'optiq-core'
+ // transitive = false
+ }
+
+ compile jarjar.repackage {
+ from configurations.upstream
+
+ archiveBypass "commons*.jar"
+ archiveExclude "slf4j*.jar"
+
+ classDelete "org.apache.thrift.**"
+
+ classRename 'org.json.**', 'org.anarres.hive.json.@1'
+ classRename 'org.iq80.**', 'org.anarres.hive.iq80.@1'
+ classRename 'org.codehaus.jackson.**', 'org.anarres.hive.jackson.@1'
+ classRename 'com.google.**', 'org.anarres.hive.google.@1'
+ classRename 'javolution.**', 'org.anarres.hive.javolution.@1'
+ classRename 'com.esotericsoftware.kryo.**', 'org.anarres.hive.kryo.@1'
+ }
+ }
+
+}
+
+project(':sub1') {
+
+ dependencies {
+ compile jarjar.repackage {
+ from ('org.apache.hive:hive-exec:0.13.0.2.1.5.0-695') {
+ exclude group: 'net.hydromatic', module: 'optiq-core'
+ // transitive = false
+ }
+
+ archiveBypass "commons*.jar"
+ archiveExclude "slf4j*.jar"
+
+ classDelete "org.apache.thrift.**"
+
+ classRename 'org.json.**', 'org.anarres.hive.json.@1'
+ classRename 'org.iq80.**', 'org.anarres.hive.iq80.@1'
+ classRename 'org.codehaus.jackson.**', 'org.anarres.hive.jackson.@1'
+ classRename 'com.google.**', 'org.anarres.hive.google.@1'
+ classRename 'javolution.**', 'org.anarres.hive.javolution.@1'
+ classRename 'com.esotericsoftware.kryo.**', 'org.anarres.hive.kryo.@1'
+ }
+ }
+
+}
+
+project(':sub2') {
+
+ dependencies {
+ compile jarjar.repackage {
+ from gradleApi()
+
+ archiveBypass "commons*.jar"
+ archiveExclude "slf4j*.jar"
+
+ }
+ }
+
+}
+
+/*
+project(':sub3') {
+ dependencies {
+ compile jarjar.dependency('org.apache.hive:hive-exec:0.13.0.2.1.5.0-695') {
+ }
+ }
+}
+*/
+
diff --git a/third_party/java/jarjar/jarjar-gradle/example/settings.gradle b/third_party/java/jarjar/jarjar-gradle/example/settings.gradle
new file mode 100644
index 0000000000..c0fb16e043
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/example/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name='jarjar-gradle-example'
+include 'sub0', 'sub1', 'sub2' // , 'sub3'
diff --git a/third_party/java/jarjar/jarjar-gradle/example/src/main/java/org/anarres/jarjar/test/Main.java b/third_party/java/jarjar/jarjar-gradle/example/src/main/java/org/anarres/jarjar/test/Main.java
new file mode 100644
index 0000000000..6d88240d50
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/example/src/main/java/org/anarres/jarjar/test/Main.java
@@ -0,0 +1,7 @@
+package org.anarres.jarjar.test;
+
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("Hello, world.");
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarArchiveTask.java b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarArchiveTask.java
new file mode 100644
index 0000000000..8824b4a7b2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarArchiveTask.java
@@ -0,0 +1,32 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.gradle.plugin.jarjar;
+
+import groovy.lang.Closure;
+import javax.annotation.Nonnull;
+import org.gradle.api.internal.DocumentationRegistry;
+import org.gradle.api.internal.file.copy.CopyAction;
+import org.gradle.api.tasks.bundling.Jar;
+
+/**
+ *
+ * @author shevek
+ */
+public class JarjarArchiveTask extends Jar {
+
+ @Override
+ protected CopyAction createCopyAction() {
+ DocumentationRegistry documentationRegistry = getServices().get(DocumentationRegistry.class);
+ return new JarjarCopyAction(getArchivePath(), getCompressor(), documentationRegistry);
+ }
+
+ public void fromJar(@Nonnull Object... sourcePaths) {
+ }
+
+ public void fromJar(@Nonnull Object sourcePath, @Nonnull Closure c) {
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarController.java b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarController.java
new file mode 100644
index 0000000000..e7913ca1fc
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarController.java
@@ -0,0 +1,60 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.gradle.plugin.jarjar;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.annotation.Nonnull;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.internal.ClosureBackedAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This object appears as 'jarjar' in the project extensions.
+ *
+ * @author shevek
+ */
+public class JarjarController extends GroovyObjectSupport {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JarjarController.class);
+ private static final AtomicInteger SEQ = new AtomicInteger(0);
+ private final Project project;
+
+ public JarjarController(@Nonnull Project project) {
+ this.project = project;
+ }
+
+ @Nonnull
+ public Dependency dependency(Object dependencyNotation, Closure configurationClosure) {
+ Dependency d = project.getDependencies().create(dependencyNotation, configurationClosure);
+ LOG.info("sub is " + d);
+ return new JarjarDependency(d);
+ }
+
+ @Nonnull
+ public Dependency dependency(Object dependencyNotation) {
+ return dependency(dependencyNotation, Closure.IDENTITY);
+ }
+
+ @Nonnull
+ public FileCollection repackage(@Nonnull String name, @Nonnull Closure<?> c) {
+ JarjarTask jarjar = project.getTasks().create(
+ name,
+ JarjarTask.class,
+ new ClosureBackedAction<JarjarTask>(c));
+ return jarjar.getOutputs().getFiles();
+ }
+
+ @Nonnull
+ public FileCollection repackage(@Nonnull Closure<?> c) {
+ return repackage("jarjar-" + SEQ.getAndIncrement(), c);
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarCopyAction.java b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarCopyAction.java
new file mode 100644
index 0000000000..8dd0263b06
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarCopyAction.java
@@ -0,0 +1,137 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.gradle.plugin.jarjar;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import javax.annotation.Nonnull;
+import org.apache.commons.compress.archivers.jar.JarArchiveEntry;
+import org.apache.commons.compress.archivers.jar.JarArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.UnixStat;
+import org.gradle.api.Action;
+import org.gradle.api.GradleException;
+import org.gradle.api.UncheckedIOException;
+import org.gradle.api.file.FileCopyDetails;
+import org.gradle.api.internal.DocumentationRegistry;
+import org.gradle.api.internal.file.CopyActionProcessingStreamAction;
+import org.gradle.api.internal.file.copy.CopyAction;
+import org.gradle.api.internal.file.copy.CopyActionProcessingStream;
+import org.gradle.api.internal.file.copy.FileCopyDetailsInternal;
+import org.gradle.api.internal.file.copy.ZipCompressor;
+import org.gradle.api.internal.tasks.SimpleWorkResult;
+import org.gradle.api.tasks.WorkResult;
+import org.gradle.api.tasks.bundling.Zip;
+import org.gradle.api.tasks.bundling.internal.Zip64RequiredException;
+import org.gradle.internal.IoActions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Based on ZipCopyAction from Gradle sources.
+ *
+ * @author shevek
+ */
+public class JarjarCopyAction implements CopyAction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JarjarCopyAction.class);
+ private final File zipFile;
+ // private final ZipCompressor compressor;
+ private final DocumentationRegistry documentationRegistry;
+
+ public JarjarCopyAction(@Nonnull File zipFile, @Nonnull ZipCompressor compressor, @Nonnull DocumentationRegistry documentationRegistry) {
+ this.zipFile = zipFile;
+ // this.compressor = compressor;
+ this.documentationRegistry = documentationRegistry;
+ }
+
+ @Nonnull
+ @Override
+ public WorkResult execute(@Nonnull final CopyActionProcessingStream stream) {
+ LOG.info("CopyAction Executing " + stream);
+
+ stream.process(new ScanAction());
+
+ final JarArchiveOutputStream zipOutStr;
+
+ try {
+ zipOutStr = new JarArchiveOutputStream(new FileOutputStream(zipFile));
+ } catch (Exception e) {
+ throw new GradleException(String.format("Could not create ZIP '%s'.", zipFile), e);
+ }
+
+ try {
+ IoActions.withResource(zipOutStr, new Action<JarArchiveOutputStream>() {
+ @Override
+ public void execute(@Nonnull JarArchiveOutputStream outputStream) {
+ stream.process(new ProcessAction(outputStream));
+ }
+ });
+ } catch (UncheckedIOException e) {
+ if (e.getCause() instanceof Zip64RequiredException) {
+ throw new org.gradle.api.tasks.bundling.internal.Zip64RequiredException(
+ String.format("%s\n\nTo build this archive, please enable the zip64 extension.\nSee: %s", e.getCause().getMessage(), documentationRegistry.getDslRefForProperty(Zip.class, "zip64"))
+ );
+ }
+ }
+
+ return new SimpleWorkResult(true);
+ }
+
+ private class ScanAction implements CopyActionProcessingStreamAction {
+
+ @Override
+ public void processFile(FileCopyDetailsInternal details) {
+ LOG.info("CopyAction Scanning " + details);
+ }
+ }
+
+ private class ProcessAction implements CopyActionProcessingStreamAction {
+
+ private final JarArchiveOutputStream zipOutStr;
+
+ public ProcessAction(@Nonnull JarArchiveOutputStream zipOutStr) {
+ this.zipOutStr = zipOutStr;
+ }
+
+ @Override
+ public void processFile(@Nonnull FileCopyDetailsInternal details) {
+ LOG.info("CopyAction Processing " + details);
+
+ if (details.isDirectory()) {
+ visitDir(details);
+ } else {
+ visitFile(details);
+ }
+ }
+
+ private void visitFile(@Nonnull FileCopyDetails fileDetails) {
+ try {
+ JarArchiveEntry archiveEntry = new JarArchiveEntry(fileDetails.getRelativePath().getPathString());
+ archiveEntry.setTime(fileDetails.getLastModified());
+ archiveEntry.setUnixMode(UnixStat.FILE_FLAG | fileDetails.getMode());
+ zipOutStr.putArchiveEntry(archiveEntry);
+ fileDetails.copyTo(zipOutStr);
+ zipOutStr.closeArchiveEntry();
+ } catch (Exception e) {
+ throw new GradleException(String.format("Could not add %s to ZIP '%s'.", fileDetails, zipFile), e);
+ }
+ }
+
+ private void visitDir(@Nonnull FileCopyDetails dirDetails) {
+ try {
+ // Trailing slash in name indicates that entry is a directory
+ JarArchiveEntry archiveEntry = new JarArchiveEntry(dirDetails.getRelativePath().getPathString() + '/');
+ archiveEntry.setTime(dirDetails.getLastModified());
+ archiveEntry.setUnixMode(UnixStat.DIR_FLAG | dirDetails.getMode());
+ zipOutStr.putArchiveEntry(archiveEntry);
+ zipOutStr.closeArchiveEntry();
+ } catch (Exception e) {
+ throw new GradleException(String.format("Could not add %s to ZIP '%s'.", dirDetails, zipFile), e);
+ }
+ }
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarDependency.java b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarDependency.java
new file mode 100644
index 0000000000..50e292f676
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarDependency.java
@@ -0,0 +1,67 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.gradle.plugin.jarjar;
+
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.gradle.api.Buildable;
+import org.gradle.api.Task;
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.internal.artifacts.ResolvableDependency;
+import org.gradle.api.tasks.TaskDependency;
+
+/**
+ *
+ * @author shevek
+ */
+public class JarjarDependency implements /* ResolvableDependency, */ Dependency, Buildable {
+
+ private final Dependency delegate;
+
+ public JarjarDependency(@Nonnull Dependency delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String getGroup() {
+ return delegate.getGroup();
+ }
+
+ @Override
+ public String getName() {
+ return delegate.getName();
+ }
+
+ @Override
+ public String getVersion() {
+ return delegate.getVersion();
+ }
+
+ @Override
+ public boolean contentEquals(Dependency d) {
+ while (d instanceof JarjarDependency)
+ d = ((JarjarDependency) d).delegate;
+ return delegate.contentEquals(d);
+ }
+
+ @Override
+ public Dependency copy() {
+ return new JarjarDependency(delegate);
+ }
+
+ @Override
+ public TaskDependency getBuildDependencies() {
+ if (delegate instanceof Buildable)
+ return ((Buildable) delegate).getBuildDependencies();
+ return new TaskDependency() {
+ @Override
+ public Set<? extends Task> getDependencies(Task task) {
+ return Collections.emptySet();
+ }
+ };
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarPlugin.java b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarPlugin.java
new file mode 100644
index 0000000000..93c3903a02
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarPlugin.java
@@ -0,0 +1,41 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.gradle.plugin.jarjar;
+
+import groovy.lang.Closure;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.internal.ClosureBackedAction;
+import static org.bouncycastle.asn1.x500.style.RFC4519Style.c;
+import static org.gradle.internal.Transformers.name;
+
+/**
+ *
+ * @author shevek
+ */
+public class JarjarPlugin implements Plugin<Project> {
+
+ @Override
+ public void apply(final Project project) {
+ project.getLogger().info("Applying " + this);
+ // project.getExtensions().getExtraProperties().set("Jarjar", JarjarTask.class);
+ /*
+ project.getExtensions().getExtraProperties().set("jarjarDependency", new Closure<FileCollection>(JarjarPlugin.this) {
+ @Override
+ public FileCollection call(Object... args) {
+ JarjarTask jarjar = project.getTasks().create(
+ name,
+ JarjarTask.class,
+ new ClosureBackedAction<JarjarTask>(c));
+ return jarjar.getOutputs().getFiles();
+ }
+ });
+ */
+ project.getExtensions().create("jarjar", JarjarController.class, project);
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarTask.java b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarTask.java
new file mode 100644
index 0000000000..9d863caf35
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/src/main/java/org/anarres/gradle/plugin/jarjar/JarjarTask.java
@@ -0,0 +1,232 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.gradle.plugin.jarjar;
+
+import com.tonicsystems.jarjar.classpath.ClassPath;
+import com.tonicsystems.jarjar.transform.JarTransformer;
+import com.tonicsystems.jarjar.transform.config.ClassKeepTransitive;
+import com.tonicsystems.jarjar.transform.config.ClassDelete;
+import com.tonicsystems.jarjar.transform.config.ClassRename;
+import com.tonicsystems.jarjar.transform.jar.DefaultJarProcessor;
+import groovy.lang.Closure;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.apache.oro.text.GlobCompiler;
+import org.apache.oro.text.regex.MalformedPatternException;
+import org.apache.oro.text.regex.Pattern;
+import org.apache.oro.text.regex.Perl5Matcher;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.artifacts.dsl.DependencyHandler;
+import org.gradle.api.file.ConfigurableFileCollection;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.internal.ConventionTask;
+import org.gradle.api.specs.Spec;
+import org.gradle.api.tasks.InputFiles;
+import org.gradle.api.tasks.OutputFile;
+import org.gradle.api.tasks.OutputFiles;
+import org.gradle.api.tasks.TaskAction;
+import org.gradle.api.tasks.TaskOutputs;
+
+/**
+ *
+ * @author shevek
+ */
+public class JarjarTask extends ConventionTask {
+
+ private class FilterSpec implements Spec<File> {
+
+ private final String message;
+ private final Iterable<? extends Pattern> patterns;
+ private final boolean result;
+
+ public FilterSpec(@Nonnull String message, @Nonnull Iterable<? extends Pattern> patterns, boolean result) {
+ this.message = message;
+ this.patterns = patterns;
+ this.result = result;
+ }
+
+ @Override
+ public boolean isSatisfiedBy(File t) {
+ if (matchesAny(patterns, t.getName())) {
+ getLogger().info(message + " " + t);
+ return result;
+ }
+ return !result;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "(patterns=" + patterns + ")";
+ }
+ }
+
+ private static final Perl5Matcher globMatcher = new Perl5Matcher();
+
+ private static boolean matchesAny(@Nonnull Iterable<? extends Pattern> patterns, @Nonnull String text) {
+ for (Pattern pattern : patterns) {
+ if (globMatcher.matches(text, pattern)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Nonnull
+ private static Iterable<Pattern> toPatterns(@Nonnull Iterable<? extends String>... patterns) throws MalformedPatternException {
+ GlobCompiler compiler = new GlobCompiler();
+ List<Pattern> out = new ArrayList<Pattern>();
+ for (Iterable<? extends String> in : patterns)
+ for (String pattern : in)
+ out.add(compiler.compile(pattern));
+ return out;
+ }
+
+ private final ConfigurableFileCollection sourceFiles;
+ private final Set<String> archiveBypasses = new HashSet<String>();
+ private final Set<String> archiveExcludes = new HashSet<String>();
+ private File destinationDir;
+ private String destinationName;
+
+ private final DefaultJarProcessor processor = new DefaultJarProcessor();
+
+ public JarjarTask() {
+ sourceFiles = getProject().files();
+ }
+
+ @InputFiles
+ public FileCollection getSourceFiles() {
+ return sourceFiles;
+ }
+
+ /**
+ * Returns the directory where the archive is generated into.
+ *
+ * @return the directory
+ */
+ public File getDestinationDir() {
+ File out = destinationDir;
+ if (out == null)
+ out = new File(getProject().getBuildDir(), "jarjar");
+ return out;
+ }
+
+ public void setDestinationDir(File destinationDir) {
+ this.destinationDir = destinationDir;
+ }
+
+ /**
+ * Returns the file name of the generated archive.
+ *
+ * @return the name
+ */
+ public String getDestinationName() {
+ String out = destinationName;
+ if (out == null)
+ out = getName() + ".jar";
+ return out;
+ }
+
+ public void setDestinationName(String destinationName) {
+ this.destinationName = destinationName;
+ }
+
+ /**
+ * The path where the archive is constructed.
+ * The path is simply the {@code destinationDir} plus the {@code destinationName}.
+ *
+ * @return a File object with the path to the archive
+ */
+ @OutputFile
+ public File getDestinationPath() {
+ return new File(getDestinationDir(), getDestinationName());
+ }
+
+ @OutputFiles
+ public FileCollection getBypassedArchives() throws MalformedPatternException {
+ return sourceFiles.filter(new FilterSpec("Bypassing archive", toPatterns(archiveBypasses), true));
+ }
+
+ /**
+ * Processes a FileCollection, which may be simple, a {@link Configuration},
+ * or derived from a {@link TaskOutputs}.
+ *
+ * @param files The input FileCollection to consume.
+ */
+ public void from(@Nonnull FileCollection files) {
+ sourceFiles.from(files);
+ }
+
+ /**
+ * Processes a Dependency directly, which may be derived from
+ * {@link DependencyHandler#create(java.lang.Object)},
+ * {@link DependencyHandler#project(java.util.Map)},
+ * {@link DependencyHandler#module(java.lang.Object)},
+ * {@link DependencyHandler#gradleApi()}, etc.
+ *
+ * @param dependency The dependency to process.
+ */
+ public void from(@Nonnull Dependency dependency) {
+ Configuration configuration = getProject().getConfigurations().detachedConfiguration(dependency);
+ from(configuration);
+ }
+
+ /**
+ * Processes a dependency specified by name.
+ *
+ * @param dependencyNotation The dependency, in a notation described in {@link DependencyHandler}.
+ * @param configClosure The closure to use to configure the dependency.
+ * @see DependencyHandler
+ */
+ public void from(@Nonnull String dependencyNotation, Closure configClosure) {
+ from(getProject().getDependencies().create(dependencyNotation, configClosure));
+ }
+
+ /**
+ * Processes a dependency specified by name.
+ *
+ * @param dependencyNotation The dependency, in a notation described in {@link DependencyHandler}.
+ */
+ public void from(@Nonnull String dependencyNotation) {
+ from(getProject().getDependencies().create(dependencyNotation));
+ }
+
+ public void archiveBypass(@Nonnull String pattern) throws MalformedPatternException {
+ archiveBypasses.add(pattern);
+ }
+
+ public void archiveExclude(@Nonnull String pattern) throws MalformedPatternException {
+ archiveExcludes.add(pattern);
+ }
+
+ public void classRename(@Nonnull String pattern, @Nonnull String replacement) {
+ processor.addClassRename(new ClassRename(pattern, replacement));
+ }
+
+ public void classDelete(@Nonnull String pattern) {
+ processor.addClassDelete(new ClassDelete(pattern));
+ }
+
+ public void classClosureRoot(@Nonnull String pattern) {
+ processor.addClassKeepTransitive(new ClassKeepTransitive(pattern));
+ }
+
+ @TaskAction
+ public void run() throws Exception {
+ FileCollection inputFiles = sourceFiles.filter(new FilterSpec("Excluding archive", toPatterns(archiveBypasses, archiveExcludes), false));
+ final File outputFile = getDestinationPath();
+ outputFile.getParentFile().mkdirs();
+ getLogger().info("Running jarjar for {}", outputFile);
+ getLogger().info("Inputs are {}", inputFiles);
+
+ JarTransformer transformer = new JarTransformer(outputFile, processor);
+ transformer.transform(new ClassPath(getProject().getProjectDir(), inputFiles));
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-gradle/src/test/java/org/anarres/gradle/plugin/jarjar/JarjarDependencyTest.java b/third_party/java/jarjar/jarjar-gradle/src/test/java/org/anarres/gradle/plugin/jarjar/JarjarDependencyTest.java
new file mode 100644
index 0000000000..b6a82716c3
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-gradle/src/test/java/org/anarres/gradle/plugin/jarjar/JarjarDependencyTest.java
@@ -0,0 +1,21 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.gradle.plugin.jarjar;
+
+import org.junit.Test;
+// import static org.junit.Assert.*;
+
+/**
+ *
+ * @author shevek
+ */
+public class JarjarDependencyTest {
+
+ @Test
+ public void testTask() {
+ }
+
+}
diff --git a/third_party/java/jarjar/jarjar-maven/build.gradle b/third_party/java/jarjar/jarjar-maven/build.gradle
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-maven/build.gradle
diff --git a/third_party/java/jarjar/jarjar-maven/src/main/java/com/tonicsystems/jarjar/JarJarMojo.java b/third_party/java/jarjar/jarjar-maven/src/main/java/com/tonicsystems/jarjar/JarJarMojo.java
new file mode 100644
index 0000000000..140cb1f24d
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-maven/src/main/java/com/tonicsystems/jarjar/JarJarMojo.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright 2007 Google Inc.
+ *
+ * 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.
+ */
+package com.tonicsystems.jarjar;
+
+import com.tonicsystems.jarjar.classpath.ClassPath;
+import com.tonicsystems.jarjar.transform.jar.DefaultJarProcessor;
+import com.tonicsystems.jarjar.transform.config.RulesFileParser;
+import com.tonicsystems.jarjar.transform.JarTransformer;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+
+public class JarJarMojo extends AbstractMojo {
+
+ private File fromJar;
+ private File toJar;
+ private File rulesFile;
+ private String rules;
+ @Deprecated // Maven might need this for compatibility.
+ private boolean verbose;
+
+ @Override
+ public void execute() throws MojoExecutionException {
+ if (!((rulesFile == null || !rulesFile.exists()) ^ (rules == null)))
+ throw new MojoExecutionException("Exactly one of rules or rulesFile is required");
+
+ try {
+ DefaultJarProcessor processor = new DefaultJarProcessor();
+ if (rules != null) {
+ RulesFileParser.parse(processor, rules);
+ } else {
+ RulesFileParser.parse(processor, rulesFile);
+ }
+ // TODO: refactor with Main.java
+ JarTransformer transformer = new JarTransformer(toJar, processor);
+ ClassPath fromClassPath = new ClassPath(new File(System.getProperty("user.dir")), Collections.singleton(fromJar));
+ transformer.transform(fromClassPath);
+ } catch (IOException e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg0/Main.java b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg0/Main.java
new file mode 100644
index 0000000000..97608f621c
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg0/Main.java
@@ -0,0 +1,21 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.jarjar.testdata.pkg0;
+
+import org.anarres.jarjar.testdata.pkg1.Cls1;
+
+/**
+ *
+ * @author shevek
+ */
+public class Main {
+
+ public static void main(String[] args) {
+ Cls1.m_s();
+ Cls1 c = new Cls1();
+ c.m_d();
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg1/Cls1.java b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg1/Cls1.java
new file mode 100644
index 0000000000..51daf8f254
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg1/Cls1.java
@@ -0,0 +1,24 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.jarjar.testdata.pkg1;
+
+import org.anarres.jarjar.testdata.pkg2.Cls2;
+
+/**
+ *
+ * @author shevek
+ */
+public class Cls1 {
+
+ public void m_d() {
+ Cls2 c = new Cls2();
+ c.m_d();
+ }
+
+ public static void m_s() {
+ Cls2.m_s();
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg2/Cls2.java b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg2/Cls2.java
new file mode 100644
index 0000000000..1125b56cfe
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg2/Cls2.java
@@ -0,0 +1,24 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.jarjar.testdata.pkg2;
+
+import org.anarres.jarjar.testdata.pkg3.Cls3;
+
+/**
+ *
+ * @author shevek
+ */
+public class Cls2 {
+
+ public void m_d() {
+ Cls3 c = new Cls3();
+ c.m_d();
+ }
+
+ public static void m_s() {
+ Cls3.m_s();
+ }
+}
diff --git a/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg3/Cls3.java b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg3/Cls3.java
new file mode 100644
index 0000000000..637e0a17fe
--- /dev/null
+++ b/third_party/java/jarjar/jarjar-testdata/src/main/java/org/anarres/jarjar/testdata/pkg3/Cls3.java
@@ -0,0 +1,19 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.anarres.jarjar.testdata.pkg3;
+
+/**
+ *
+ * @author shevek
+ */
+public class Cls3 {
+
+ public void m_d() {
+ }
+
+ public static void m_s() {
+ }
+}
diff --git a/third_party/java/jarjar/settings.gradle b/third_party/java/jarjar/settings.gradle
new file mode 100644
index 0000000000..e5e182a88e
--- /dev/null
+++ b/third_party/java/jarjar/settings.gradle
@@ -0,0 +1,7 @@
+rootProject.name='jarjar'
+include 'jarjar-testdata',
+ 'jarjar-core',
+ 'jarjar-ant',
+ 'jarjar-maven',
+ 'jarjar-gradle',
+ 'jarjar-command'
diff --git a/third_party/java/jarjar/src/main/ghpages/index.html b/third_party/java/jarjar/src/main/ghpages/index.html
new file mode 100644
index 0000000000..32292c3702
--- /dev/null
+++ b/third_party/java/jarjar/src/main/ghpages/index.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+<a href="docs/javadoc/">Javadoc</a>
+<a href="docs/cobertura/">Coverage</a>
+</body>
+</html>