diff --git a/scripts/ij.bazelproject b/scripts/ij.bazelproject
index d4991199445512..e35d2de84abc4d 100644
--- a/scripts/ij.bazelproject
+++ b/scripts/ij.bazelproject
@@ -16,7 +16,6 @@ targets:
//src/java_tools/buildjar/javatests/...
//src/java_tools/junitrunner/java/com/google/testing/junit/runner:Runner
//src/java_tools/junitrunner/javatests/...
- //src/java_tools/singlejar:SingleJar
//src/test/...
//src/tools/remote/...
//src/tools/starlark/...
diff --git a/src/BUILD b/src/BUILD
index 6c55a332769c54..57a7ac85db1881 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -433,7 +433,6 @@ filegroup(
"//src/java_tools/buildjar:srcs",
"//src/java_tools/import_deps_checker:srcs",
"//src/java_tools/junitrunner:srcs",
- "//src/java_tools/singlejar:srcs",
"//src/main/cpp:srcs",
"//src/main/res:srcs",
"//src/main/java/com/google/devtools/build/docgen:srcs",
@@ -569,7 +568,6 @@ genrule(
srcs = [
"//src/java_tools/buildjar:srcs",
"//src/java_tools/junitrunner:srcs",
- "//src/java_tools/singlejar:srcs",
"//src/tools/singlejar:embedded_java_tools",
"//third_party/checker_framework_dataflow:srcs",
"//third_party/checker_framework_javacutil:srcs",
diff --git a/src/java_tools/junitrunner/java/com/google/testing/coverage/BUILD b/src/java_tools/junitrunner/java/com/google/testing/coverage/BUILD
index 15a07c033d4fed..39bb35840e2589 100644
--- a/src/java_tools/junitrunner/java/com/google/testing/coverage/BUILD
+++ b/src/java_tools/junitrunner/java/com/google/testing/coverage/BUILD
@@ -54,14 +54,14 @@ genrule(
outs = ["JacocoCoverage_jarjar_deploy.jar"],
cmd = "\n".join([
"JARJAR=\"$$(mktemp -t bazel.XXXXXXXX)\"",
- "\"$(JAVA)\" -jar \"$(location //third_party/jarjar:jarjar_command_deploy.jar)\" process \"$(location :JacocoCoverage.jarjar)\" \"$(location :JacocoCoverage_deploy.jar)\" \"$${JARJAR}\"",
+ "\"$(location //src/tools/singlejar:singlejar_local)\" process \"$(location :JacocoCoverage.jarjar)\" \"$(location :JacocoCoverage_deploy.jar)\" \"$${JARJAR}\"",
"\"$(JAVA)\" -jar \"$(location //src/java_tools/singlejar:SingleJar_deploy.jar)\" --normalize --sources \"$${JARJAR}\" --output \"$@\"",
"rm -fr \"$${JARJAR}\"",
]),
tags = ["manual"],
toolchains = ["@bazel_tools//tools/jdk:current_host_java_runtime"],
tools = [
- "//src/java_tools/singlejar:SingleJar_deploy.jar",
+ "//src/tools/singlejar:singlejar_local",
"//third_party/jarjar:jarjar_command_deploy.jar",
"@bazel_tools//tools/jdk:current_host_java_runtime",
],
diff --git a/src/java_tools/singlejar/BUILD b/src/java_tools/singlejar/BUILD
deleted file mode 100644
index 4eeae8848632fe..00000000000000
--- a/src/java_tools/singlejar/BUILD
+++ /dev/null
@@ -1,51 +0,0 @@
-# Description:
-# SingleJar combines multiple zip files and additional files
-# into a single zip file.
-package(default_visibility = [
- "//scripts/bootstrap:__subpackages__",
- "//src/java_tools:__subpackages__",
-])
-
-filegroup(
- name = "srcs",
- srcs = glob(["*"]) + [
- "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:srcs",
- "//src/java_tools/singlejar/java/com/google/devtools/build/zip:srcs",
- "//src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar:srcs",
- "//src/java_tools/singlejar/javatests/com/google/devtools/build/zip:srcs",
- ],
- visibility = ["//src:__subpackages__"],
-)
-
-package_group(
- name = "singlejar_package_group",
- packages = ["//src/java_tools/singlejar/..."],
-)
-
-alias(
- name = "libSingleJar",
- actual = "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:libSingleJar",
- visibility = ["//visibility:public"],
-)
-
-alias(
- name = "SingleJar",
- actual = "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:bazel-singlejar",
- visibility = ["//visibility:public"],
-)
-
-alias(
- name = "SingleJar_deploy.jar",
- actual = "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:bazel-singlejar_deploy.jar",
- visibility = ["//visibility:public"],
-)
-
-alias(
- name = "bootstrap",
- actual = "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:bootstrap",
-)
-
-alias(
- name = "bootstrap_deploy.jar",
- actual = "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:bootstrap_deploy.jar",
-)
diff --git a/src/java_tools/singlejar/README b/src/java_tools/singlejar/README
deleted file mode 100644
index da92eb7a9bacfe..00000000000000
--- a/src/java_tools/singlejar/README
+++ /dev/null
@@ -1,2 +0,0 @@
-SingleJar is a tool used to combine multiple jar file into a single one. It is used by Bazel to
-build java binaries that are self-contained.
\ No newline at end of file
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/BUILD b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/BUILD
deleted file mode 100644
index b6349019423a3c..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/BUILD
+++ /dev/null
@@ -1,102 +0,0 @@
-load("@rules_java//java:defs.bzl", "java_binary", "java_library")
-load("//tools/build_rules:java_rules_skylark.bzl", "bootstrap_java_binary", "bootstrap_java_library")
-
-# Description:
-# SingleJar combines multiple zip files and additional files
-# into a single zip file.
-package(default_visibility = ["//src/java_tools/singlejar:singlejar_package_group"])
-
-filegroup(
- name = "srcs",
- srcs = glob(["*"]),
- visibility = ["//src:__subpackages__"],
-)
-
-# This is used as a library outside of Bazel.
-java_library(
- name = "libSingleJar",
- srcs = [
- "ConcatenateStrategy.java",
- "CopyEntryFilter.java",
- "DefaultJarEntryFilter.java",
- "JarUtils.java",
- "ZipCombiner.java",
- "ZipEntryFilter.java",
- ],
- visibility = [
- "//src/java_tools/singlejar:__pkg__",
- "//src/java_tools/singlejar:singlejar_package_group",
- "//src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar:__pkg__",
- "//src/test/java/com/google/devtools/build/android:__pkg__",
- "//src/tools/android/java/com/google/devtools/build/android:__pkg__",
- ],
- deps = [
- "//src/java_tools/singlejar/java/com/google/devtools/build/zip",
- "//third_party:jsr305",
- ],
-)
-
-java_library(
- name = "libSingleJarMain",
- srcs = glob(["**/*.java"]),
- # Avoid adding dependencies here - this is a very low-level library and we don't want to pull in
- # the world, even including commons.
- deps = [
- "//src/java_tools/singlejar/java/com/google/devtools/build/zip",
- "//src/main/java/com/google/devtools/build/lib/shell",
- "//src/main/protobuf:desugar_deps_java_proto",
- "//src/main/protobuf:worker_protocol_java_proto",
- "//third_party:jsr305",
- "//third_party/protobuf:protobuf_java",
- ],
-)
-
-java_binary(
- name = "bazel-singlejar",
- srcs = glob(["*.java"]),
- main_class = "com.google.devtools.build.singlejar.SingleJar",
- visibility = [
- "//:__subpackages__",
- "//src/java_tools/singlejar:singlejar_package_group",
- ],
- deps = [
- "//src/java_tools/singlejar/java/com/google/devtools/build/zip",
- "//src/main/java/com/google/devtools/build/lib/shell",
- "//src/main/protobuf:desugar_deps_java_proto",
- "//src/main/protobuf:worker_protocol_java_proto",
- "//third_party:jsr305",
- "//third_party/protobuf:protobuf_java",
- ],
-)
-
-#
-# Bootstrapping using Starlark rules
-#
-
-bootstrap_java_library(
- name = "starlark-deps",
- jars = [
- "//third_party:jsr305-jars",
- ],
- tags = ["manual"],
-)
-
-bootstrap_java_binary(
- name = "bootstrap",
- srcs = glob(
- ["**/*.java"],
- exclude = [
- "Java8DesugarDepsJarEntryFilter.java",
- "SingleJarWorker.java",
- ],
- ) + [
- "//src/java_tools/singlejar/java/com/google/devtools/build/zip:java-srcs",
- ],
- main_class = "com.google.devtools.build.singlejar.SingleJar",
- tags = ["manual"],
- visibility = ["//visibility:public"],
- deps = [
- ":starlark-deps",
- "//src/main/java/com/google/devtools/build/lib/shell:shell-starlark",
- ],
-)
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ConcatenateStrategy.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ConcatenateStrategy.java
deleted file mode 100644
index 496c8eb7653b9d..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ConcatenateStrategy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import com.google.devtools.build.singlejar.ZipEntryFilter.CustomMergeStrategy;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import javax.annotation.concurrent.NotThreadSafe;
-
-/**
- * A strategy that merges a set of files by concatenating them. This is used
- * for services files. By default, this class automatically adds a newline
- * character {@code '\n'} between files if the previous file did not end with one.
- *
- *
Note: automatically inserting newline characters differs from the
- * original behavior. Use {@link #ConcatenateStrategy(boolean)} to turn this
- * behavior off.
- */
-@NotThreadSafe
-public final class ConcatenateStrategy implements CustomMergeStrategy {
-
- // The strategy assumes that files are generally small. This is a first guess
- // about the size of the files.
- private static final int BUFFER_SIZE = 4096;
-
- private final byte[] buffer = new byte[BUFFER_SIZE];
- private byte lastByteCopied = '\n';
- private final boolean appendNewLine;
-
- public ConcatenateStrategy() {
- this(true);
- }
-
- /**
- * @param appendNewLine Whether to add a newline character between files if
- * the previous file did not end with one.
- */
- public ConcatenateStrategy(boolean appendNewLine) {
- this.appendNewLine = appendNewLine;
- }
-
- @Override
- public void merge(InputStream in, OutputStream out) throws IOException {
- if (appendNewLine && lastByteCopied != '\n') {
- out.write('\n');
- lastByteCopied = '\n';
- }
- int bytesRead;
- while ((bytesRead = in.read(buffer)) != -1) {
- out.write(buffer, 0, bytesRead);
- lastByteCopied = buffer[bytesRead - 1];
- }
- }
-
- @Override
- public void finish(OutputStream out) {
- // No need to do anything. All the data was already written.
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/CopyEntryFilter.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/CopyEntryFilter.java
deleted file mode 100644
index 8f94706d915ada..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/CopyEntryFilter.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import java.io.IOException;
-
-import javax.annotation.concurrent.Immutable;
-
-/**
- * A filter which invokes {@link StrategyCallback#copy} for every entry. As a
- * result, the first entry for every given name is copied and further entries
- * with the same name are skipped.
- */
-@Immutable
-public final class CopyEntryFilter implements ZipEntryFilter {
-
- @Override
- public void accept(String filename, StrategyCallback callback) throws IOException {
- callback.copy(null);
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/DefaultJarEntryFilter.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/DefaultJarEntryFilter.java
deleted file mode 100644
index 4a4902f9360e39..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/DefaultJarEntryFilter.java
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import java.io.IOException;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.jar.JarFile;
-import javax.annotation.concurrent.Immutable;
-
-/**
- * A default filter for JAR files. It merges all services files in the {@code META-INF/services/}
- * directory. The original {@code MANIFEST} files are skipped, as are JAR signing files. Anything
- * not in the supplied path filter, an arbitrary predicate, is also skipped. To use this filter
- * properly, a new {@code MANIFEST} file should be explicitly added to the combined ZIP file.
- */
-@Immutable
-public class DefaultJarEntryFilter implements ZipEntryFilter {
-
- /** An interface to restrict which files are copied over and which are not. */
- public static interface PathFilter {
- /**
- * Returns true if an entry with the given name may be copied over.
- */
- boolean allowed(String path);
- }
-
- /** A filter that allows any path. */
- public static final PathFilter ANY_PATH = new PathFilter() {
- @Override
- public boolean allowed(String path) {
- return true;
- }
- };
-
- // ZIP timestamps have a resolution of 2 seconds, so this is the next timestamp after 1/1/1980.
- // This is only Visible for testing.
- static final Date DOS_EPOCH_PLUS_2_SECONDS =
- new GregorianCalendar(1980, 0, 1, 0, 0, 2).getTime();
-
- // Merge all files with a name in here:
- private static final String SERVICES_DIR = "META-INF/services/";
-
- // Merge all spring.handlers files.
- private static final String SPRING_HANDLERS = "META-INF/spring.handlers";
-
- // Merge all spring.schemas files.
- private static final String SPRING_SCHEMAS = "META-INF/spring.schemas";
-
- // Ignore all files with this name:
- private static final String MANIFEST_NAME = JarFile.MANIFEST_NAME;
-
- // Merge all protobuf extension registries.
- private static final String PROTOBUF_META = "protobuf.meta";
-
- // Merge all reference config files.
- private static final String REFERENCE_CONF = "reference.conf";
-
- protected final Date date;
- protected final Date classDate;
- protected PathFilter allowedPaths;
-
- public DefaultJarEntryFilter(boolean normalize, PathFilter allowedPaths) {
- this.date = normalize ? ZipCombiner.DOS_EPOCH : null;
- this.classDate = normalize ? DOS_EPOCH_PLUS_2_SECONDS : null;
- this.allowedPaths = allowedPaths;
- }
-
- public DefaultJarEntryFilter(boolean normalize) {
- this(normalize, ANY_PATH);
- }
-
- public DefaultJarEntryFilter() {
- this(true);
- }
-
- @Override
- public void accept(String filename, StrategyCallback callback) throws IOException {
- if (!allowedPaths.allowed(filename)) {
- callback.skip();
- } else if (filename.equals(SPRING_HANDLERS)) {
- callback.customMerge(date, new ConcatenateStrategy());
- } else if (filename.equals(SPRING_SCHEMAS)) {
- callback.customMerge(date, new ConcatenateStrategy());
- } else if (filename.equals(REFERENCE_CONF)) {
- callback.customMerge(date, new ConcatenateStrategy());
- } else if (filename.startsWith(SERVICES_DIR)) {
- // Merge all services files.
- callback.customMerge(date, new ConcatenateStrategy());
- } else if (filename.equals(MANIFEST_NAME) || filename.endsWith(".SF")
- || filename.endsWith(".DSA") || filename.endsWith(".RSA")) {
- // Ignore existing manifests and any .SF, .DSA or .RSA jar signing files.
- // TODO(bazel-team): I think we should be stricter and only skip signing
- // files from the META-INF/ directory.
- callback.skip();
- } else if (filename.endsWith(".class")) {
- // Copy .class files over, but 2 seconds ahead of the dos epoch. If it finds both source and
- // class files on the classpath, javac prefers the source file, if the class file is not newer
- // than the source file. Since we normalize the timestamps, we need to provide timestamps for
- // class files that are newer than those for the corresponding source files.
- callback.copy(classDate);
- } else if (filename.equals(PROTOBUF_META)) {
- // Merge all protobuf meta data without inserting newlines,
- // since the file is in protobuf binary format.
- callback.customMerge(date, new ConcatenateStrategy(false));
- } else {
- // Copy all other files over.
- callback.copy(date);
- }
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/JarUtils.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/JarUtils.java
deleted file mode 100644
index a3fac8e8f681e8..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/JarUtils.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import com.google.devtools.build.zip.ExtraData;
-
-import java.io.IOException;
-import java.util.Date;
-
-/**
- * Provides utilities for using ZipCombiner to pack up Jar files.
- */
-public final class JarUtils {
- private static final String MANIFEST_DIRECTORY = "META-INF/";
- private static final short MAGIC_JAR_ID = (short) 0xCAFE;
- private static final ExtraData[] MAGIC_JAR_ID_EXTRA_ENTRIES =
- new ExtraData[] { new ExtraData(MAGIC_JAR_ID, new byte[0]) };
-
- /**
- * Adds META-INF directory through ZipCombiner with the given date and the
- * magic jar ID.
- *
- * @throws IOException if {@link ZipCombiner#addDirectory(String, Date, ExtraData[])}
- * throws an IOException.
- */
- public static void addMetaInf(ZipCombiner combiner, Date date) throws IOException {
- combiner.addDirectory(MANIFEST_DIRECTORY, date, MAGIC_JAR_ID_EXTRA_ENTRIES);
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/Java8DesugarDepsJarEntryFilter.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/Java8DesugarDepsJarEntryFilter.java
deleted file mode 100644
index 93c6cc768e0d28..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/Java8DesugarDepsJarEntryFilter.java
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2018 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import com.google.devtools.build.android.desugar.proto.DesugarDeps.Dependency;
-import com.google.devtools.build.android.desugar.proto.DesugarDeps.DesugarDepsInfo;
-import com.google.devtools.build.android.desugar.proto.DesugarDeps.InterfaceDetails;
-import com.google.devtools.build.android.desugar.proto.DesugarDeps.InterfaceWithCompanion;
-import com.google.devtools.build.android.desugar.proto.DesugarDeps.Type;
-import com.google.protobuf.ByteString;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * {@link ZipEntryFilter} that implements consistency checking of {@code META-INF/desugar_deps}
- * files emitted by {@link com.google.devtools.build.android.desugar.Desugar}. This is used to
- * implement singlejar's {@code --check_desugar_deps} flag.
- */
-class Java8DesugarDepsJarEntryFilter
- implements ZipEntryFilter, ZipEntryFilter.CustomMergeStrategy {
-
- private final Map neededDeps = new LinkedHashMap<>();
- private final Map missingInterfaces = new LinkedHashMap<>();
- private final Map> extendedInterfaces = new HashMap<>();
- private final Map hasDefaultMethods = new HashMap<>();
- private final Set seen = new HashSet<>();
-
- private final ZipEntryFilter delegate;
-
- public Java8DesugarDepsJarEntryFilter(ZipEntryFilter delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void accept(String filename, StrategyCallback callback) throws IOException {
- if ("META-INF/desugar_deps".equals(filename)) {
- callback.customMerge(null, this);
- } else if (filename.startsWith("j$/")) {
- throw new IOException("Unexpectedly found desugar_jdk_libs file: " + filename);
- } else {
- seen.add(filename);
- delegate.accept(filename, callback);
- }
- }
-
- @Override
- public void merge(InputStream in, OutputStream out) throws IOException {
- DesugarDepsInfo depsInfo = DesugarDepsInfo.parseFrom(in);
- for (Dependency assumed : depsInfo.getAssumePresentList()) {
- neededDeps.putIfAbsent(
- assumed.getTarget().getBinaryName() + ".class",
- assumed.getOrigin().getBinaryNameBytes());
- }
- for (Dependency missing : depsInfo.getMissingInterfaceList()) {
- missingInterfaces.putIfAbsent(
- missing.getTarget().getBinaryName(),
- missing.getOrigin().getBinaryNameBytes());
- }
- for (InterfaceDetails itf : depsInfo.getInterfaceWithSupertypesList()) {
- if (itf.getExtendedInterfaceCount() > 0
- && !extendedInterfaces.containsKey(itf.getOrigin().getBinaryName())) {
- // Avoid Guava dependency
- ArrayList supertypes = new ArrayList<>(itf.getExtendedInterfaceCount());
- for (Type extended : itf.getExtendedInterfaceList()) {
- supertypes.add(extended.getBinaryName());
- }
- extendedInterfaces.putIfAbsent(itf.getOrigin().getBinaryName(), supertypes);
- }
- }
- for (InterfaceWithCompanion companion : depsInfo.getInterfaceWithCompanionList()) {
- if (companion.getNumDefaultMethods() > 0) {
- // Only remember interfaces that definitely have default methods for now.
- // For all other interfaces we'll transitively check extended interfaces
- // in HasDefaultMethods.
- hasDefaultMethods.putIfAbsent(companion.getOrigin().getBinaryName(), true);
- }
- }
- // Don't write anything to out, we just want to check these files for consistency
- }
-
- @Override
- public void finish(OutputStream out) throws IOException {
- for (Map.Entry need : neededDeps.entrySet()) {
- if (!seen.contains(need.getKey())) {
- throw new IOException(need.getKey() + " referenced by " + need.getValue().toStringUtf8()
- + " but not found. Is the former defined in a neverlink library?");
- }
- }
-
- for (Map.Entry missing : missingInterfaces.entrySet()) {
- if (hasDefaultMethods(missing.getKey())) {
- throw new IOException(missing.getKey()
- + " needed to desugar "
- + missing.getValue().toStringUtf8()
- + ". Please add a dependency to the former to the library containing the latter.");
- }
- }
- // Don't write anything to out, we just want to check these files for consistency
- }
-
- @Override
- public boolean skipEmpty() {
- return true; // We never want to write these files into the output Jar
- }
-
- private boolean hasDefaultMethods(String itf) {
- Boolean cached = hasDefaultMethods.putIfAbsent(itf, false);
- if (cached != null) {
- return cached; // Already in the map
- }
-
- List extended = extendedInterfaces.get(itf);
- if (extended != null) {
- for (String supertype : extended) {
- if (hasDefaultMethods(supertype)) {
- hasDefaultMethods.put(itf, true);
- return true;
- }
- }
- }
- // We primed with false above in case of cycles so just return that
- return false;
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/JavaIoFileSystem.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/JavaIoFileSystem.java
deleted file mode 100644
index 878accd58869c7..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/JavaIoFileSystem.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * An implementation based on java.io.
- */
-public final class JavaIoFileSystem implements SimpleFileSystem {
-
- @Override
- public InputStream getInputStream(String filename) throws IOException {
- return new FileInputStream(filename);
- }
-
- @Override
- public OutputStream getOutputStream(String filename) throws IOException {
- return new FileOutputStream(filename);
- }
-
- @Override
- public File getFile(String filename) throws IOException {
- return new File(filename);
- }
-
- @Override
- public boolean delete(String filename) {
- return new File(filename).delete();
- }
-}
\ No newline at end of file
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/OptionFileExpander.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/OptionFileExpander.java
deleted file mode 100644
index aa396b5973e19d..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/OptionFileExpander.java
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-
-import com.google.devtools.build.lib.shell.ShellUtils;
-import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-import javax.annotation.concurrent.Immutable;
-
-/**
- * A utility class to parse option files and expand them.
- */
-@Immutable
-final class OptionFileExpander {
-
- /**
- * An interface that allows injecting different implementations for reading
- * files. This is mostly used for testing.
- */
- interface OptionFileProvider {
-
- /**
- * Opens a file for reading and returns an input stream.
- */
- InputStream getInputStream(String filename) throws IOException;
- }
-
- private final OptionFileProvider fileSystem;
-
- /**
- * Creates an instance with the given option file provider.
- */
- public OptionFileExpander(OptionFileProvider fileSystem) {
- this.fileSystem = fileSystem;
- }
-
- /**
- * Pre-processes an argument list, expanding options of the form &at;filename
- * to read in the content of the file and add it to the list of arguments.
- *
- * @param args the List of arguments to pre-process.
- * @return the List of pre-processed arguments.
- * @throws IOException if one of the files containing options cannot be read.
- */
- public List expandArguments(List args) throws IOException {
- List expanded = new ArrayList<>(args.size());
- for (String arg : args) {
- expandArgument(arg, expanded);
- }
- return expanded;
- }
-
- /**
- * Expands a single argument, expanding options &at;filename to read in
- * the content of the file and add it to the list of processed arguments.
- *
- * @param arg the argument to pre-process.
- * @param expanded the List of pre-processed arguments.
- * @throws IOException if one of the files containing options cannot be read.
- */
- private void expandArgument(String arg, List expanded) throws IOException {
- if (arg.startsWith("@")) {
- try (InputStreamReader reader =
- new InputStreamReader(fileSystem.getInputStream(arg.substring(1)), ISO_8859_1)) {
- // TODO(bazel-team): This code doesn't handle escaped newlines correctly.
- // ShellUtils doesn't support them either.
- for (String line : readAllLines(reader)) {
- List parsedTokens = new ArrayList<>();
- try {
- ShellUtils.tokenize(parsedTokens, line);
- } catch (TokenizationException e) {
- throw new IOException("Could not tokenize parameter file!", e);
- }
- for (String token : parsedTokens) {
- expandArgument(token, expanded);
- }
- }
- }
- } else {
- expanded.add(arg);
- }
- }
-
- private List readAllLines(Reader in) throws IOException {
- List result = new ArrayList<>();
- BufferedReader reader = new BufferedReader(in);
- String line;
- while ((line = reader.readLine()) != null) {
- result.add(line);
- }
- return result;
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/PrefixListPathFilter.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/PrefixListPathFilter.java
deleted file mode 100644
index 7a3d6617ac2f4f..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/PrefixListPathFilter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import com.google.devtools.build.singlejar.DefaultJarEntryFilter.PathFilter;
-
-import java.util.List;
-
-/**
- * A predicate used to filter jar entries according to a list of path prefixes.
- */
-final class PrefixListPathFilter implements PathFilter {
- private final List prefixes;
-
- public PrefixListPathFilter(List prefixes) {
- this.prefixes = prefixes;
- }
-
- @Override
- public boolean allowed(String path) {
- for (String prefix : prefixes) {
- if (path.startsWith(prefix)) {
- return true;
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SimpleFileSystem.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SimpleFileSystem.java
deleted file mode 100644
index 300b4f5e1baa20..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SimpleFileSystem.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import com.google.devtools.build.singlejar.OptionFileExpander.OptionFileProvider;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * A simple virtual file system interface. It's much simpler than the Blaze
- * virtual file system and only to be used inside this package.
- */
-public interface SimpleFileSystem extends OptionFileProvider {
-
- @Override
- InputStream getInputStream(String filename) throws IOException;
-
- /**
- * Opens a file for output and returns an output stream. If a file of that
- * name already exists, it is overwritten.
- */
- OutputStream getOutputStream(String filename) throws IOException;
-
- /**
- * Returns the File object for this filename.
- */
- File getFile(String filename) throws IOException;
-
- /** Delete the file with the given name and return whether deleting it was successful. */
- boolean delete(String filename);
-}
\ No newline at end of file
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJar.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJar.java
deleted file mode 100644
index a9da39e3519bd3..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJar.java
+++ /dev/null
@@ -1,469 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.devtools.build.singlejar.ZipCombiner.DOS_EPOCH;
-
-import com.google.devtools.build.singlejar.DefaultJarEntryFilter.PathFilter;
-import com.google.devtools.build.singlejar.ZipCombiner.OutputMode;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Properties;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import javax.annotation.concurrent.NotThreadSafe;
-
-/**
- * An application that emulates the existing SingleJar tool, using the {@link
- * ZipCombiner} class.
- */
-@NotThreadSafe
-public class SingleJar {
-
- private static final byte NEWLINE_BYTE = (byte) '\n';
- private static final String MANIFEST_FILENAME = JarFile.MANIFEST_NAME;
- private static final String BUILD_DATA_FILENAME = "build-data.properties";
-
- private final SimpleFileSystem fileSystem;
-
- /** The input jar files we want to combine into the output jar. */
- private final List inputJars = new ArrayList<>();
-
- /** Additional resources to be added to the output jar. */
- private final List resources = new ArrayList<>();
-
- /** Additional class path resources to be added to the output jar. */
- private final List classpathResources = new ArrayList<>();
-
- /** The name of the output Jar file. */
- private String outputJar;
-
- /** A filter for what jar entries to include */
- private PathFilter allowedPaths = DefaultJarEntryFilter.ANY_PATH;
-
- /** Extra manifest contents. */
- private String extraManifestContent;
- /** The main class - this is put into the manifest and also into the build info. */
- private String mainClass;
-
- /**
- * Warn about duplicate resource files, and skip them. Default behavior is to
- * give an error message.
- */
- private boolean warnDuplicateFiles = false;
-
- /** Indicates whether to set all timestamps to a fixed value. */
- private boolean normalize = false;
- private boolean checkDesugarDeps = false;
- private OutputMode outputMode = OutputMode.FORCE_STORED;
-
- /** Whether to include build-data.properties file */
- protected boolean includeBuildData = true;
-
- /** List of build information properties files */
- protected List buildInformationFiles = new ArrayList<>();
-
- /** Extraneous build informations (key=value) */
- protected List buildInformations = new ArrayList<>();
-
- /** The (optional) native executable that will be prepended to this JAR. */
- private String launcherBin = null;
-
- // Only visible for testing.
- protected SingleJar(SimpleFileSystem fileSystem) {
- this.fileSystem = fileSystem;
- }
-
- /**
- * Creates a manifest and returns an input stream for its contents.
- */
- private InputStream createManifest() throws IOException {
- Manifest manifest = new Manifest();
- Attributes attributes = manifest.getMainAttributes();
- attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
- attributes.put(new Attributes.Name("Created-By"), "blaze-singlejar");
- if (mainClass != null) {
- attributes.put(Attributes.Name.MAIN_CLASS, mainClass);
- }
- if (extraManifestContent != null) {
- ByteArrayInputStream in = new ByteArrayInputStream(extraManifestContent.getBytes("UTF8"));
- manifest.read(in);
- }
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- manifest.write(out);
- return new ByteArrayInputStream(out.toByteArray());
- }
-
- private InputStream createBuildData() throws IOException {
- Properties properties = mergeBuildData();
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- properties.store(outputStream, null);
- byte[] output = outputStream.toByteArray();
- // Properties#store() adds a timestamp comment as first line, delete it.
- output = stripFirstLine(output);
- return new ByteArrayInputStream(output);
- }
-
- static byte[] stripFirstLine(byte[] output) {
- int i = 0;
- while (i < output.length && output[i] != NEWLINE_BYTE) {
- i++;
- }
- if (i < output.length) {
- output = Arrays.copyOfRange(output, i + 1, output.length);
- } else {
- output = new byte[0];
- }
- return output;
- }
-
- private Properties mergeBuildData() throws IOException {
- Properties properties = new Properties();
- for (String fileName : buildInformationFiles) {
- InputStream file = fileSystem.getInputStream(fileName);
- if (file != null) {
- properties.load(file);
- }
- }
-
- // extra properties
- for (String info : buildInformations) {
- String[] split = info.split("=", 2);
- String key = split[0];
- String value = "";
- if (split.length > 1) {
- value = split[1];
- }
- properties.put(key, value);
- }
-
- // finally add generic information
- // TODO(b/28294322): do we need to resolve the path to be absolute or canonical?
- properties.put("build.target", outputJar);
- if (mainClass != null) {
- properties.put("main.class", mainClass);
- }
- return properties;
- }
-
- private String getName(String filename) {
- int index = filename.lastIndexOf('/');
- return index < 0 ? filename : filename.substring(index + 1);
- }
-
- // Only visible for testing.
- protected int run(List args) throws IOException {
- List expandedArgs = new OptionFileExpander(fileSystem).expandArguments(args);
- processCommandlineArgs(expandedArgs);
- InputStream buildInfo = createBuildData();
-
- ZipCombiner combiner = null;
- try (OutputStream out = fileSystem.getOutputStream(outputJar)) {
- combiner = new ZipCombiner(outputMode, createEntryFilterHelper(), out);
- if (launcherBin != null) {
- combiner.prependExecutable(fileSystem.getInputStream(launcherBin));
- }
- Date date = normalize ? ZipCombiner.DOS_EPOCH : null;
-
- // Add a manifest file.
- JarUtils.addMetaInf(combiner, date);
- combiner.addFile(MANIFEST_FILENAME, date, createManifest());
-
- if (includeBuildData) {
- // Add the build data file.
- combiner.addFile(BUILD_DATA_FILENAME, date, buildInfo);
- }
-
- // Copy the resources to the top level of the jar file.
- for (String classpathResource : classpathResources) {
- String entryName = getName(classpathResource);
- if (warnDuplicateFiles && combiner.containsFile(entryName)) {
- System.err.println("File " + entryName + " clashes with a previous file");
- continue;
- }
- combiner.addFile(entryName, date, fileSystem.getInputStream(classpathResource));
- }
-
- // Copy the resources into the jar file.
- for (String resource : resources) {
- String from;
- String to;
- int i = resource.indexOf(':');
- if (i < 0) {
- to = from = resource;
- } else {
- from = resource.substring(0, i);
- to = resource.substring(i + 1);
- }
- if (warnDuplicateFiles && combiner.containsFile(to)) {
- System.err.println("File " + from + " at " + to + " clashes with a previous file");
- continue;
- }
-
- // Add parent directory entries.
- int idx = to.indexOf('/');
- while (idx != -1) {
- String dir = to.substring(0, idx + 1);
- if (!combiner.containsFile(dir)) {
- combiner.addDirectory(dir, DOS_EPOCH);
- }
- idx = to.indexOf('/', idx + 1);
- }
-
- combiner.addFile(to, date, fileSystem.getInputStream(from));
- }
-
- // Copy the jars into the jar file.
- for (String inputJar : inputJars) {
- File jar = fileSystem.getFile(inputJar);
- combiner.addZip(jar);
- }
-
- // Close the output file. If something goes wrong here, delete the file.
- combiner.close();
- combiner = null;
- } finally {
- // This part is only executed if an exception occurred.
- if (combiner != null) {
- try {
- // We may end up calling close twice, but that's ok.
- combiner.close();
- } catch (IOException e) {
- // There's already an exception in progress - this won't add any
- // additional information.
- }
- // Ignore return value - there's already an exception in progress.
- fileSystem.delete(outputJar);
- }
- }
- return 0;
- }
-
- private ZipEntryFilter createEntryFilterHelper() {
- ZipEntryFilter result = createEntryFilter(normalize, allowedPaths);
- if (checkDesugarDeps) {
- // Invocation is done through reflection so that this code will work in bazel open source
- // as well. SingleJar is used for bootstrap and thus can not depend on protos (used in
- // Java8DesugarDepsJarEntryFilter).
- try {
- return (ZipEntryFilter)
- Class.forName("com.google.devtools.build.singlejar.Java8DesugarDepsJarEntryFilter")
- .getConstructor(ZipEntryFilter.class).newInstance(result);
- } catch (ReflectiveOperationException e) {
- throw new IllegalStateException("Couldn't instantiate desugar deps checker", e);
- }
- } else {
- return (filename, callback) -> {
- if ("META-INF/desugar_deps".equals(filename)) {
- callback.skip(); // We never want these files in the output
- } else {
- result.accept(filename, callback);
- }
- };
- }
-
- }
-
- protected ZipEntryFilter createEntryFilter(boolean normalize, PathFilter allowedPaths) {
- return new DefaultJarEntryFilter(normalize, allowedPaths);
- }
-
- /**
- * Collects the arguments for a command line flag until it finds a flag that
- * starts with the terminatorPrefix.
- *
- * @param args
- * @param startIndex the start index in the args to collect the flag arguments
- * from
- * @param flagArguments the collected flag arguments
- * @param terminatorPrefix the terminator prefix to stop collecting of
- * argument flags
- * @return the index of the first argument that started with the
- * terminatorPrefix
- */
- private static int collectFlagArguments(List args, int startIndex,
- List flagArguments, String terminatorPrefix) {
- startIndex++;
- while (startIndex < args.size()) {
- String name = args.get(startIndex);
- if (name.startsWith(terminatorPrefix)) {
- return startIndex - 1;
- }
- flagArguments.add(name);
- startIndex++;
- }
- return startIndex;
- }
-
- /**
- * Returns a single argument for a command line option.
- *
- * @throws IOException if no more arguments are available
- */
- private static String getArgument(List args, int i, String arg) throws IOException {
- if (i + 1 < args.size()) {
- return args.get(i + 1);
- }
- throw new IOException(arg + ": missing argument");
- }
-
- /**
- * Processes the command line arguments.
- *
- * @throws IOException if one of the files containing options cannot be read
- */
- protected void processCommandlineArgs(List args) throws IOException {
- List manifestLines = new ArrayList<>();
- List prefixes = new ArrayList<>();
- for (int i = 0; i < args.size(); i++) {
- String arg = args.get(i);
- if (arg.equals("--sources")) {
- i = collectFlagArguments(args, i, inputJars, "--");
- } else if (arg.equals("--resources")) {
- i = collectFlagArguments(args, i, resources, "--");
- } else if (arg.equals("--classpath_resources")) {
- i = collectFlagArguments(args, i, classpathResources, "--");
- } else if (arg.equals("--deploy_manifest_lines")) {
- i = collectFlagArguments(args, i, manifestLines, "--");
- } else if (arg.equals("--build_info_file")) {
- buildInformationFiles.add(getArgument(args, i, arg));
- i++;
- } else if (arg.equals("--extra_build_info")) {
- buildInformations.add(getArgument(args, i, arg));
- i++;
- } else if (arg.equals("--main_class")) {
- mainClass = getArgument(args, i, arg);
- i++;
- } else if (arg.equals("--output")) {
- outputJar = getArgument(args, i, arg);
- i++;
- } else if (arg.equals("--compression")) {
- outputMode = OutputMode.FORCE_DEFLATE;
- } else if (arg.equals("--dont_change_compression")) {
- outputMode = OutputMode.DONT_CARE;
- } else if (arg.equals("--normalize")) {
- normalize = true;
- } else if (arg.equals("--include_prefixes")) {
- i = collectFlagArguments(args, i, prefixes, "--");
- } else if (arg.equals("--exclude_build_data")) {
- includeBuildData = false;
- } else if (arg.equals("--warn_duplicate_resources")) {
- warnDuplicateFiles = true;
- } else if (arg.equals("--java_launcher")) {
- launcherBin = getArgument(args, i, arg);
- i++;
- } else if (arg.equals("--check_desugar_deps")) {
- checkDesugarDeps = true;
- } else {
- throw new IOException("unknown option : '" + arg + "'");
- }
- }
- if (!manifestLines.isEmpty()) {
- setExtraManifestContent(joinWithNewlines(manifestLines));
- }
- if (!prefixes.isEmpty()) {
- setPathPrefixes(prefixes);
- }
- }
-
- private String joinWithNewlines(Iterable lines) {
- StringBuilder result = new StringBuilder();
- Iterator it = lines.iterator();
- if (it.hasNext()) {
- result.append(it.next());
- }
- while (it.hasNext()) {
- result.append('\n');
- result.append(it.next());
- }
- return result.toString();
- }
-
- private void setExtraManifestContent(String extraManifestContent) {
- // The manifest content has to be terminated with a newline character
- if (!extraManifestContent.endsWith("\n")) {
- extraManifestContent = extraManifestContent + '\n';
- }
- this.extraManifestContent = extraManifestContent;
- }
-
- private void setPathPrefixes(List prefixes) throws IOException {
- if (prefixes.isEmpty()) {
- throw new IOException(
- "Empty set of path prefixes; cowardly refusing to emit an empty jar file");
- }
- allowedPaths = new PrefixListPathFilter(prefixes);
- }
-
- static int singleRun(String[] args) throws IOException {
- SingleJar singlejar = new SingleJar(new JavaIoFileSystem());
- return singlejar.run(Arrays.asList(args));
- }
-
- public static void main(String[] args) {
- if (shouldRunInWorker(args)) {
- if (!canRunInWorker()) {
- System.err.println("Asked to run in a worker, but no worker support");
- System.exit(1);
- }
- try {
- runWorker(args);
- } catch (Exception e) {
- System.err.println("Error running worker : " + e.getMessage());
- System.exit(1);
- }
- return;
- }
-
- try {
- System.exit(singleRun(args));
- } catch (IOException e) {
- System.err.println("SingleJar threw exception : " + e.getMessage());
- System.exit(1);
- }
- }
-
- private static void runWorker(String[] args) throws Exception {
- // Invocation is done through reflection so that this code will work in bazel open source
- // as well. SingleJar is used for bootstrap and thus can not depend on protos (used in
- // SingleJarWorker).
- Class> workerClass = Class.forName("com.google.devtools.build.singlejar.SingleJarWorker");
- workerClass.getMethod("main", String[].class).invoke(null, (Object) args);
- }
-
- protected static boolean shouldRunInWorker(String[] args) {
- return Arrays.asList(args).contains("--persistent_worker");
- }
-
- private static boolean canRunInWorker() {
- try {
- Class.forName("com.google.devtools.build.singlejar.SingleJarWorker");
- return true;
- } catch (ClassNotFoundException e1) {
- return false;
- }
- }
-
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJarWorker.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJarWorker.java
deleted file mode 100644
index 95554a8679c30a..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/SingleJarWorker.java
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2016 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest;
-import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-
-/**
- * A blaze worker to run {@link SingleJar} in a warm JVM process.
- */
-public class SingleJarWorker {
-
- public static void main(String[] args) {
- new SingleJarWorker().runWorker();
- }
-
- private PrintStream originalStdout;
- private PrintStream originalSterr;
- private ByteArrayOutputStream stdoutAndStderr;
-
- protected void runWorker() {
- trapOutputs();
-
- try {
- dispatchWorkRequestsForever();
- } catch (IOException e) {
- // IOException will only occur if System.in has been closed
- // In that case we silently exit our process
- }
- }
-
- private void trapOutputs() {
- originalStdout = System.out;
- originalSterr = System.err;
- stdoutAndStderr = new ByteArrayOutputStream();
- System.setErr(new PrintStream(stdoutAndStderr, true));
- System.setOut(new PrintStream(stdoutAndStderr, true));
- }
-
- private void dispatchWorkRequestsForever() throws IOException {
- while (true) {
- WorkRequest workRequest = WorkRequest.parseDelimitedFrom(System.in);
-
- String[] args = workRequest.getArgumentsList().toArray(new String[0]);
-
- int returnCode = runSingleJar(args);
-
- outputResult(returnCode);
- }
- }
-
- private void outputResult(int returnCode) throws IOException {
- WorkResponse.newBuilder()
- .setExitCode(returnCode)
- .setOutput(new String(stdoutAndStderr.toByteArray(), StandardCharsets.UTF_8))
- .build()
- .writeDelimitedTo(originalStdout);
-
- // Reset output streams, we are not simply calling reset on the BAOS since this will
- // still keep the full buffer allocated.
- stdoutAndStderr = new ByteArrayOutputStream();
- System.setErr(new PrintStream(stdoutAndStderr, true));
- System.setOut(new PrintStream(stdoutAndStderr, true));
- }
-
- private int runSingleJar(String[] args) {
- try {
- return singleRun(args);
- } catch (IOException e) {
- // Some IO failures are okay no need to quit the worker
- System.err.println("SingleJar threw exception : " + e.getMessage());
- return 1;
- } catch (Exception e) {
- // We had an actual unexpected error, lets quit the worker
- originalSterr.println("SingleJar threw an unexpected exception : " + e.getMessage());
- e.printStackTrace(originalSterr);
- System.exit(1);
- return 1;
- }
- }
-
- protected int singleRun(String[] args) throws Exception {
- return SingleJar.singleRun(args);
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ZipCombiner.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ZipCombiner.java
deleted file mode 100644
index 44d4f0262b69e5..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ZipCombiner.java
+++ /dev/null
@@ -1,636 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.devtools.build.singlejar.ZipEntryFilter.CustomMergeStrategy;
-import com.google.devtools.build.singlejar.ZipEntryFilter.StrategyCallback;
-import com.google.devtools.build.zip.ExtraData;
-import com.google.devtools.build.zip.ExtraDataList;
-import com.google.devtools.build.zip.ZipFileEntry;
-import com.google.devtools.build.zip.ZipFileEntry.Compression;
-import com.google.devtools.build.zip.ZipReader;
-import com.google.devtools.build.zip.ZipUtil;
-import com.google.devtools.build.zip.ZipWriter;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.zip.CRC32;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterInputStream;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-import javax.annotation.Nullable;
-
-/**
- * An object that combines multiple ZIP files into a single file. It only
- * supports a subset of the ZIP format, specifically:
- *
- * - It only supports STORE and DEFLATE storage methods.
- * - It only supports 32-bit ZIP files.
- *
- *
- * These restrictions are also present in the JDK implementations
- * {@link java.util.jar.JarInputStream}, {@link java.util.zip.ZipInputStream},
- * though they are not documented there.
- *
- *
IMPORTANT NOTE: Callers must call {@link #finish()} or {@link #close()}
- * at the end of processing to ensure that the output buffers are flushed and
- * the ZIP file is complete.
- *
- *
This class performs only rudimentary data checking. If the input files
- * are damaged, the output will likely also be damaged.
- *
- *
Also see:
- * ZIP format
- */
-public class ZipCombiner implements AutoCloseable {
- public static final Date DOS_EPOCH = new Date(ZipUtil.DOS_EPOCH);
- /**
- * Whether to compress or decompress entries.
- */
- public enum OutputMode {
-
- /**
- * Output entries using any method.
- */
- DONT_CARE,
-
- /**
- * Output all entries using DEFLATE method, except directory entries. It is always more
- * efficient to store directory entries uncompressed.
- */
- FORCE_DEFLATE,
-
- /**
- * Output all entries using STORED method.
- */
- FORCE_STORED,
- }
-
- /**
- * The type of action to take for a ZIP file entry.
- */
- private enum ActionType {
-
- /**
- * Skip the entry.
- */
- SKIP,
-
- /**
- * Copy the entry.
- */
- COPY,
-
- /**
- * Rename the entry.
- */
- RENAME,
-
- /**
- * Merge the entry.
- */
- MERGE;
- }
-
- /**
- * Encapsulates the action to take for a ZIP file entry along with optional details specific to
- * the action type. The minimum requirements per type are:
- *
- * - SKIP: none.
- * - COPY: none.
- * - RENAME: newName.
- * - MERGE: strategy, mergeBuffer.
- *
- *
- * An action can be easily changed from one type to another by using
- * {@link EntryAction#EntryAction(ActionType, EntryAction)}.
- */
- private static final class EntryAction {
- private final ActionType type;
- @Nullable private final Date date;
- @Nullable private final String newName;
- @Nullable private final CustomMergeStrategy strategy;
- @Nullable private final ByteArrayOutputStream mergeBuffer;
-
- /**
- * Create an action of the specified type with no extra details.
- */
- public EntryAction(ActionType type) {
- this(type, null, null, null, null);
- }
-
- /**
- * Create a duplicate action with a different {@link ActionType}.
- */
- public EntryAction(ActionType type, EntryAction action) {
- this(type, action.getDate(), action.getNewName(), action.getStrategy(),
- action.getMergeBuffer());
- }
-
- /**
- * Create an action of the specified type and details.
- *
- * @param type the type of action
- * @param date the custom date to set on the entry
- * @param newName the custom name to create the entry as
- * @param strategy the {@link CustomMergeStrategy} to use for merging this entry
- * @param mergeBuffer the output stream to use for merge results
- */
- public EntryAction(ActionType type, Date date, String newName, CustomMergeStrategy strategy,
- ByteArrayOutputStream mergeBuffer) {
- checkArgument(type != ActionType.RENAME || newName != null,
- "NewName must not be null if the ActionType is RENAME.");
- checkArgument(type != ActionType.MERGE || strategy != null,
- "Strategy must not be null if the ActionType is MERGE.");
- checkArgument(type != ActionType.MERGE || mergeBuffer != null,
- "MergeBuffer must not be null if the ActionType is MERGE.");
- this.type = type;
- this.date = date;
- this.newName = newName;
- this.strategy = strategy;
- this.mergeBuffer = mergeBuffer;
- }
-
- /** Returns the type. */
- public ActionType getType() {
- return type;
- }
-
- /** Returns the date. */
- public Date getDate() {
- return date;
- }
-
- /** Returns the new name. */
- public String getNewName() {
- return newName;
- }
-
- /** Returns the strategy. */
- public CustomMergeStrategy getStrategy() {
- return strategy;
- }
-
- /** Returns the mergeBuffer. */
- public ByteArrayOutputStream getMergeBuffer() {
- return mergeBuffer;
- }
- }
-
- private final class FilterCallback implements StrategyCallback {
- private String filename;
- private final AtomicBoolean called = new AtomicBoolean();
-
- public void resetForFile(String filename) {
- this.filename = filename;
- this.called.set(false);
- }
-
- @Override public void skip() throws IOException {
- checkCall();
- actions.put(filename, new EntryAction(ActionType.SKIP));
- }
-
- @Override public void copy(Date date) throws IOException {
- checkCall();
- actions.put(filename, new EntryAction(ActionType.COPY, date, null, null, null));
- }
-
- @Override public void rename(String newName, Date date) throws IOException {
- checkCall();
- actions.put(filename, new EntryAction(ActionType.RENAME, date, newName, null, null));
- }
-
- @Override public void customMerge(Date date, CustomMergeStrategy strategy) throws IOException {
- checkCall();
- actions.put(filename, new EntryAction(ActionType.MERGE, date, null, strategy,
- new ByteArrayOutputStream()));
- }
-
- private void checkCall() {
- checkState(called.compareAndSet(false, true), "The callback was already called once.");
- }
- }
-
- /** Returns a {@link Deflater} for performing ZIP compression. */
- private static Deflater getDeflater() {
- return new Deflater(Deflater.DEFAULT_COMPRESSION, true);
- }
-
- /** Returns a {@link Inflater} for performing ZIP decompression. */
- private static Inflater getInflater() {
- return new Inflater(true);
- }
-
- /** Copies all data from the input stream to the output stream. */
- private static long copyStream(InputStream from, OutputStream to) throws IOException {
- byte[] buf = new byte[0x1000];
- long total = 0;
- int r;
- while ((r = from.read(buf)) != -1) {
- to.write(buf, 0, r);
- total += r;
- }
- return total;
- }
-
- private final OutputMode mode;
- private final ZipEntryFilter entryFilter;
- private final FilterCallback callback;
- private final ZipWriter out;
-
- private final Map entries;
- private final Map actions;
-
- /**
- * Creates a {@link ZipCombiner} for combining ZIP files using the specified {@link OutputMode},
- * {@link ZipEntryFilter}, and destination {@link OutputStream}.
- *
- * @param mode the compression preference for the output ZIP file
- * @param entryFilter the filter to use when adding ZIP files to the combined output
- * @param out the {@link OutputStream} for writing the combined ZIP file
- */
- public ZipCombiner(OutputMode mode, ZipEntryFilter entryFilter, OutputStream out) {
- this.mode = mode;
- this.entryFilter = entryFilter;
- this.callback = new FilterCallback();
- this.out = new ZipWriter(new BufferedOutputStream(out), UTF_8);
- this.entries = new HashMap<>();
- this.actions = new HashMap<>();
- }
-
- /**
- * Creates a {@link ZipCombiner} for combining ZIP files using the specified
- * {@link ZipEntryFilter}, and destination {@link OutputStream}. Uses the DONT_CARE
- * {@link OutputMode}.
- *
- * @param entryFilter the filter to use when adding ZIP files to the combined output
- * @param out the {@link OutputStream} for writing the combined ZIP file
- */
- public ZipCombiner(ZipEntryFilter entryFilter, OutputStream out) {
- this(OutputMode.DONT_CARE, entryFilter, out);
- }
-
- /**
- * Creates a {@link ZipCombiner} for combining ZIP files using the specified {@link OutputMode},
- * and destination {@link OutputStream}. Uses a {@link CopyEntryFilter} as the
- * {@link ZipEntryFilter}.
- *
- * @param mode the compression preference for the output ZIP file
- * @param out the {@link OutputStream} for writing the combined ZIP file
- */
- public ZipCombiner(OutputMode mode, OutputStream out) {
- this(mode, new CopyEntryFilter(), out);
- }
-
- /**
- * Creates a {@link ZipCombiner} for combining ZIP files using the specified destination
- * {@link OutputStream}. Uses the DONT_CARE {@link OutputMode} and a {@link CopyEntryFilter} as
- * the {@link ZipEntryFilter}.
- *
- * @param out the {@link OutputStream} for writing the combined ZIP file
- */
- public ZipCombiner(OutputStream out) {
- this(OutputMode.DONT_CARE, new CopyEntryFilter(), out);
- }
-
- /**
- * Write all contents from the {@link InputStream} as a prefix file for the combined ZIP file.
- *
- * @param in the {@link InputStream} containing the prefix file data
- * @throws IOException if there is an error writing the prefix file
- */
- public void prependExecutable(InputStream in) throws IOException {
- out.startPrefixFile();
- copyStream(in, out);
- out.endPrefixFile();
- }
-
- /**
- * Adds a directory entry to the combined ZIP file using the specified filename and date.
- *
- * @param filename the name of the directory to create
- * @param date the modified time to assign to the directory
- * @throws IOException if there is an error writing the directory entry
- */
- public void addDirectory(String filename, Date date) throws IOException {
- addDirectory(filename, date, new ExtraData[0]);
- }
-
- /**
- * Adds a directory entry to the combined ZIP file using the specified filename, date, and extra
- * data.
- *
- * @param filename the name of the directory to create
- * @param date the modified time to assign to the directory
- * @param extra the extra field data to add to the directory entry
- * @throws IOException if there is an error writing the directory entry
- */
- public void addDirectory(String filename, Date date, ExtraData[] extra) throws IOException {
- checkArgument(filename.endsWith("/"), "Directory names must end with a /");
- checkState(!entries.containsKey(filename),
- "Zip already contains a directory named %s", filename);
-
- ZipFileEntry entry = new ZipFileEntry(filename);
- entry.setMethod(Compression.STORED);
- entry.setCrc(0);
- entry.setSize(0);
- entry.setCompressedSize(0);
- entry.setTime(date != null ? date.getTime() : new Date().getTime());
- entry.setExtra(new ExtraDataList(extra));
- out.putNextEntry(entry);
- out.closeEntry();
- entries.put(filename, entry);
- }
-
- /**
- * Adds a file with the specified name to the combined ZIP file.
- *
- * @param filename the name of the file to create
- * @param in the {@link InputStream} containing the file data
- * @throws IOException if there is an error writing the file entry
- * @throws IllegalArgumentException if the combined ZIP file already contains a file of the same
- * name.
- */
- public void addFile(String filename, InputStream in) throws IOException {
- addFile(filename, null, in);
- }
-
- /**
- * Adds a file with the specified name and date to the combined ZIP file.
- *
- * @param filename the name of the file to create
- * @param date the modified time to assign to the file
- * @param in the {@link InputStream} containing the file data
- * @throws IOException if there is an error writing the file entry
- * @throws IllegalArgumentException if the combined ZIP file already contains a file of the same
- * name.
- */
- public void addFile(String filename, Date date, InputStream in) throws IOException {
- ZipFileEntry entry = new ZipFileEntry(filename);
- entry.setTime(date != null ? date.getTime() : new Date().getTime());
- addFile(entry, in);
- }
-
- /**
- * Adds a file with attributes specified by the {@link ZipFileEntry} to the combined ZIP file.
- *
- * @param entry the {@link ZipFileEntry} containing the entry meta-data
- * @param in the {@link InputStream} containing the file data
- * @throws IOException if there is an error writing the file entry
- * @throws IllegalArgumentException if the combined ZIP file already contains a file of the same
- * name.
- */
- public void addFile(ZipFileEntry entry, InputStream in) throws IOException {
- checkNotNull(entry, "Zip entry must not be null.");
- checkNotNull(in, "Input stream must not be null.");
- checkArgument(!entries.containsKey(entry.getName()), "Zip already contains a file named '%s'.",
- entry.getName());
-
- ByteArrayOutputStream uncompressed = new ByteArrayOutputStream();
- copyStream(in, uncompressed);
-
- writeEntryFromBuffer(new ZipFileEntry(entry), uncompressed.toByteArray());
- }
-
- /**
- * Adds the contents of a ZIP file to the combined ZIP file using the specified
- * {@link ZipEntryFilter} to determine the appropriate action for each file.
- *
- * @param zipFile the ZIP file to add to the combined ZIP file
- * @throws IOException if there is an error reading the ZIP file or writing entries to the
- * combined ZIP file
- */
- public void addZip(File zipFile) throws IOException {
- try (ZipReader zip = new ZipReader(zipFile)) {
- for (ZipFileEntry entry : zip.entries()) {
- String filename = entry.getName();
- EntryAction action = getAction(filename);
- switch (action.getType()) {
- case SKIP:
- break;
- case COPY:
- case RENAME:
- writeEntry(zip, entry, action);
- break;
- case MERGE:
- entries.put(filename, null);
- InputStream in = zip.getRawInputStream(entry);
- if (entry.getMethod() == Compression.DEFLATED) {
- in = new InflaterInputStream(in, getInflater());
- }
- action.getStrategy().merge(in, action.getMergeBuffer());
- break;
- }
- }
- }
- }
-
- /** Returns the action to take for a file of the given filename. */
- private EntryAction getAction(String filename) throws IOException {
- // If this filename has not been encountered before (no entry for filename) or this filename
- // has been renamed (RENAME entry for filename), the desired action should be recomputed.
- if (!actions.containsKey(filename) || actions.get(filename).getType() == ActionType.RENAME) {
- callback.resetForFile(filename);
- entryFilter.accept(filename, callback);
- }
- checkState(actions.containsKey(filename),
- "Action for file '%s' should have been set by ZipEntryFilter.", filename);
-
- EntryAction action = actions.get(filename);
- // Only copy if this is the first instance of filename.
- if (action.getType() == ActionType.COPY && entries.containsKey(filename)) {
- action = new EntryAction(ActionType.SKIP, action);
- actions.put(filename, action);
- }
- // Only rename if there is not already an entry with filename or filename's action is SKIP.
- if (action.getType() == ActionType.RENAME) {
- if (actions.containsKey(action.getNewName())
- && actions.get(action.getNewName()).getType() == ActionType.SKIP) {
- action = new EntryAction(ActionType.SKIP, action);
- }
- if (entries.containsKey(action.getNewName())) {
- action = new EntryAction(ActionType.SKIP, action);
- }
- }
- return action;
- }
-
- /** Writes an entry with the given name, date and external file attributes from the buffer. */
- private void writeEntryFromBuffer(ZipFileEntry entry, byte[] uncompressed) throws IOException {
- CRC32 crc = new CRC32();
- crc.update(uncompressed);
-
- entry.setCrc(crc.getValue());
- entry.setSize(uncompressed.length);
- if (mode == OutputMode.FORCE_STORED) {
- entry.setMethod(Compression.STORED);
- entry.setCompressedSize(uncompressed.length);
- writeEntry(entry, new ByteArrayInputStream(uncompressed));
- } else {
- ByteArrayOutputStream compressed = new ByteArrayOutputStream();
- copyStream(new DeflaterInputStream(new ByteArrayInputStream(uncompressed), getDeflater()),
- compressed);
- entry.setMethod(Compression.DEFLATED);
- entry.setCompressedSize(compressed.size());
- writeEntry(entry, new ByteArrayInputStream(compressed.toByteArray()));
- }
- }
-
- /**
- * Writes an entry from the specified source {@link ZipReader} and {@link ZipFileEntry} using the
- * specified {@link EntryAction}.
- *
- * Writes the output entry from the input entry performing inflation or deflation as needed
- * and applies any values from the {@link EntryAction} as needed.
- */
- private void writeEntry(ZipReader zip, ZipFileEntry entry, EntryAction action)
- throws IOException {
- checkArgument(action.getType() != ActionType.SKIP,
- "Cannot write a zip entry whose action is of type SKIP.");
-
- ZipFileEntry outEntry = new ZipFileEntry(entry);
- if (action.getType() == ActionType.RENAME) {
- checkNotNull(action.getNewName(),
- "ZipEntryFilter actions of type RENAME must not have a null filename.");
- outEntry.setName(action.getNewName());
- }
-
- if (action.getDate() != null) {
- outEntry.setTime(action.getDate().getTime());
- }
-
- InputStream data;
- if (mode == OutputMode.FORCE_DEFLATE && entry.getMethod() != Compression.DEFLATED) {
- // The output mode is deflate, but the entry compression is not. Create a deflater stream
- // from the raw file data and deflate to a temporary byte array to determine the deflated
- // size. Then use this byte array as the input stream for writing the entry.
- ByteArrayOutputStream tmp = new ByteArrayOutputStream();
- copyStream(new DeflaterInputStream(zip.getRawInputStream(entry), getDeflater()), tmp);
- data = new ByteArrayInputStream(tmp.toByteArray());
- outEntry.setMethod(Compression.DEFLATED);
- outEntry.setCompressedSize(tmp.size());
- } else if (mode == OutputMode.FORCE_STORED && entry.getMethod() != Compression.STORED) {
- // The output mode is stored, but the entry compression is not; create an inflater stream
- // from the raw file data.
- data = new InflaterInputStream(zip.getRawInputStream(entry), getInflater());
- outEntry.setMethod(Compression.STORED);
- outEntry.setCompressedSize(entry.getSize());
- } else {
- // Entry compression agrees with output mode; use the raw file data as is.
- data = zip.getRawInputStream(entry);
- }
- writeEntry(outEntry, data);
- }
-
- /**
- * Writes the specified {@link ZipFileEntry} using the data from the given {@link InputStream}.
- */
- private void writeEntry(ZipFileEntry entry, InputStream data) throws IOException {
- out.putNextEntry(entry);
- copyStream(data, out);
- out.closeEntry();
- entries.put(entry.getName(), entry);
- }
-
- /**
- * Returns true if the combined ZIP file already contains a file of the specified file name.
- *
- * @param filename the filename of the file whose presence in the combined ZIP file is to be
- * tested
- * @return true if the combined ZIP file contains the specified file
- */
- public boolean containsFile(String filename) {
- // TODO(apell): may be slightly different behavior because v1 returns true on skipped names.
- return entries.containsKey(filename);
- }
-
- /**
- * Writes any remaining output data to the output stream and also creates the merged entries by
- * calling the {@link CustomMergeStrategy} implementations given back from the
- * {@link ZipEntryFilter}.
- *
- * @throws IOException if the output stream or the filter throws an IOException
- * @throws IllegalStateException if this method was already called earlier
- */
- public void finish() throws IOException {
- for (Map.Entry entry : actions.entrySet()) {
- String filename = entry.getKey();
- EntryAction action = entry.getValue();
- if (action.getType() == ActionType.MERGE) {
- ByteArrayOutputStream uncompressed = action.getMergeBuffer();
- action.getStrategy().finish(uncompressed);
- if (uncompressed.size() == 0 && action.getStrategy().skipEmpty()) {
- continue;
- }
-
- ZipFileEntry e = new ZipFileEntry(filename);
- e.setTime(action.getDate() != null ? action.getDate().getTime() : new Date().getTime());
- writeEntryFromBuffer(e, uncompressed.toByteArray());
- }
- }
- out.finish();
- }
-
- /**
- * Writes any remaining output data to the output stream and closes it.
- *
- * @throws IOException if the output stream or the filter throws an IOException
- */
- @Override public void close() throws IOException {
- finish();
- out.close();
- }
-
- /** Ensures the truth of an expression involving one or more parameters to the calling method. */
- private static void checkArgument(boolean expression,
- @Nullable String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
- if (!expression) {
- throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
- }
- }
-
- /** Ensures that an object reference passed as a parameter to the calling method is not null. */
- public static T checkNotNull(T reference,
- @Nullable String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
- if (reference == null) {
- // If either of these parameters is null, the right thing happens anyway
- throw new NullPointerException(String.format(errorMessageTemplate, errorMessageArgs));
- }
- return reference;
- }
-
- /** Ensures the truth of an expression involving state. */
- private static void checkState(boolean expression,
- @Nullable String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
- if (!expression) {
- throw new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs));
- }
- }
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ZipEntryFilter.java b/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ZipEntryFilter.java
deleted file mode 100644
index c4692a775c947a..00000000000000
--- a/src/java_tools/singlejar/java/com/google/devtools/build/singlejar/ZipEntryFilter.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Date;
-
-/**
- * A custom filter for entries when combining multiple ZIP files (or even just
- * copying a single ZIP file).
- *
- * Implementations of this interface must be thread-safe. The {@link
- * #accept} method may be called concurrently by multiple threads.
- */
-public interface ZipEntryFilter {
-
- /**
- * Strategy for a custom merge operation. The current file and all additional
- * file are passed to the strategy object via {@link #merge}, which merges
- * the files. At the end of the ZIP combination, {@link #finish} is called,
- * which then writes the merged single entry of that name.
- *
- *
Implementations of this interface are not required to be thread-safe.
- * Thread-safety is achieved by creating multiple instances. Each instance
- * that is separately passed to {@link StrategyCallback#customMerge} is
- * guaranteed not to be called by two threads at the same time.
- */
- interface CustomMergeStrategy {
-
- /**
- * Merges another file into the current state. This method is called for
- * every file entry of the same name.
- */
- void merge(InputStream in, OutputStream out) throws IOException;
-
- /**
- * Outputs the merged result into the given output stream. This method is
- * only called once when no further file of the same name is available.
- */
- void finish(OutputStream out) throws IOException;
-
- /**
- * Called after {@link #finish} if no output was written to check if an empty file should be
- * written. Returns {@code false} by default.
- * @return {@code true} to skip empty merge results, {@code false} to write them.
- */
- default boolean skipEmpty() {
- return false;
- }
- }
-
- /**
- * A callback interface for the {@link ZipEntryFilter#accept} method. Use
- * this interface to indicate the type of processing for the given file name.
- * For every file name, exactly one of the methods must be called once. A
- * second method call throws {@link IllegalStateException}.
- *
- *
There is no guarantee that the callback will perform the requested
- * operation at the time of the invocation. An implementation may choose to
- * defer the operation to an arbitrary later time.
- *
- *
IMPORTANT NOTE: Do not implement this interface. It will be modified to
- * support future extensions, and all implementations in this package will be
- * updated. If you violate this advice, your code will break.
- */
- interface StrategyCallback {
-
- /**
- * Skips the current entry and all entries with the same name.
- */
- void skip() throws IOException;
-
- /**
- * Copies the current entry and skips all further entries with the same
- * name. If {@code date} is non-null, then the timestamp of the entry is
- * overwritten with the given value.
- */
- void copy(Date date) throws IOException;
-
- /**
- * Renames and copies the current entry, and skips all further entries with
- * the same name. If {@code date} is non-null, then the timestamp of the entry
- * is overwritten with the given value.
- */
- void rename(String filename, Date date) throws IOException;
-
- /**
- * Merges this and all further entries with the same name with the given
- * {@link CustomMergeStrategy}. This method must never be called twice with
- * the same object. If {@code date} is non-null, then the timestamp of the
- * generated entry is set to the given value; otherwise, it is set to the
- * current time.
- */
- void customMerge(Date date, CustomMergeStrategy strategy) throws IOException;
- }
-
- /**
- * Determines the policy with which to handle the ZIP file entry with the
- * given name and calls the appropriate method on the callback interface
- * {@link StrategyCallback}. For every unique name in the set of all ZIP file
- * entries, this method is called exactly once and the result is used for all
- * entries of the same name. Except, if an entry is renamed, the original name
- * is not considered as having been encountered yet.
- *
- *
Implementations should use the filename to distinguish the desired
- * processing, call one method on the callback interface and return
- * immediately after that call.
- *
- *
There is no guarantee that the callback will perform the requested
- * operation at the time of the invocation. An implementation may choose to
- * defer the operation to an arbitrary later time.
- */
- void accept(String filename, StrategyCallback callback) throws IOException;
-}
diff --git a/src/java_tools/singlejar/java/com/google/devtools/build/zip/BUILD b/src/java_tools/singlejar/java/com/google/devtools/build/zip/BUILD
index e876551507088a..e21c956cb6f5f6 100644
--- a/src/java_tools/singlejar/java/com/google/devtools/build/zip/BUILD
+++ b/src/java_tools/singlejar/java/com/google/devtools/build/zip/BUILD
@@ -4,7 +4,12 @@ load("@rules_java//java:defs.bzl", "java_library")
# Zip provides a library for reading and writing zip files, allowing more
# advanced manipulation than the JDK equivalents by providing detailed zip
# entry data and raw file access.
-package(default_visibility = ["//src/java_tools/singlejar:singlejar_package_group"])
+package(default_visibility = [":singlejar_package_group"])
+
+package_group(
+ name = "singlejar_package_group",
+ packages = ["//src/java_tools/singlejar/..."],
+)
filegroup(
name = "srcs",
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/BUILD b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/BUILD
deleted file mode 100644
index 19d3582ed591cb..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/BUILD
+++ /dev/null
@@ -1,33 +0,0 @@
-load("@rules_java//java:defs.bzl", "java_library", "java_test")
-
-# Description:
-# Tests for SingleJar
-package(default_visibility = ["//src/java_tools/singlejar:singlejar_package_group"])
-
-java_library(
- name = "libSingleJarTesting",
- testonly = 1,
- srcs = glob(["*.java"]),
- deps = [
- "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:libSingleJar",
- "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:libSingleJarMain",
- "//src/java_tools/singlejar/java/com/google/devtools/build/zip",
- "//src/test/java/com/google/devtools/build/lib/testutil:TestSuite",
- "//third_party:guava",
- "//third_party:jsr305",
- "//third_party:junit4",
- "//third_party:truth",
- ],
-)
-
-java_test(
- name = "SingleJarTests",
- test_class = "com.google.devtools.build.singlejar.SingleJarTests",
- runtime_deps = [":libSingleJarTesting"],
-)
-
-filegroup(
- name = "srcs",
- srcs = glob(["*.java"]) + ["BUILD"],
- visibility = ["//src:__subpackages__"],
-)
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ConcatenateStrategyTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ConcatenateStrategyTest.java
deleted file mode 100644
index 1d46ffa8a3d4d3..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ConcatenateStrategyTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Unit tests for {@link ConcatenateStrategy}. */
-@RunWith(JUnit4.class)
-public class ConcatenateStrategyTest {
-
- private String merge(String... inputs) throws IOException {
- return mergeInternal(true, inputs);
- }
-
- private String mergeNoNewLine(String... inputs) throws IOException {
- return mergeInternal(false, inputs);
- }
-
- private String mergeInternal(boolean appendNewLine, String... inputs) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ConcatenateStrategy strategy = new ConcatenateStrategy(appendNewLine);
- for (String input : inputs) {
- strategy.merge(new ByteArrayInputStream(input.getBytes(UTF_8)), out);
- }
- strategy.finish(out);
- return new String(out.toByteArray(), UTF_8);
- }
-
- @Test
- public void testSingleInput() throws IOException {
- assertThat(merge("a")).isEqualTo("a");
- assertThat(mergeNoNewLine("a")).isEqualTo("a");
- }
-
- @Test
- public void testTwoInputs() throws IOException {
- assertThat(merge("a\n", "b")).isEqualTo("a\nb");
- assertThat(mergeNoNewLine("a\n", "b")).isEqualTo("a\nb");
- }
-
- @Test
- public void testAutomaticNewline() throws IOException {
- assertThat(merge("a", "b")).isEqualTo("a\nb");
- assertThat(mergeNoNewLine("a", "b")).isEqualTo("ab");
- }
-
- @Test
- public void testAutomaticNewlineAndEmptyFile() throws IOException {
- assertThat(merge("a", "", "b")).isEqualTo("a\nb");
- assertThat(mergeNoNewLine("a", "", "b")).isEqualTo("ab");
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/CopyEntryFilterTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/CopyEntryFilterTest.java
deleted file mode 100644
index 47f4a361d0956d..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/CopyEntryFilterTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import java.io.IOException;
-import java.util.Arrays;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Unit tests for {@link CopyEntryFilter}. */
-@RunWith(JUnit4.class)
-public class CopyEntryFilterTest {
-
- @Test
- public void testSingleInput() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new CopyEntryFilter().accept("abc", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("copy"));
- }
-
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/DefaultJarEntryFilterTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/DefaultJarEntryFilterTest.java
deleted file mode 100644
index 2e2e910143e67d..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/DefaultJarEntryFilterTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.jar.JarFile;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Unit tests for {@link DefaultJarEntryFilter}.
- */
-@RunWith(JUnit4.class)
-public class DefaultJarEntryFilterTest {
-
- private static final Date DOS_EPOCH = ZipCombiner.DOS_EPOCH;
-
- @Test
- public void testSingleInput() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept("abc", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("copy"));
- assertThat(callback.dates).isEqualTo(Arrays.asList(DOS_EPOCH));
- }
-
- @Test
- public void testProtobufExtensionsInput() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept("protobuf.meta", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("customMerge"));
- assertThat(callback.dates).isEqualTo(Arrays.asList(DOS_EPOCH));
- }
-
- @Test
- public void testManifestInput() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept(JarFile.MANIFEST_NAME, callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("skip"));
- }
-
- @Test
- public void testServiceInput() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept("META-INF/services/any.service", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("customMerge"));
- assertThat(callback.dates).isEqualTo(Arrays.asList(DOS_EPOCH));
- }
-
- @Test
- public void testSpringHandlers() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept("META-INF/spring.handlers", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("customMerge"));
- assertThat(callback.dates).isEqualTo(Arrays.asList(DOS_EPOCH));
- }
-
- @Test
- public void testSpringSchemas() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept("META-INF/spring.schemas", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("customMerge"));
- assertThat(callback.dates).isEqualTo(Arrays.asList(DOS_EPOCH));
- }
-
- @Test
- public void testReferenceConfigs() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept("reference.conf", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("customMerge"));
- assertThat(callback.dates).isEqualTo(Arrays.asList(DOS_EPOCH));
- }
-
- @Test
- public void testClassInput() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- new DefaultJarEntryFilter().accept("a.class", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("copy"));
- assertThat(callback.dates)
- .isEqualTo(Arrays.asList(DefaultJarEntryFilter.DOS_EPOCH_PLUS_2_SECONDS));
- }
-
- @Test
- public void testOtherSkippedInputs() throws IOException {
- RecordingCallback callback = new RecordingCallback();
- ZipEntryFilter filter = new DefaultJarEntryFilter();
- filter.accept("a.SF", callback);
- filter.accept("a.DSA", callback);
- filter.accept("a.RSA", callback);
- assertThat(callback.calls).isEqualTo(Arrays.asList("skip", "skip", "skip"));
- assertThat(callback.dates).isEqualTo(Arrays.asList());
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/FakeZipFile.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/FakeZipFile.java
deleted file mode 100644
index 9b4a2dcb7c53a0..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/FakeZipFile.java
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.devtools.build.singlejar.SingleJarTest.EntryMode;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-/**
- * A fake zip file to assert that a given {@link ZipInputStream} contains
- * specified entries in a specified order. Just for unit testing.
- */
-public final class FakeZipFile {
-
- /**
- * Validates an input provided as a byte array.
- */
- public static interface ByteValidator {
- /**
- * Check if {@code object} is the expected input. If {@code object} does not match the expected
- * pattern, an assertion should fails with the necessary message.
- */
- void validate(byte[] object);
- }
-
- private static void assertSameByteArray(byte[] expected, byte[] actual) {
- if (expected == null) {
- assertThat(actual).isNull();
- } else {
- assertThat(actual).isEqualTo(expected);
- }
- }
-
- private static byte[] readZipEntryContent(ZipInputStream zipInput) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int bytesCopied;
- while ((bytesCopied = zipInput.read(buffer)) != -1) {
- out.write(buffer, 0, bytesCopied);
- }
- return out.toByteArray();
- }
-
- private static final class PlainByteValidator implements ByteValidator {
- private final byte[] expected;
-
- private PlainByteValidator(String expected) {
- this.expected = expected == null ? new byte[0] : expected.getBytes(UTF_8);
- }
-
- @Override
- public void validate(byte[] object) {
- assertSameByteArray(expected, object);
- }
-
- }
-
- private static final class FakeZipEntry {
-
- private final String name;
- private final ByteValidator content;
- private final Date date;
- private final byte[] extra;
- private final EntryMode mode;
-
- private FakeZipEntry(String name, Date date, String content, byte[] extra, EntryMode mode) {
- this.name = name;
- this.date = date;
- this.content = new PlainByteValidator(content);
- this.extra = extra;
- this.mode = mode;
- }
-
- private FakeZipEntry(String name, Date date, ByteValidator content, byte[] extra,
- EntryMode mode) {
- this.name = name;
- this.date = date;
- this.content = content;
- this.extra = extra;
- this.mode = mode;
- }
-
- public void assertNext(ZipInputStream zipInput) throws IOException {
- ZipEntry zipEntry = zipInput.getNextEntry();
- assertThat(zipEntry).isNotNull();
- switch (mode) {
- case EXPECT_DEFLATE:
- assertThat(zipEntry.getMethod()).isEqualTo(ZipEntry.DEFLATED);
- break;
- case EXPECT_STORED:
- assertThat(zipEntry.getMethod()).isEqualTo(ZipEntry.STORED);
- break;
- default:
- // we don't care.
- break;
- }
- assertThat(zipEntry.getName()).isEqualTo(name);
- if (date != null) {
- assertThat(zipEntry.getTime()).isEqualTo(date.getTime());
- }
- assertSameByteArray(extra, zipEntry.getExtra());
- content.validate(readZipEntryContent(zipInput));
- }
- }
-
- private final List entries = new ArrayList<>();
-
- public FakeZipFile addEntry(String name, String content) {
- entries.add(new FakeZipEntry(name, null, content, null, EntryMode.DONT_CARE));
- return this;
- }
-
- public FakeZipFile addEntry(String name, String content, boolean compressed) {
- entries.add(new FakeZipEntry(name, null, content, null,
- compressed ? EntryMode.EXPECT_DEFLATE : EntryMode.EXPECT_STORED));
- return this;
- }
-
- public FakeZipFile addEntry(String name, Date date, String content) {
- entries.add(new FakeZipEntry(name, date, content, null, EntryMode.DONT_CARE));
- return this;
- }
-
- public FakeZipFile addEntry(String name, Date date, String content, boolean compressed) {
- entries.add(new FakeZipEntry(name, date, content, null,
- compressed ? EntryMode.EXPECT_DEFLATE : EntryMode.EXPECT_STORED));
- return this;
- }
-
- public FakeZipFile addEntry(String name, ByteValidator content) {
- entries.add(new FakeZipEntry(name, null, content, null, EntryMode.DONT_CARE));
- return this;
- }
-
- public FakeZipFile addEntry(String name, ByteValidator content, boolean compressed) {
- entries.add(new FakeZipEntry(name, null, content, null,
- compressed ? EntryMode.EXPECT_DEFLATE : EntryMode.EXPECT_STORED));
- return this;
- }
-
- public FakeZipFile addEntry(String name, Date date, ByteValidator content) {
- entries.add(new FakeZipEntry(name, date, content, null, EntryMode.DONT_CARE));
- return this;
- }
-
- public FakeZipFile addEntry(String name, Date date, ByteValidator content,
- boolean compressed) {
- entries.add(new FakeZipEntry(name, date, content, null,
- compressed ? EntryMode.EXPECT_DEFLATE : EntryMode.EXPECT_STORED));
- return this;
- }
-
- public FakeZipFile addEntry(String name, byte[] extra) {
- entries.add(new FakeZipEntry(name, null, (String) null, extra, EntryMode.DONT_CARE));
- return this;
- }
-
- public FakeZipFile addEntry(String name, byte[] extra, boolean compressed) {
- entries.add(new FakeZipEntry(name, null, (String) null, extra,
- compressed ? EntryMode.EXPECT_DEFLATE : EntryMode.EXPECT_STORED));
- return this;
- }
-
- private byte[] preamble = null;
-
- public FakeZipFile addPreamble(byte[] contents) {
- preamble = Arrays.copyOf(contents, contents.length);
- return this;
- }
-
- private int getUnsignedShort(byte[] source, int offset) {
- int a = source[offset + 0] & 0xff;
- int b = source[offset + 1] & 0xff;
- return (b << 8) | a;
- }
-
- public void assertSame(byte[] data) throws IOException {
- int offset = 0;
- int length = data.length;
- if (preamble != null) {
- offset += preamble.length;
- length -= offset;
- byte[] maybePreamble = Arrays.copyOfRange(data, 0, offset);
- assertThat(maybePreamble).isEqualTo(preamble);
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(data, offset, length));
- for (FakeZipEntry entry : entries) {
- entry.assertNext(zipInput);
- }
- assertThat(zipInput.getNextEntry()).isNull();
- // Verify that the end of central directory data is correct.
- // This assumes that the end of directory is at the end of input and that there is no zip file
- // comment.
- int count = getUnsignedShort(data, data.length-14);
- assertThat(count).isEqualTo(entries.size());
- count = getUnsignedShort(data, data.length-12);
- assertThat(count).isEqualTo(entries.size());
- }
-
- /**
- * Assert that {@code expected} is the same zip file as {@code actual}. It is similar to
- * {@link org.junit.Assert#assertArrayEquals(byte[], byte[])} but should use a more
- * helpful error message.
- */
- public static void assertSame(byte[] expected, byte[] actual) throws IOException {
- // First parse the zip files, then compare to have explicit comparison messages.
- ZipInputStream expectedZip = new ZipInputStream(new ByteArrayInputStream(expected));
- ZipInputStream actualZip = new ZipInputStream(new ByteArrayInputStream(actual));
- StringBuffer actualFileList = new StringBuffer();
- StringBuffer expectedFileList = new StringBuffer();
- Map actualEntries = new HashMap();
- Map expectedEntries = new HashMap();
- Map actualEntryContents = new HashMap();
- Map expectedEntryContents = new HashMap();
- parseZipEntry(expectedZip, expectedFileList, expectedEntries, expectedEntryContents);
- parseZipEntry(actualZip, actualFileList, actualEntries, actualEntryContents);
- // Compare the ordered file list first.
- assertThat(actualFileList.toString()).isEqualTo(expectedFileList.toString());
-
- // Then compare each entry.
- for (String name : expectedEntries.keySet()) {
- ZipEntry expectedEntry = expectedEntries.get(name);
- ZipEntry actualEntry = actualEntries.get(name);
- assertWithMessage("Time differs for " + name)
- .that(actualEntry.getTime())
- .isEqualTo(expectedEntry.getTime());
- assertWithMessage("Extraneous content differs for " + name)
- .that(actualEntry.getExtra())
- .isEqualTo(expectedEntry.getExtra());
- assertWithMessage("Content differs for " + name)
- .that(actualEntryContents.get(name))
- .isEqualTo(expectedEntryContents.get(name));
- }
-
- // Finally do a binary array comparison to be sure that test fails if files are different in
- // some way we don't test.
- assertThat(actual).isEqualTo(expected);
- }
-
- private static void parseZipEntry(ZipInputStream expectedZip, StringBuffer expectedFileList,
- Map expectedEntries, Map expectedEntryContents)
- throws IOException {
- ZipEntry expectedEntry;
- while ((expectedEntry = expectedZip.getNextEntry()) != null) {
- expectedFileList.append(expectedEntry.getName()).append("\n");
- expectedEntries.put(expectedEntry.getName(), expectedEntry);
- expectedEntryContents.put(expectedEntry.getName(), readZipEntryContent(expectedZip));
- }
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java
deleted file mode 100644
index 6ebef2001f59c3..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/MockSimpleFileSystem.java
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * FileSystem for testing. FileSystem supports exactly one one OutputStream for filename
- * specified in constructor.
- * Workflow for using this class in tests are following:
- *
- * - Construct with exactly one outputFile.
- * - add some input files using method addFile
- * - check content of outputFile calling toByteArray
- *
- */
-public final class MockSimpleFileSystem implements SimpleFileSystem {
-
- private final String outputFileName;
- private ByteArrayOutputStream out;
- private final Map files = new HashMap<>();
-
- public MockSimpleFileSystem(String outputFileName) {
- this.outputFileName = outputFileName;
- }
-
- public void addFile(String name, byte[] content) {
- files.put(name, content);
- }
-
- public void addFile(String name, String content) {
- files.put(name, content.getBytes(UTF_8));
- }
-
- @Override
- public OutputStream getOutputStream(String filename) {
- assertThat(filename).isEqualTo(outputFileName);
- assertThat(out).isNull();
- out = new ByteArrayOutputStream();
- return out;
- }
-
- @Override
- public InputStream getInputStream(String filename) throws IOException {
- byte[] data = files.get(filename);
- if (data == null) {
- throw new FileNotFoundException();
- }
- return new ByteArrayInputStream(data);
- }
-
- @Override
- public File getFile(String filename) throws IOException {
- byte[] data = files.get(filename);
- if (data == null) {
- throw new FileNotFoundException();
- }
- File file = File.createTempFile(filename, null);
- Files.copy(new ByteArrayInputStream(data), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
- return file;
- }
-
- @Override
- public boolean delete(String filename) {
- assertThat(filename).isEqualTo(outputFileName);
- assertThat(out).isNotNull();
- out = null;
- return true;
- }
-
- public byte[] toByteArray() {
- assertThat(out).isNotNull();
- return out.toByteArray();
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/OptionFileExpanderTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/OptionFileExpanderTest.java
deleted file mode 100644
index f6556b950ca235..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/OptionFileExpanderTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertThrows;
-
-import com.google.devtools.build.singlejar.OptionFileExpander.OptionFileProvider;
-import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Unit tests for {@link OptionFileExpander}.
- */
-@RunWith(JUnit4.class)
-public class OptionFileExpanderTest {
-
- private static class StoredOptionFileProvider implements OptionFileProvider {
-
- private Map availableFiles = new HashMap<>();
-
- void addFile(String filename, String content) {
- availableFiles.put(filename, content.getBytes(UTF_8));
- }
-
- @Override
- public InputStream getInputStream(String filename) throws IOException {
- byte[] result = availableFiles.get(filename);
- if (result == null) {
- throw new FileNotFoundException();
- }
- return new ByteArrayInputStream(result);
- }
- }
-
- @Test
- public void testNoExpansion() throws IOException {
- OptionFileExpander expander = new OptionFileExpander(new StoredOptionFileProvider());
- assertThat(expander.expandArguments(Arrays.asList("--some", "option", "list")))
- .isEqualTo(Arrays.asList("--some", "option", "list"));
- }
-
- @Test
- public void testExpandSimpleOptionsFile() throws IOException {
- StoredOptionFileProvider provider = new StoredOptionFileProvider();
- provider.addFile("options", "--some option list");
- OptionFileExpander expander = new OptionFileExpander(provider);
- assertThat(expander.expandArguments(Arrays.asList("@options")))
- .isEqualTo(Arrays.asList("--some", "option", "list"));
- }
-
- @Test
- public void testIllegalOptionsFile() {
- StoredOptionFileProvider provider = new StoredOptionFileProvider();
- provider.addFile("options", "'missing apostrophe");
- OptionFileExpander expander = new OptionFileExpander(provider);
- assertThrows(IOException.class, () -> expander.expandArguments(Arrays.asList("@options")));
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/PrefixListPathFilterTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/PrefixListPathFilterTest.java
deleted file mode 100644
index 030ae277a593ff..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/PrefixListPathFilterTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.singlejar.DefaultJarEntryFilter.PathFilter;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link PrefixListPathFilter}.
- */
-@RunWith(JUnit4.class)
-public class PrefixListPathFilterTest {
- private PathFilter filter;
-
- @Test
- public void testPrefixList() {
- filter = new PrefixListPathFilter(ImmutableList.of("dir1", "dir/subdir"));
- assertIncluded("dir1/file1");
- assertExcluded("dir2/file1");
- assertIncluded("dir/subdir/file1");
- assertExcluded("dir2/subdir/file1");
- assertExcluded("dir/othersub/file1");
- assertExcluded("dir3/file1");
- }
-
- private void assertExcluded(String path) {
- assertWithMessage(path + " should have been excluded, but was included")
- .that(filter.allowed(path))
- .isFalse();
- }
-
- private void assertIncluded(String path) {
- assertWithMessage(path + " should have been included but was not")
- .that(filter.allowed(path))
- .isTrue();
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/RecordingCallback.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/RecordingCallback.java
deleted file mode 100644
index e77dd47bfd30e3..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/RecordingCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-
-import com.google.devtools.build.singlejar.ZipEntryFilter.CustomMergeStrategy;
-import com.google.devtools.build.singlejar.ZipEntryFilter.StrategyCallback;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * A helper implementation of {@link StrategyCallback} that records callback
- * invocations as string.
- */
-public final class RecordingCallback implements StrategyCallback {
-
- public final List calls = new ArrayList<>();
- public final List dates = new ArrayList<>();
-
- @Override
- public void copy(Date date) {
- calls.add("copy");
- dates.add(date);
- }
-
- @Override
- public void rename(String filename, Date date) {
- calls.add("rename");
- dates.add(date);
- }
-
- @Override
- public void customMerge(Date date, CustomMergeStrategy strategy) {
- calls.add("customMerge");
- dates.add(date);
- }
-
- @Override
- public void skip() {
- calls.add("skip");
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java
deleted file mode 100644
index 688ec149d41c9e..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTest.java
+++ /dev/null
@@ -1,648 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertThrows;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.singlejar.FakeZipFile.ByteValidator;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.jar.JarFile;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Unit tests for {@link SingleJar}.
- */
-@RunWith(JUnit4.class)
-public class SingleJarTest {
-
- public static final byte[] EXTRA_FOR_META_INF = new byte[] {(byte) 0xFE, (byte) 0xCA, 0x00, 0x00};
-
- static final Joiner LINE_JOINER = Joiner.on("\r\n");
- static final Joiner LINEFEED_JOINER = Joiner.on("\n");
-
- static enum EntryMode {
- DONT_CARE, EXPECT_DEFLATE, EXPECT_STORED;
- }
-
- public static final class BuildInfoValidator implements ByteValidator {
- private final List buildInfoLines;
-
- public BuildInfoValidator(List buildInfoLines) {
- this.buildInfoLines = buildInfoLines;
- }
-
- @Override
- public void validate(byte[] content) {
- String actualBuildInfo = new String(content, StandardCharsets.UTF_8);
- List expectedBuildInfos = new ArrayList<>();
- for (String line : buildInfoLines) { // the character : is escaped
- expectedBuildInfos.add(line.replace(":", "\\:"));
- }
- Collections.sort(expectedBuildInfos);
- String[] actualBuildInfos = actualBuildInfo.split("\n");
- Arrays.sort(actualBuildInfos);
- assertThat(LINEFEED_JOINER.join(actualBuildInfos))
- .isEqualTo(LINEFEED_JOINER.join(expectedBuildInfos));
- }
-
- }
-
- // Manifest file line ordering is dependent of the ordering in HashMap (Attributes class) so
- // we do a sorted comparison for Manifest.
- public static final class ManifestValidator implements ByteValidator {
- private final List manifestLines;
-
- public ManifestValidator(List manifestLines) {
- this.manifestLines = new ArrayList<>(manifestLines);
- Collections.sort(this.manifestLines);
- }
-
- public ManifestValidator(String... manifestLines) {
- this.manifestLines = Arrays.asList(manifestLines);
- Collections.sort(this.manifestLines);
- }
-
- @Override
- public void validate(byte[] content) {
- String actualManifest = new String(content, StandardCharsets.UTF_8);
- String[] actualManifestLines = actualManifest.trim().split("\r\n");
- Arrays.sort(actualManifestLines);
- assertThat(LINEFEED_JOINER.join(actualManifestLines))
- .isEqualTo(LINEFEED_JOINER.join(manifestLines));
- }
-
- }
-
- private BuildInfoValidator redactedBuildData(String outputJar) {
- return new BuildInfoValidator(ImmutableList.of("build.target=" + outputJar));
- }
-
- private BuildInfoValidator redactedBuildData(String outputJar, String mainClass) {
- return new BuildInfoValidator(
- ImmutableList.of("build.target=" + outputJar, "main.class=" + mainClass));
- }
-
- static List getBuildInfo() {
- return ImmutableList.of("build.build_id=11111-222-33333",
- "build.version=12659499",
- "build.location=user@machine.domain.com:/home/user/source",
- "build.target=output.jar",
- "build.time=Fri Jan 2 02:17:36 1970 (123456)",
- "build.timestamp=Fri Jan 2 02:17:36 1970 (123456)",
- "build.timestamp.as.int=123456"
- );
- }
-
- private byte[] sampleZip() {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.txt", "Hello World!");
- return factory.toByteArray();
- }
-
- private byte[] sampleUncompressedZip() {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.txt", "Hello World!", false);
- return factory.toByteArray();
- }
-
- private byte[] sampleZipWithSF() {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.SF", "Hello World!");
- return factory.toByteArray();
- }
-
- private byte[] sampleZipWithSubdirs() {
- ZipFactory factory = new ZipFactory();
- factory.addFile("dir1/file1", "contents11");
- factory.addFile("dir1/file2", "contents12");
- factory.addFile("dir2/file1", "contents21");
- factory.addFile("dir3/file1", "contents31");
- return factory.toByteArray();
- }
-
- private void assertStripFirstLine(String expected, String testCase) {
- byte[] result = SingleJar.stripFirstLine(testCase.getBytes(StandardCharsets.UTF_8));
- assertThat(new String(result, UTF_8)).isEqualTo(expected);
- }
-
- @Test
- public void testStripFirstLine() {
- assertStripFirstLine("", "");
- assertStripFirstLine("", "no linefeed");
- assertStripFirstLine(LINEFEED_JOINER.join("toto", "titi"),
- LINEFEED_JOINER.join("# timestamp comment", "toto", "titi"));
- assertStripFirstLine(LINE_JOINER.join("toto", "titi"),
- LINE_JOINER.join("# timestamp comment", "toto", "titi"));
- }
-
- @Test
- public void testEmptyJar() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"))
- .addEntry("build-data.properties", redactedBuildData("output.jar"));
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- // Test that two identical calls at different time actually returns identical results
- @Test
- public void testDeterministicJar() throws IOException, InterruptedException {
- MockSimpleFileSystem mockFs1 = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar1 = new SingleJar(mockFs1);
- singleJar1.run(ImmutableList.of("--output", "output.jar", "--extra_build_info", "toto=titi",
- "--normalize"));
- Thread.sleep(1000); // ensure that we are not at the same seconds
-
- MockSimpleFileSystem mockFs2 = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar2 = new SingleJar(mockFs2);
- singleJar2.run(ImmutableList.of("--output", "output.jar", "--extra_build_info", "toto=titi",
- "--normalize"));
-
- FakeZipFile.assertSame(mockFs1.toByteArray(), mockFs2.toByteArray());
- }
-
- @Test
- public void testExtraManifestContent() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--deploy_manifest_lines",
- "Main-Class: SomeClass", "X-Other: Duh"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar",
- "Main-Class: SomeClass",
- "X-Other: Duh"))
- .addEntry("build-data.properties", redactedBuildData("output.jar"));
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testMultipleExtraManifestContent() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--deploy_manifest_lines", "X-Other: Duh",
- "--output", "output.jar",
- "--deploy_manifest_lines", "Main-Class: SomeClass"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar",
- "Main-Class: SomeClass",
- "X-Other: Duh"))
- .addEntry("build-data.properties", redactedBuildData("output.jar"));
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testMainClass() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--main_class", "SomeClass"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar",
- "Main-Class: SomeClass"))
- .addEntry("build-data.properties", redactedBuildData("output.jar", "SomeClass"));
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- // These four tests test all combinations of compressed/uncompressed input and output.
- @Test
- public void testSimpleZip() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("test.jar", sampleZip());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources", "test.jar"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"), false)
- .addEntry("build-data.properties", redactedBuildData("output.jar"), false)
- .addEntry("hello.txt", "Hello World!", false);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testSimpleZipExpectCompressedOutput() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("test.jar", sampleZip());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources", "test.jar",
- "--compression"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"), true)
- .addEntry("build-data.properties", redactedBuildData("output.jar"), true)
- .addEntry("hello.txt", "Hello World!", true);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testSimpleUncompressedZip() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("test.jar", sampleUncompressedZip());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources", "test.jar"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(ImmutableList.of(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar")), false)
- .addEntry("build-data.properties", redactedBuildData("output.jar"), false)
- .addEntry("hello.txt", "Hello World!", false);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testSimpleUncompressedZipExpectCompressedOutput() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("test.jar", sampleUncompressedZip());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources", "test.jar",
- "--compression"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"), true)
- .addEntry("build-data.properties", redactedBuildData("output.jar"), true)
- .addEntry("hello.txt", "Hello World!", true);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- // Integration test for option file expansion.
- @Test
- public void testOptionFile() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("input.jar", sampleZip());
- mockFs.addFile("options", "--output output.jar --sources input.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("@options"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"))
- .addEntry("build-data.properties", redactedBuildData("output.jar"))
- .addEntry("hello.txt", "Hello World!");
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testSkipsSignatureFiles() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("input.jar", sampleZipWithSF());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources", "input.jar"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"))
- .addEntry("build-data.properties", redactedBuildData("output.jar"));
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testSkipsUsingInputPrefixes() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("input.jar", sampleZipWithSubdirs());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources",
- "input.jar", "--include_prefixes", "dir1", "dir2"));
-
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"))
- .addEntry("build-data.properties", redactedBuildData("output.jar"))
- .addEntry("dir1/file1", "contents11")
- .addEntry("dir1/file2", "contents12")
- .addEntry("dir2/file1", "contents21");
-
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testSkipsUsingMultipleInputPrefixes() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("input.jar", sampleZipWithSubdirs());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--include_prefixes", "dir2",
- "--sources", "input.jar", "--include_prefixes", "dir1"));
-
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"))
- .addEntry("build-data.properties", redactedBuildData("output.jar"))
- .addEntry("dir1/file1", "contents11")
- .addEntry("dir1/file2", "contents12")
- .addEntry("dir2/file1", "contents21");
-
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testNormalize() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("input.jar", sampleZip());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources", "input.jar",
- "--normalize"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME, ZipCombiner.DOS_EPOCH, new ManifestValidator(
- "Manifest-Version: 1.0", "Created-By: blaze-singlejar"), false)
- .addEntry("build-data.properties", ZipCombiner.DOS_EPOCH,
- redactedBuildData("output.jar"), false)
- .addEntry("hello.txt", ZipCombiner.DOS_EPOCH, "Hello World!", false);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testNormalizeAndCompress() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("input.jar", sampleZip());
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--sources", "input.jar",
- "--normalize", "--compression"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME, ZipCombiner.DOS_EPOCH, new ManifestValidator(
- "Manifest-Version: 1.0", "Created-By: blaze-singlejar"), true)
- .addEntry("build-data.properties", ZipCombiner.DOS_EPOCH,
- redactedBuildData("output.jar"), true)
- .addEntry("hello.txt", ZipCombiner.DOS_EPOCH, "Hello World!", true);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testAddBuildInfoProperties() throws IOException {
- List buildInfo = getBuildInfo();
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0", "Created-By: blaze-singlejar"), false)
- .addEntry("build-data.properties", new BuildInfoValidator(buildInfo),
- false);
-
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- List args = new ArrayList<>();
- args.add("--output");
- args.add("output.jar");
- args.addAll(infoPropertyArguments(buildInfo));
- singleJar.run(args);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- private static List infoPropertyArguments(List buildInfoLines) {
- List args = new ArrayList<>();
- for (String s : buildInfoLines) {
- if (!s.isEmpty()) {
- args.add("--extra_build_info");
- args.add(s);
- }
- }
- return args;
- }
-
- @Test
- public void testAddBuildInfoPropertiesFile() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- doTestAddBuildInfoPropertiesFile(mockFs, "output.jar", singleJar);
- }
-
- public static void doTestAddBuildInfoPropertiesFile(MockSimpleFileSystem mockFs, String target,
- SingleJar singleJar) throws IOException {
- List buildInfo = getBuildInfo();
- mockFs.addFile("my.properties", makePropertyFileFromBuildInfo(buildInfo));
- singleJar.run(ImmutableList.of("--output", target, "--build_info_file", "my.properties"));
-
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME,
- new ManifestValidator("Manifest-Version: 1.0", "Created-By: blaze-singlejar"), false)
- .addEntry("build-data.properties", new BuildInfoValidator(buildInfo),
- false);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- private static String makePropertyFileFromBuildInfo(List buildInfo) {
- return LINEFEED_JOINER.join(buildInfo).replace(":", "\\:");
- }
-
- @Test
- public void testAddBuildInfoPropertiesFiles() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- doTestAddBuildInfoPropertiesFiles(mockFs, "output.jar", singleJar);
- }
-
- public static void doTestAddBuildInfoPropertiesFiles(MockSimpleFileSystem mockFs, String target,
- SingleJar singleJar) throws IOException {
- List buildInfo = getBuildInfo();
-
- mockFs.addFile("my1.properties", makePropertyFileFromBuildInfo(buildInfo.subList(0, 4)));
- mockFs.addFile("my2.properties",
- makePropertyFileFromBuildInfo(buildInfo.subList(4, buildInfo.size())));
- singleJar.run(ImmutableList.of("--output", target,
- "--build_info_file", "my1.properties",
- "--build_info_file", "my2.properties"));
-
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME,
- new ManifestValidator("Manifest-Version: 1.0", "Created-By: blaze-singlejar"), false)
- .addEntry("build-data.properties", new BuildInfoValidator(buildInfo),
- false);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testAddBuildInfoPropertiesAndFiles() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- doTestAddBuildInfoPropertiesAndFiles(mockFs, "output.jar", singleJar);
- }
-
- public static void doTestAddBuildInfoPropertiesAndFiles(MockSimpleFileSystem mockFs,
- String target, SingleJar singleJar) throws IOException {
- List buildInfo = getBuildInfo();
-
- mockFs.addFile("my1.properties", makePropertyFileFromBuildInfo(buildInfo.subList(0, 4)));
- mockFs.addFile("my2.properties", makePropertyFileFromBuildInfo(
- buildInfo.subList(4, buildInfo.size())));
- List args = ImmutableList.builder()
- .add("--output").add(target)
- .add("--build_info_file").add("my1.properties")
- .add("--build_info_file").add("my2.properties")
- .addAll(infoPropertyArguments(buildInfo.subList(4, buildInfo.size())))
- .build();
-
- singleJar.run(args);
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF, false)
- .addEntry(JarFile.MANIFEST_NAME,
- new ManifestValidator("Manifest-Version: 1.0", "Created-By: blaze-singlejar"), false)
- .addEntry("build-data.properties", new BuildInfoValidator(buildInfo),
- false);
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
-
- @Test
- public void testExcludeBuildData() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- SingleJar singleJar = new SingleJar(mockFs);
- doTestExcludeBuildData(mockFs, "output.jar", singleJar);
- }
-
- public static void doTestExcludeBuildData(MockSimpleFileSystem mockFs, String target,
- SingleJar singleJar) throws IOException {
- singleJar.run(ImmutableList.of("--output", target, "--exclude_build_data"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"));
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testResourceMapping() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("a/b/c", "Test");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--exclude_build_data",
- "--resources", "a/b/c:c/b/a"));
- FakeZipFile expectedResult = new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(JarFile.MANIFEST_NAME, new ManifestValidator(
- "Manifest-Version: 1.0",
- "Created-By: blaze-singlejar"))
- .addEntry("c/", (String) null)
- .addEntry("c/b/", (String) null)
- .addEntry("c/b/a", "Test");
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testResourceMappingIdentity() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("a/b/c", "Test");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--exclude_build_data",
- "--resources", "a/b/c"));
- FakeZipFile expectedResult =
- new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(
- JarFile.MANIFEST_NAME,
- new ManifestValidator("Manifest-Version: 1.0", "Created-By: blaze-singlejar"))
- .addEntry("a/", (String) null)
- .addEntry("a/b/", (String) null)
- .addEntry("a/b/c", "Test");
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testResourceMappingDuplicateError() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("a/b/c", "Test");
- SingleJar singleJar = new SingleJar(mockFs);
- IllegalArgumentException e =
- assertThrows(
- IllegalArgumentException.class,
- () ->
- singleJar.run(
- ImmutableList.of(
- "--output",
- "output.jar",
- "--exclude_build_data",
- "--resources",
- "a/b/c",
- "a/b/c")));
- assertThat(e).hasMessageThat().contains("already contains a file named 'a/b/c'.");
- }
-
- @Test
- public void testResourceMappingDuplicateWarning() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- mockFs.addFile("a/b/c", "Test");
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar", "--exclude_build_data",
- "--warn_duplicate_resources", "--resources", "a/b/c", "a/b/c"));
- FakeZipFile expectedResult =
- new FakeZipFile()
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(
- JarFile.MANIFEST_NAME,
- new ManifestValidator("Manifest-Version: 1.0", "Created-By: blaze-singlejar"))
- .addEntry("a/", (String) null)
- .addEntry("a/b/", (String) null)
- .addEntry("a/b/c", "Test");
- expectedResult.assertSame(mockFs.toByteArray());
- }
-
- @Test
- public void testCanAddPreamble() throws IOException {
- MockSimpleFileSystem mockFs = new MockSimpleFileSystem("output.jar");
- String preamble = "WeThePeople";
- mockFs.addFile(preamble, preamble.getBytes(UTF_8));
- SingleJar singleJar = new SingleJar(mockFs);
- singleJar.run(ImmutableList.of("--output", "output.jar",
- "--java_launcher", preamble,
- "--main_class", "SomeClass"));
- FakeZipFile expectedResult =
- new FakeZipFile()
- .addPreamble(preamble.getBytes(UTF_8))
- .addEntry("META-INF/", EXTRA_FOR_META_INF)
- .addEntry(
- JarFile.MANIFEST_NAME,
- new ManifestValidator("Manifest-Version: 1.0", "Created-By: blaze-singlejar",
- "Main-Class: SomeClass"))
- .addEntry("build-data.properties", redactedBuildData("output.jar", "SomeClass"));
- expectedResult.assertSame(mockFs.toByteArray());
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTests.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTests.java
deleted file mode 100644
index 2eedeb9bec53a4..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SingleJarTests.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-
-import com.google.devtools.build.lib.testutil.ClasspathSuite;
-
-import org.junit.runner.RunWith;
-
-/**
- * A test-suite builder for this package.
- */
-@RunWith(ClasspathSuite.class)
-public class SingleJarTests {
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SlowConcatenateStrategy.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SlowConcatenateStrategy.java
deleted file mode 100644
index c82e89ad7ebc71..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/SlowConcatenateStrategy.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-
-import com.google.devtools.build.singlejar.ZipEntryFilter.CustomMergeStrategy;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import javax.annotation.concurrent.NotThreadSafe;
-
-/**
- * A strategy that merges a set of files by concatenating them. It inserts no
- * additional characters and copies bytes one by one. Used for testing.
- */
-@NotThreadSafe
-final class SlowConcatenateStrategy implements CustomMergeStrategy {
-
- @Override
- public void merge(InputStream in, OutputStream out) throws IOException {
- int nextByte;
- while ((nextByte = in.read()) != -1) {
- out.write(nextByte);
- }
- }
-
- @Override
- public void finish(OutputStream out) {
- // No need to do anything. All the data was already written.
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java
deleted file mode 100644
index b8e118df1bda74..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipCombinerTest.java
+++ /dev/null
@@ -1,800 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertThrows;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ListMultimap;
-import com.google.devtools.build.singlejar.ZipCombiner.OutputMode;
-import com.google.devtools.build.singlejar.ZipEntryFilter.CustomMergeStrategy;
-import com.google.devtools.build.zip.ExtraData;
-import com.google.devtools.build.zip.ZipFileEntry;
-import com.google.devtools.build.zip.ZipReader;
-import com.google.devtools.build.zip.ZipUtil;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.jar.JarOutputStream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Unit tests for {@link ZipCombiner}.
- */
-@RunWith(JUnit4.class)
-public class ZipCombinerTest {
- @Rule public TemporaryFolder tmp = new TemporaryFolder();
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- private File sampleZip() throws IOException {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.txt", "Hello World!");
- return writeInputStreamToFile(factory.toInputStream());
- }
-
- private File sampleZip2() throws IOException {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello2.txt", "Hello World 2!");
- return writeInputStreamToFile(factory.toInputStream());
- }
-
- private File sampleZipWithTwoEntries() throws IOException {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.txt", "Hello World!");
- factory.addFile("hello2.txt", "Hello World 2!");
- return writeInputStreamToFile(factory.toInputStream());
- }
-
- private File sampleZipWithOneUncompressedEntry() throws IOException {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.txt", "Hello World!", false);
- return writeInputStreamToFile(factory.toInputStream());
- }
-
- private File sampleZipWithTwoUncompressedEntries() throws IOException {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.txt", "Hello World!", false);
- factory.addFile("hello2.txt", "Hello World 2!", false);
- return writeInputStreamToFile(factory.toInputStream());
- }
-
- private File writeInputStreamToFile(InputStream in) throws IOException {
- File out = tmp.newFile();
- Files.copy(in, out.toPath(), StandardCopyOption.REPLACE_EXISTING);
- return out;
- }
-
- private void assertEntry(ZipInputStream zipInput, String filename, long time, byte[] content)
- throws IOException {
- ZipEntry zipEntry = zipInput.getNextEntry();
- assertThat(zipEntry).isNotNull();
- assertThat(zipEntry.getName()).isEqualTo(filename);
- assertThat(zipEntry.getTime()).isEqualTo(time);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int bytesCopied;
- while ((bytesCopied = zipInput.read(buffer)) != -1) {
- out.write(buffer, 0, bytesCopied);
- }
- assertThat(out.toByteArray()).isEqualTo(content);
- }
-
- private void assertEntry(ZipInputStream zipInput, String filename, byte[] content)
- throws IOException {
- assertEntry(zipInput, filename, ZipUtil.DOS_EPOCH, content);
- }
-
- private void assertEntry(ZipInputStream zipInput, String filename, String content)
- throws IOException {
- assertEntry(zipInput, filename, content.getBytes(ISO_8859_1));
- }
-
- private void assertEntry(ZipInputStream zipInput, String filename, Date date, String content)
- throws IOException {
- assertEntry(zipInput, filename, date.getTime(), content.getBytes(ISO_8859_1));
- }
-
- @Test
- public void testCompressedDontCare() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addZip(sampleZip());
- }
- FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", true);
- expectedResult.assertSame(out.toByteArray());
- }
-
- @Test
- public void testCompressedForceDeflate() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_DEFLATE, out)) {
- zipCombiner.addZip(sampleZip());
- }
- FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", true);
- expectedResult.assertSame(out.toByteArray());
- }
-
- @Test
- public void testCompressedForceStored() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_STORED, out)) {
- zipCombiner.addZip(sampleZip());
- }
- FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", false);
- expectedResult.assertSame(out.toByteArray());
- }
-
- @Test
- public void testUncompressedDontCare() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addZip(sampleZipWithOneUncompressedEntry());
- }
- FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", false);
- expectedResult.assertSame(out.toByteArray());
- }
-
- @Test
- public void testUncompressedForceDeflate() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_DEFLATE, out)) {
- zipCombiner.addZip(sampleZipWithOneUncompressedEntry());
- }
- FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", true);
- expectedResult.assertSame(out.toByteArray());
- }
-
- @Test
- public void testUncompressedForceStored() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(OutputMode.FORCE_STORED, out)) {
- zipCombiner.addZip(sampleZipWithOneUncompressedEntry());
- }
- FakeZipFile expectedResult = new FakeZipFile().addEntry("hello.txt", "Hello World!", false);
- expectedResult.assertSame(out.toByteArray());
- }
-
- @Test
- public void testCopyTwoEntries() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testCopyTwoUncompressedEntries() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testCombine() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addZip(sampleZip());
- zipCombiner.addZip(sampleZip2());
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testDuplicateEntry() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addZip(sampleZip());
- zipCombiner.addZip(sampleZip());
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testBadZipFileNoEntry() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- thrown.expect(ZipException.class);
- thrown.expectMessage("It does not contain an end of central directory record.");
- zipCombiner.addZip(writeInputStreamToFile(new ByteArrayInputStream(new byte[] {1, 2, 3, 4})));
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- private InputStream asStream(String content) {
- return new ByteArrayInputStream(content.getBytes(UTF_8));
- }
-
- @Test
- public void testAddFile() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addFile("hello.txt", ZipCombiner.DOS_EPOCH, asStream("Hello World!"));
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testAddFileAndDuplicateZipEntry() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- zipCombiner.addFile("hello.txt", ZipCombiner.DOS_EPOCH, asStream("Hello World!"));
- zipCombiner.addZip(sampleZip());
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- static final class MergeStrategyPlaceHolder implements CustomMergeStrategy {
-
- @Override
- public void finish(OutputStream out) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void merge(InputStream in, OutputStream out) {
- throw new UnsupportedOperationException();
- }
- }
-
- private static final CustomMergeStrategy COPY_PLACEHOLDER = new MergeStrategyPlaceHolder();
- private static final CustomMergeStrategy SKIP_PLACEHOLDER = new MergeStrategyPlaceHolder();
-
- /**
- * A mock implementation that either uses the specified behavior or calls
- * through to copy.
- */
- class MockZipEntryFilter implements ZipEntryFilter {
-
- private Date date = ZipCombiner.DOS_EPOCH;
- private final List calls = new ArrayList<>();
- // File name to merge strategy map.
- private final Map behavior =
- new HashMap<>();
- private final ListMultimap renameMap = ArrayListMultimap.create();
-
- @Override
- public void accept(String filename, StrategyCallback callback) throws IOException {
- calls.add(filename);
- CustomMergeStrategy strategy = behavior.get(filename);
- if (strategy == null) {
- callback.copy(null);
- } else if (strategy == COPY_PLACEHOLDER) {
- List names = renameMap.get(filename);
- if (names != null && !names.isEmpty()) {
- // rename to the next name in list of replacement names.
- String newName = names.get(0);
- callback.rename(newName, null);
- // Unless this is the last replacment names, we pop the used name.
- // The lastreplacement name applies any additional entries.
- if (names.size() > 1) {
- names.remove(0);
- }
- } else {
- callback.copy(null);
- }
- } else if (strategy == SKIP_PLACEHOLDER) {
- callback.skip();
- } else {
- callback.customMerge(date, strategy);
- }
- }
- }
-
- @Test
- public void testCopyCallsFilter() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZip());
- }
- assertThat(mockFilter.calls).containsExactly("hello.txt");
- }
-
- @Test
- public void testDuplicateEntryCallsFilterOnce() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZip());
- zipCombiner.addZip(sampleZip());
- }
- assertThat(mockFilter.calls).containsExactly("hello.txt");
- }
-
- @Test
- public void testMergeStrategy() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", new ConcatenateStrategy());
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZip());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt").inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertEntry(zipInput, "hello.txt", "Hello World!\nHello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testMergeStrategyWithUncompressedFiles() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", new ConcatenateStrategy());
- mockFilter.behavior.put("hello2.txt", SKIP_PLACEHOLDER);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- }
- assertThat(mockFilter.calls).isEqualTo(Arrays.asList("hello.txt", "hello2.txt"));
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!\nHello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testMergeStrategyWithSlowCopy() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", new SlowConcatenateStrategy());
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZip());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls).isEqualTo(Arrays.asList("hello.txt", "hello2.txt"));
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertEntry(zipInput, "hello.txt", "Hello World!Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testMergeStrategyWithUncompressedFilesAndSlowCopy() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", new SlowConcatenateStrategy());
- mockFilter.behavior.put("hello2.txt", SKIP_PLACEHOLDER);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- }
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt").inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- private File specialZipWithMinusOne() throws IOException {
- ZipFactory factory = new ZipFactory();
- factory.addFile("hello.txt", new byte[] {-1});
- return writeInputStreamToFile(factory.toInputStream());
- }
-
- @Test
- public void testMergeStrategyWithSlowCopyAndNegativeBytes() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", new SlowConcatenateStrategy());
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(specialZipWithMinusOne());
- }
- assertThat(mockFilter.calls).containsExactly("hello.txt");
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", new byte[] { -1 });
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testCopyDateHandling() throws IOException {
- final Date date = new GregorianCalendar(2009, 8, 2, 0, 0, 0).getTime();
- ZipEntryFilter mockFilter =
- new ZipEntryFilter() {
- @Override
- public void accept(String filename, StrategyCallback callback) throws IOException {
- assertThat(filename).isEqualTo("hello.txt");
- callback.copy(date);
- }
- };
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZip());
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", date, "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testMergeDateHandling() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", new ConcatenateStrategy());
- mockFilter.date = new GregorianCalendar(2009, 8, 2, 0, 0, 0).getTime();
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZip());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls).containsExactly("hello.txt", "hello2.txt").inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello2.txt", ZipCombiner.DOS_EPOCH, "Hello World 2!");
- assertEntry(zipInput, "hello.txt", mockFilter.date, "Hello World!\nHello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- @Test
- public void testDuplicateCallThrowsException() throws IOException {
- ZipEntryFilter badFilter = new ZipEntryFilter() {
- @Override
- public void accept(String filename, StrategyCallback callback) throws IOException {
- // Duplicate callback call.
- callback.skip();
- callback.copy(null);
- }
- };
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(badFilter, out)) {
- assertThrows(IllegalStateException.class, () -> zipCombiner.addZip(sampleZip()));
- }
- }
-
- @Test
- public void testNoCallThrowsException() throws IOException {
- ZipEntryFilter badFilter = new ZipEntryFilter() {
- @Override
- public void accept(String filename, StrategyCallback callback) {
- // No callback call.
- }
- };
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(badFilter, out)) {
- assertThrows(IllegalStateException.class, () -> zipCombiner.addZip(sampleZip()));
- }
- }
-
- // This test verifies that if an entry A is renamed as A (identy mapping),
- // then subsequent entries named A are still subject to filtering.
- // Note: this is different from a copy, where subsequent entries are skipped.
- @Test
- public void testRenameIdentityMapping() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
- mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
- mockFilter.renameMap.put("hello.txt", "hello.txt"); // identity rename, not copy
- mockFilter.renameMap.put("hello2.txt", "hello2.txt"); // identity rename, not copy
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls)
- .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
- .inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello.txt", "Hello World!");
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- // This test verifies that multiple entries with the same name can be
- // renamed to unique names.
- @Test
- public void testRenameNoConflictMapping() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
- mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
- mockFilter.renameMap.putAll("hello.txt", Arrays.asList("hello1.txt", "hello2.txt"));
- mockFilter.renameMap.putAll("hello2.txt", Arrays.asList("world1.txt", "world2.txt"));
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls)
- .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
- .inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello1.txt", "Hello World!");
- assertEntry(zipInput, "world1.txt", "Hello World 2!");
- assertEntry(zipInput, "hello2.txt", "Hello World!");
- assertEntry(zipInput, "world2.txt", "Hello World 2!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- // This tests verifies that an attempt to rename an entry to a
- // name already written, results in the entry being skipped, after
- // calling the filter.
- @Test
- public void testRenameSkipUsedName() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
- mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
- mockFilter.renameMap.putAll("hello.txt",
- Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
- mockFilter.renameMap.put("hello2.txt", "hello2.txt");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls)
- .containsExactly(
- "hello.txt", "hello2.txt", "hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
- .inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello1.txt", "Hello World!");
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertEntry(zipInput, "hello3.txt", "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- // This tests verifies that if an entry has been copied, then
- // further entries of the same name are skipped (filter not invoked),
- // and entries renamed to the same name are skipped (after calling filter).
- @Test
- public void testRenameAndCopy() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
- mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
- mockFilter.renameMap.putAll("hello.txt",
- Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls)
- .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello.txt")
- .inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello1.txt", "Hello World!");
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertEntry(zipInput, "hello3.txt", "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- // This tests verifies that if an entry has been skipped, then
- // further entries of the same name are skipped (filter not invoked),
- // and entries renamed to the same name are skipped (after calling filter).
- @Test
- public void testRenameAndSkip() throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
- mockFilter.behavior.put("hello2.txt", SKIP_PLACEHOLDER);
- mockFilter.renameMap.putAll("hello.txt",
- Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- zipCombiner.addZip(sampleZipWithTwoEntries());
- }
- assertThat(mockFilter.calls)
- .containsExactly("hello.txt", "hello2.txt", "hello.txt", "hello.txt")
- .inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello1.txt", "Hello World!");
- assertEntry(zipInput, "hello3.txt", "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- // This test verifies that renaming works when input and output
- // disagree on compression method. This is the simple case, where
- // content is read and rewritten, and no header repair is needed.
- @Test
- public void testRenameWithUncompressedFiles () throws IOException {
- MockZipEntryFilter mockFilter = new MockZipEntryFilter();
- mockFilter.behavior.put("hello.txt", COPY_PLACEHOLDER);
- mockFilter.behavior.put("hello2.txt", COPY_PLACEHOLDER);
- mockFilter.renameMap.putAll("hello.txt",
- Arrays.asList("hello1.txt", "hello2.txt", "hello3.txt"));
- mockFilter.renameMap.put("hello2.txt", "hello2.txt");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(mockFilter, out)) {
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- zipCombiner.addZip(sampleZipWithTwoUncompressedEntries());
- }
- assertThat(mockFilter.calls)
- .containsExactly(
- "hello.txt", "hello2.txt", "hello.txt", "hello2.txt", "hello.txt", "hello2.txt")
- .inOrder();
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- assertEntry(zipInput, "hello1.txt", "Hello World!");
- assertEntry(zipInput, "hello2.txt", "Hello World 2!");
- assertEntry(zipInput, "hello3.txt", "Hello World!");
- assertThat(zipInput.getNextEntry()).isNull();
- }
-
- // The next two tests check that ZipCombiner can handle a ZIP with an data
- // descriptor marker in the compressed data, i.e. that it does not scan for
- // the data descriptor marker. It's unfortunately a bit tricky to create such
- // a ZIP.
- private static final int LOCAL_FILE_HEADER_MARKER = 0x04034b50;
-
- // Create a ZIP with a partial entry.
- private InputStream zipWithPartialEntry() {
- ByteBuffer out = ByteBuffer.wrap(new byte[32]).order(ByteOrder.LITTLE_ENDIAN);
- out.clear();
- // file header
- out.putInt(LOCAL_FILE_HEADER_MARKER); // file header signature
- out.putShort((short) 6); // version to extract
- out.putShort((short) 0); // general purpose bit flag
- out.putShort((short) ZipOutputStream.STORED); // compression method
- out.putShort((short) 0); // mtime (00:00:00)
- out.putShort((short) 0x21); // mdate (1.1.1980)
- out.putInt(0); // crc32
- out.putInt(10); // compressed size
- out.putInt(10); // uncompressed size
- out.putShort((short) 1); // file name length
- out.putShort((short) 0); // extra field length
- out.put((byte) 'a'); // file name
-
- // file contents
- out.put((byte) 0x01);
- // Unexpected end of file.
-
- return new ByteArrayInputStream(out.array());
- }
-
- @Test
- public void testBadZipFilePartialEntry() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner = new ZipCombiner(out)) {
- thrown.expect(ZipException.class);
- thrown.expectMessage("It does not contain an end of central directory record.");
- zipCombiner.addZip(writeInputStreamToFile(zipWithPartialEntry()));
- }
- }
-
- @Test
- public void testZipCombinerAgainstJavaUtil() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (JarOutputStream jarOut = new JarOutputStream(out)) {
- ZipEntry entry;
- entry = new ZipEntry("META-INF/");
- entry.setTime(ZipCombiner.DOS_EPOCH.getTime());
- entry.setMethod(JarOutputStream.STORED);
- entry.setSize(0);
- entry.setCompressedSize(0);
- entry.setCrc(0);
- jarOut.putNextEntry(entry);
- entry = new ZipEntry("META-INF/MANIFEST.MF");
- entry.setTime(ZipCombiner.DOS_EPOCH.getTime());
- entry.setMethod(JarOutputStream.DEFLATED);
- jarOut.putNextEntry(entry);
- jarOut.write(new byte[] {1, 2, 3, 4});
- }
- File javaFile = writeInputStreamToFile(new ByteArrayInputStream(out.toByteArray()));
- out.reset();
-
- try (ZipCombiner zipcombiner = new ZipCombiner(out)) {
- zipcombiner.addDirectory("META-INF/", ZipCombiner.DOS_EPOCH,
- new ExtraData[] {new ExtraData((short) 0xCAFE, new byte[0])});
- zipcombiner.addFile("META-INF/MANIFEST.MF", ZipCombiner.DOS_EPOCH,
- new ByteArrayInputStream(new byte[] {1, 2, 3, 4}));
- }
- File zipCombinerFile = writeInputStreamToFile(new ByteArrayInputStream(out.toByteArray()));
- byte[] zipCombinerRaw = out.toByteArray();
-
- new ZipTester(zipCombinerRaw).validate();
- assertZipFilesEquivalent(zipCombinerFile, javaFile);
- }
-
- void assertZipFilesEquivalent(File a, File b) throws IOException {
- try (ZipReader x = new ZipReader(a);
- ZipReader y = new ZipReader(b)) {
- Collection xEntries = x.entries();
- Collection yEntries = y.entries();
- assertThat(xEntries).hasSize(yEntries.size());
- Iterator xIter = xEntries.iterator();
- Iterator yIter = yEntries.iterator();
- for (int i = 0; i < xEntries.size(); i++) {
- assertZipEntryEquivalent(xIter.next(), yIter.next());
- }
- }
- }
-
- void assertZipEntryEquivalent(ZipFileEntry x, ZipFileEntry y) {
- assertThat(x.getComment()).isEqualTo(y.getComment());
- assertThat(x.getCompressedSize()).isEqualTo(y.getCompressedSize());
- assertThat(x.getCrc()).isEqualTo(y.getCrc());
- assertThat(x.getExternalAttributes()).isEqualTo(y.getExternalAttributes());
- // The JDK adds different extra data to zip files on different platforms, so we don't compare
- // the extra data.
- assertThat(x.getInternalAttributes()).isEqualTo(y.getInternalAttributes());
- assertThat(x.getMethod()).isEqualTo(y.getMethod());
- assertThat(x.getName()).isEqualTo(y.getName());
- assertThat(x.getSize()).isEqualTo(y.getSize());
- assertThat(x.getTime()).isEqualTo(y.getTime());
- assertThat(x.getVersion()).isEqualTo(y.getVersion());
- assertThat(x.getVersionNeeded()).isEqualTo(y.getVersionNeeded());
- // Allow general purpose bit 3 (data descriptor) used in jdk7 to differ.
- // Allow general purpose bit 11 (UTF-8 encoding) used in jdk7 to differ.
- assertThat(x.getFlags() | (1 << 3) | (1 << 11))
- .isEqualTo(y.getFlags() | (1 << 3) | (1 << 11));
- }
-
- /**
- * Ensures that the code that grows the central directory and the code that patches it is not
- * obviously broken.
- */
- @Test
- public void testLotsOfFiles() throws IOException {
- int fileCount = 100;
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (ZipCombiner zipCombiner =
- new ZipCombiner(OutputMode.DONT_CARE, new CopyEntryFilter(), out)) {
- for (int i = 0; i < fileCount; i++) {
- zipCombiner.addFile("hello" + i, ZipCombiner.DOS_EPOCH, asStream("Hello " + i + "!"));
- }
- }
- ZipInputStream zipInput = new ZipInputStream(new ByteArrayInputStream(out.toByteArray()));
- for (int i = 0; i < fileCount; i++) {
- assertEntry(zipInput, "hello" + i, "Hello " + i + "!");
- }
- assertThat(zipInput.getNextEntry()).isNull();
- new ZipTester(out.toByteArray()).validate();
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipFactory.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipFactory.java
deleted file mode 100644
index e102d8a435aa30..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipFactory.java
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.CRC32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-
-/**
- * A helper class to create zip files for testing.
- */
-public class ZipFactory {
-
- static class Entry {
- private final String name;
- private final byte[] content;
- private final boolean compressed;
- private Entry(String name, byte[] content, boolean compressed) {
- this.name = name;
- this.content = content;
- this.compressed = compressed;
- }
- }
-
- private final List entries = new ArrayList<>();
-
- // Assumes that content was created locally. Does not perform a defensive copy!
- private void addEntry(String name, byte[] content, boolean compressed) {
- entries.add(new Entry(name, content, compressed));
- }
-
- public ZipFactory addFile(String name, String content) {
- addEntry(name, content.getBytes(ISO_8859_1), true);
- return this;
- }
-
- public ZipFactory addFile(String name, byte[] content) {
- addEntry(name, content.clone(), true);
- return this;
- }
-
- public ZipFactory addFile(String name, String content, boolean compressed) {
- addEntry(name, content.getBytes(ISO_8859_1), compressed);
- return this;
- }
-
- public ZipFactory addFile(String name, byte[] content, boolean compressed) {
- addEntry(name, content.clone(), compressed);
- return this;
- }
-
- public byte[] toByteArray() {
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ZipOutputStream zipper = new ZipOutputStream(out);
- for (Entry entry : entries) {
- ZipEntry zipEntry = new ZipEntry(entry.name);
- if (entry.compressed) {
- zipEntry.setMethod(ZipEntry.DEFLATED);
- } else {
- zipEntry.setMethod(ZipEntry.STORED);
- zipEntry.setSize(entry.content.length);
- zipEntry.setCrc(calculateCrc32(entry.content));
- }
- zipEntry.setTime(ZipCombiner.DOS_EPOCH.getTime());
- zipper.putNextEntry(zipEntry);
- zipper.write(entry.content);
- zipper.closeEntry();
- }
- zipper.close();
- return out.toByteArray();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public InputStream toInputStream() {
- return new ByteArrayInputStream(toByteArray());
- }
-
- public static long calculateCrc32(byte[] content) {
- CRC32 crc = new CRC32();
- crc.update(content);
- return crc.getValue();
- }
-}
diff --git a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipTester.java b/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipTester.java
deleted file mode 100644
index f2e8b3a8445dd6..00000000000000
--- a/src/java_tools/singlejar/javatests/com/google/devtools/build/singlejar/ZipTester.java
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.singlejar;
-
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.CRC32;
-import java.util.zip.DataFormatException;
-import java.util.zip.Inflater;
-
-/**
- * A helper class to validate zip files and provide reasonable diagnostics (better than what zip
- * does). We might want to make this into a fully-fledged binary some day.
- */
-final class ZipTester {
-
- // The following constants are ZIP-specific.
- private static final int LOCAL_FILE_HEADER_MARKER = 0x04034b50;
- private static final int DATA_DESCRIPTOR_MARKER = 0x08074b50;
- private static final int CENTRAL_DIRECTORY_MARKER = 0x02014b50;
- private static final int END_OF_CENTRAL_DIRECTORY_MARKER = 0x06054b50;
-
- private static final int FILE_HEADER_BUFFER_SIZE = 26; // without marker
- private static final int DATA_DESCRIPTOR_BUFFER_SIZE = 12; // without marker
-
- private static final int DIRECTORY_ENTRY_BUFFER_SIZE = 42; // without marker
- private static final int END_OF_CENTRAL_DIRECTORY_BUFFER_SIZE = 18; // without marker
-
- // Set if the size, compressed size and CRC are set to zero, and present in
- // the data descriptor after the data.
- private static final int SIZE_MASKED_FLAG = 1 << 3;
-
- private static final int STORED_METHOD = 0;
- private static final int DEFLATE_METHOD = 8;
-
- private static final int VERSION_STORED = 10; // Version 1.0
- private static final int VERSION_DEFLATE = 20; // Version 2.0
-
- private static class Entry {
- private final long pos;
- private final String name;
- private final int flags;
- private final int method;
- private final int dosTime;
- Entry(long pos, String name, int flags, int method, int dosTime) {
- this.pos = pos;
- this.name = name;
- this.flags = flags;
- this.method = method;
- this.dosTime = dosTime;
- }
- }
-
- private final InputStream in;
- private final byte[] buffer = new byte[1024];
- private int bufferLength;
- private int bufferOffset;
- private long pos;
-
- private List entries = new ArrayList();
-
- public ZipTester(InputStream in) {
- this.in = in;
- }
-
- public ZipTester(byte[] data) {
- this(new ByteArrayInputStream(data));
- }
-
- private void warn(String msg) {
- System.err.println("WARNING: " + msg);
- }
-
- private void readMoreData(String action) throws IOException {
- if ((bufferLength > 0) && (bufferOffset > 0)) {
- System.arraycopy(buffer, bufferOffset, buffer, 0, bufferLength);
- }
- if (bufferLength >= buffer.length) {
- // The buffer size is specifically chosen to avoid this situation.
- throw new AssertionError("Internal error: buffer overrun.");
- }
- bufferOffset = 0;
- int bytesRead = in.read(buffer, bufferLength, buffer.length - bufferLength);
- if (bytesRead <= 0) {
- throw new IOException("Unexpected end of file, while " + action);
- }
- bufferLength += bytesRead;
- }
-
- private int readByte(String action) throws IOException {
- if (bufferLength == 0) {
- readMoreData(action);
- }
- byte result = buffer[bufferOffset];
- bufferOffset++; bufferLength--;
- pos++;
- return result & 0xff;
- }
-
- private long getUnsignedInt(String action) throws IOException {
- int a = readByte(action);
- int b = readByte(action);
- int c = readByte(action);
- int d = readByte(action);
- return ((d << 24) | (c << 16) | (b << 8) | a) & 0xffffffffL;
- }
-
- private long getUnsignedInt(byte[] source, int offset) {
- int a = source[offset + 0] & 0xff;
- int b = source[offset + 1] & 0xff;
- int c = source[offset + 2] & 0xff;
- int d = source[offset + 3] & 0xff;
- return ((d << 24) | (c << 16) | (b << 8) | a) & 0xffffffffL;
- }
-
- private void readFully(byte[] buffer, String action) throws IOException {
- for (int i = 0; i < buffer.length; i++) {
- buffer[i] = (byte) readByte(action);
- }
- }
-
- private void skip(long length, String action) throws IOException {
- for (long i = 0; i < length; i++) {
- readByte(action);
- }
- }
-
- private int getUnsignedShort(byte[] source, int offset) {
- int a = source[offset + 0] & 0xff;
- int b = source[offset + 1] & 0xff;
- return (b << 8) | a;
- }
-
- private class DeflateInputStream extends InputStream {
-
- private final byte[] singleByteBuffer = new byte[1];
- private int consumedBytes;
- private final Inflater inflater = new Inflater(true);
- private long totalBytesRead;
-
- private int inflateData(byte[] dest, int off, int len)
- throws IOException {
- consumedBytes = 0;
- int bytesProduced = 0;
- int bytesConsumed = 0;
- while ((bytesProduced == 0) && !inflater.finished()) {
- inflater.setInput(buffer, bufferOffset + bytesConsumed, bufferLength - bytesConsumed);
- int remainingBefore = inflater.getRemaining();
- try {
- bytesProduced = inflater.inflate(dest, off, len);
- } catch (DataFormatException e) {
- throw new IOException("Invalid deflate stream in ZIP file.", e);
- }
- bytesConsumed += remainingBefore - inflater.getRemaining();
- consumedBytes = bytesConsumed;
- if (bytesProduced == 0) {
- if (inflater.needsDictionary()) {
- // The DEFLATE algorithm as used in the ZIP file format does not
- // require an additional dictionary.
- throw new AssertionError("Inflater unexpectedly requires a dictionary.");
- } else if (inflater.needsInput()) {
- readMoreData("need more data for deflate");
- } else if (inflater.finished()) {
- return 0;
- } else {
- // According to the Inflater specification, this cannot happen.
- throw new AssertionError("Inflater unexpectedly produced no output.");
- }
- }
- }
- return bytesProduced;
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- if (inflater.finished()) {
- return -1;
- }
- int length = inflateData(b, off, len);
- totalBytesRead += consumedBytes;
- bufferLength -= consumedBytes;
- bufferOffset += consumedBytes;
- pos += consumedBytes;
- return length == 0 ? -1 : length;
- }
-
- @Override
- public int read() throws IOException {
- int bytesRead = read(singleByteBuffer, 0, 1);
- return (bytesRead == -1) ? -1 : (singleByteBuffer[0] & 0xff);
- }
- }
-
- private void readEntry() throws IOException {
- long entrypos = pos - 4;
- String entryDesc = "file entry at " + Long.toHexString(entrypos);
- byte[] entryBuffer = new byte[FILE_HEADER_BUFFER_SIZE];
- readFully(entryBuffer, "reading file header");
- int versionToExtract = getUnsignedShort(entryBuffer, 0);
- int flags = getUnsignedShort(entryBuffer, 2);
- int method = getUnsignedShort(entryBuffer, 4);
- int dosTime = (int) getUnsignedInt(entryBuffer, 6);
- int crc32 = (int) getUnsignedInt(entryBuffer, 10);
- long compressedSize = getUnsignedInt(entryBuffer, 14);
- long uncompressedSize = getUnsignedInt(entryBuffer, 18);
- int filenameLength = getUnsignedShort(entryBuffer, 22);
- int extraLength = getUnsignedShort(entryBuffer, 24);
-
- byte[] filename = new byte[filenameLength];
- readFully(filename, "reading file name");
- skip(extraLength, "skipping extra data");
-
- String name = new String(filename, "UTF-8");
- for (int i = 0; i < filename.length; i++) {
- if ((filename[i] < ' ') || (filename[i] > 127)) {
- warn(entryDesc + ": file name has unexpected non-ascii characters");
- }
- }
- entryDesc = "file entry '" + name + "' at " + Long.toHexString(entrypos);
-
- if ((method != STORED_METHOD) && (method != DEFLATE_METHOD)) {
- throw new IOException(entryDesc + ": unknown method " + method);
- }
- if ((flags != 0) && (flags != SIZE_MASKED_FLAG)) {
- throw new IOException(entryDesc + ": unknown flags " + flags);
- }
- if ((method == STORED_METHOD) && (versionToExtract != VERSION_STORED)) {
- warn(entryDesc + ": unexpected version to extract for stored entry " + versionToExtract);
- }
- if ((method == DEFLATE_METHOD) && (versionToExtract != VERSION_DEFLATE)) {
-// warn(entryDesc + ": unexpected version to extract for deflated entry " + versionToExtract);
- }
-
- if (method == STORED_METHOD) {
- if (compressedSize != uncompressedSize) {
- throw new IOException(entryDesc + ": stored entries should have identical compressed and "
- + "uncompressed sizes");
- }
- skip(compressedSize, entryDesc + "skipping data");
- } else {
- // No OS resources are actually allocated.
- @SuppressWarnings("resource") DeflateInputStream deflater = new DeflateInputStream();
- long generatedBytes = 0;
- byte[] deflated = new byte[1024];
- int readBytes;
- CRC32 crc = new CRC32();
- while ((readBytes = deflater.read(deflated)) > 0) {
- crc.update(deflated, 0, readBytes);
- generatedBytes += readBytes;
- }
- int actualCrc32 = (int) crc.getValue();
- long consumedBytes = deflater.totalBytesRead;
- if (flags == SIZE_MASKED_FLAG) {
- long id = getUnsignedInt("reading footer marker");
- if (id != DATA_DESCRIPTOR_MARKER) {
- throw new IOException(entryDesc + ": expected footer at " + Long.toHexString(pos - 4)
- + ", but found " + Long.toHexString(id));
- }
- byte[] footer = new byte[DATA_DESCRIPTOR_BUFFER_SIZE];
- readFully(footer, "reading footer");
- crc32 = (int) getUnsignedInt(footer, 0);
- compressedSize = getUnsignedInt(footer, 4);
- uncompressedSize = getUnsignedInt(footer, 8);
- }
-
- if (consumedBytes != compressedSize) {
- throw new IOException(entryDesc + ": amount of compressed data does not match value "
- + "specified in the zip (specified: " + compressedSize + ", actual: " + consumedBytes
- + ")");
- }
- if (generatedBytes != uncompressedSize) {
- throw new IOException(entryDesc + ": amount of uncompressed data does not match value "
- + "specified in the zip (specified: " + uncompressedSize + ", actual: "
- + generatedBytes + ")");
- }
- if (crc32 != actualCrc32) {
- throw new IOException(entryDesc + ": specified crc checksum does not match actual check "
- + "sum");
- }
- }
- entries.add(new Entry(entrypos, name, flags, method, dosTime));
- }
-
- @SuppressWarnings("unused") // A couple of unused local variables.
- private void validateCentralDirectoryEntry(Entry entry) throws IOException {
- long entrypos = pos - 4;
- String entryDesc = "file directory entry '" + entry.name + "' at " + Long.toHexString(entrypos);
-
- byte[] entryBuffer = new byte[DIRECTORY_ENTRY_BUFFER_SIZE];
- readFully(entryBuffer, "reading central directory entry");
- int versionMadeBy = getUnsignedShort(entryBuffer, 0);
- int versionToExtract = getUnsignedShort(entryBuffer, 2);
- int flags = getUnsignedShort(entryBuffer, 4);
- int method = getUnsignedShort(entryBuffer, 6);
- int dosTime = (int) getUnsignedInt(entryBuffer, 8);
- int crc32 = (int) getUnsignedInt(entryBuffer, 12);
- long compressedSize = getUnsignedInt(entryBuffer, 16);
- long uncompressedSize = getUnsignedInt(entryBuffer, 20);
- int filenameLength = getUnsignedShort(entryBuffer, 24);
- int extraLength = getUnsignedShort(entryBuffer, 26);
- int commentLength = getUnsignedShort(entryBuffer, 28);
- int diskNumberStart = getUnsignedShort(entryBuffer, 30);
- int internalAttributes = getUnsignedShort(entryBuffer, 32);
- int externalAttributes = (int) getUnsignedInt(entryBuffer, 34);
- long offset = getUnsignedInt(entryBuffer, 38);
-
- byte[] filename = new byte[filenameLength];
- readFully(filename, "reading file name");
- skip(extraLength, "skipping extra data");
- String name = new String(filename, "UTF-8");
-
- if (!name.equals(entry.name)) {
- throw new IOException(entryDesc + ": file name in central directory does not match original "
- + "name");
- }
- if (offset != entry.pos) {
- throw new IOException(entryDesc);
- }
- if (flags != entry.flags) {
- throw new IOException(entryDesc);
- }
- if (method != entry.method) {
- throw new IOException(entryDesc);
- }
- if (dosTime != entry.dosTime) {
- throw new IOException(entryDesc);
- }
- }
-
- private void validateCentralDirectory() throws IOException {
- boolean first = true;
- for (Entry entry : entries) {
- if (first) {
- first = false;
- } else {
- long id = getUnsignedInt("reading marker");
- if (id != CENTRAL_DIRECTORY_MARKER) {
- throw new IOException();
- }
- }
- validateCentralDirectoryEntry(entry);
- }
- }
-
- @SuppressWarnings("unused") // A couple of unused local variables.
- private void validateEndOfCentralDirectory() throws IOException {
- long id = getUnsignedInt("expecting end of central directory");
- byte[] entryBuffer = new byte[END_OF_CENTRAL_DIRECTORY_BUFFER_SIZE];
- readFully(entryBuffer, "reading end of central directory");
- int diskNumber = getUnsignedShort(entryBuffer, 0);
- int startDiskNumber = getUnsignedShort(entryBuffer, 2);
- int numEntries = getUnsignedShort(entryBuffer, 4);
- int numTotalEntries = getUnsignedShort(entryBuffer, 6);
- long centralDirectorySize = getUnsignedInt(entryBuffer, 8);
- long centralDirectoryOffset = getUnsignedInt(entryBuffer, 12);
- int commentLength = getUnsignedShort(entryBuffer, 16);
- if (diskNumber != 0) {
- throw new IOException(String.format("diskNumber=%d", diskNumber));
- }
- if (startDiskNumber != 0) {
- throw new IOException(String.format("startDiskNumber=%d", diskNumber));
- }
- if (numEntries != numTotalEntries) {
- throw new IOException(String.format("numEntries=%d numTotalEntries=%d",
- numEntries, numTotalEntries));
- }
- if (numEntries != (entries.size() % 0x10000)) {
- throw new IOException("bad number of entries in central directory footer");
- }
- if (numTotalEntries != (entries.size() % 0x10000)) {
- throw new IOException("bad number of entries in central directory footer");
- }
- if (commentLength != 0) {
- throw new IOException("Zip file comment is unexpected");
- }
- if (id != END_OF_CENTRAL_DIRECTORY_MARKER) {
- throw new IOException("Expected end of central directory marker");
- }
- }
-
- public void validate() throws IOException {
- while (true) {
- long id = getUnsignedInt("reading marker");
- if (id == LOCAL_FILE_HEADER_MARKER) {
- readEntry();
- } else if (id == CENTRAL_DIRECTORY_MARKER) {
- validateCentralDirectory();
- validateEndOfCentralDirectory();
- return;
- } else {
- throw new IOException("unexpected result for marker: "
- + Long.toHexString(id) + " at position " + Long.toHexString(pos - 4));
- }
- }
- }
-}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/BUILD b/src/test/java/com/google/devtools/build/android/desugar/BUILD
index 55c1831fa2fab2..b3108e9c832d08 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/BUILD
+++ b/src/test/java/com/google/devtools/build/android/desugar/BUILD
@@ -1879,16 +1879,11 @@ grep lambda $(location subclass_disassembled.txt) > $(location subclass_lambda_s
],
)
-_SINGLEJAR_IMPLS = {
- "singlejar": "//src/tools/singlejar:singlejar_local",
- "JavaSingleJar": "//src/java_tools/singlejar:SingleJar",
-}
-
-[sh_test(
- name = "desugar_deps_consistent_%s_test" % label,
+sh_test(
+ name = "desugar_deps_consistent_singlejar_test",
srcs = ["desugar_deps_consistency_test.sh"],
args = [
- "$(location %s)" % singlejar,
+ "$(location //src/tools/singlejar:singlejar_local)",
"$(location @bazel_tools//tools/jdk:jar)",
"$(location :testdata_desugared_default_methods.jar)",
"$(location :separate_java8_desugared_default_methods.jar)",
@@ -1898,19 +1893,19 @@ _SINGLEJAR_IMPLS = {
":guava_at_head_desugared.jar",
":separate_java8_desugared_default_methods.jar",
":testdata_desugared_default_methods.jar",
- singlejar,
+ "//src/tools/singlejar:singlejar_local",
"@bazel_tools//tools/jdk:jar",
],
tags = ["no_windows"],
-) for label, singlejar in _SINGLEJAR_IMPLS.items()]
+)
# Tests that deps checking fails due to missing default method: libseparate_java8.jar defines
# default methods which testdata_desugared_default_methods.jar assumes have been moved to companion.
-[sh_test(
- name = "desugar_deps_missing_%s_fail_test" % label,
+sh_test(
+ name = "desugar_deps_missing_singlejar_fail_test",
srcs = ["desugar_deps_consistency_test.sh"],
args = [
- "$(location %s)" % singlejar,
+ "$(location //src/tools/singlejar:singlejar_local)",
"$(location @bazel_tools//tools/jdk:jar)",
"$(location :testdata_desugared_default_methods.jar)",
"$(location :libseparate_java8.jar)",
@@ -1920,36 +1915,36 @@ _SINGLEJAR_IMPLS = {
":guava_at_head_desugared.jar",
":libseparate_java8.jar",
":testdata_desugared_default_methods.jar",
- singlejar,
+ "//src/tools/singlejar:singlejar_local",
"@bazel_tools//tools/jdk:jar",
],
tags = ["no_windows"],
-) for label, singlejar in _SINGLEJAR_IMPLS.items()]
+)
# Regression test for b/68049457 with deps checking failing due to missing static method:
# b68049457_caller_desugared.jar assumes presence of companion class that's missing (in fact,
# the whole Jar is missing, similar to neverlink situations).
-[sh_test(
- name = "desugar_deps_b68049457_%s_fail_test" % label,
+sh_test(
+ name = "desugar_deps_b68049457_singlejar_fail_test",
srcs = ["desugar_deps_consistency_test.sh"],
args = [
- "$(location %s)" % singlejar,
+ "$(location //src/tools/singlejar:singlejar_local)",
"$(location @bazel_tools//tools/jdk:jar)",
"$(location :b68049457_caller_desugared.jar)",
],
data = [
":b68049457_caller_desugared.jar",
- singlejar,
+ "//src/tools/singlejar:singlejar_local",
"@bazel_tools//tools/jdk:jar",
],
tags = ["no_windows"],
-) for label, singlejar in _SINGLEJAR_IMPLS.items()]
+)
-[sh_test(
- name = "desugar_deps_missed_default_method_%s_fail_test" % label,
+sh_test(
+ name = "desugar_deps_missed_default_method_singlejar_fail_test",
srcs = ["desugar_deps_consistency_test.sh"],
args = [
- "$(location %s)" % singlejar,
+ "$(location //src/tools/singlejar:singlejar_local)",
"$(location @bazel_tools//tools/jdk:jar)",
"$(location :testdata_desugared_with_missing_dep.jar)",
"$(location :separate_java8_desugared_default_methods.jar)",
@@ -1959,30 +1954,30 @@ _SINGLEJAR_IMPLS = {
":guava_at_head_desugared.jar",
":separate_java8_desugared_default_methods.jar",
":testdata_desugared_with_missing_dep.jar",
- singlejar,
+ "//src/tools/singlejar:singlejar_local",
"@bazel_tools//tools/jdk:jar",
],
tags = ["no_windows"],
-) for label, singlejar in _SINGLEJAR_IMPLS.items()]
+)
# Tests that any Jar entry starting with j$/ causes singlejar to fail when run
# with --check_desugar_deps. This is a backstop against such entries being
# included in deploy.jars.
-[sh_test(
- name = "bad_entry_jar_%s_fail_test" % label,
+sh_test(
+ name = "bad_entry_jar_singlejar_fail_test",
srcs = ["desugar_deps_consistency_test.sh"],
args = [
- "$(location %s)" % singlejar,
+ "$(location //src/tools/singlejar:singlejar_local)",
"$(location @bazel_tools//tools/jdk:jar)",
"$(location :mock_bad_entry_jar)",
],
data = [
":mock_bad_entry_jar",
- singlejar,
+ "//src/tools/singlejar:singlejar_local",
"@bazel_tools//tools/jdk:jar",
],
tags = ["no_windows"],
-) for label, singlejar in _SINGLEJAR_IMPLS.items()]
+)
genrule(
name = "desugar_testdata_with_missing_dep",