aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/java_tools
diff options
context:
space:
mode:
authorGravatar cnsun <cnsun@google.com>2018-04-26 15:15:10 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-04-26 15:16:25 -0700
commit257ddab3bc80967bc88b52e5ea7b8b58d3d100a4 (patch)
tree77b7747c89f046ce6c45b7f4a62b1b61ed4ca382 /src/java_tools
parent860975ab5e21078bee9009049031b9c72508f2cf (diff)
Emit jdeps proto, that is, the used jars on the regular classpath.
RELNOTES: PiperOrigin-RevId: 194461881
Diffstat (limited to 'src/java_tools')
-rw-r--r--src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/BUILD2
-rw-r--r--src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ClassCache.java72
-rw-r--r--src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ImportDepsChecker.java21
-rw-r--r--src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/Main.java40
-rw-r--r--src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ClassCacheTest.java67
-rw-r--r--src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/DepsCheckerClassVisitorTest.java4
-rw-r--r--src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ImportDepsCheckerTest.java149
7 files changed, 322 insertions, 33 deletions
diff --git a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/BUILD b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/BUILD
index b512df021f..65fbf0135f 100644
--- a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/BUILD
+++ b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/BUILD
@@ -25,6 +25,7 @@ java_library(
exclude = ["Main.java"],
),
deps = [
+ "//src/main/protobuf:deps_java_proto",
"//third_party:asm",
"//third_party:asm-commons",
"//third_party:asm-tree",
@@ -46,6 +47,7 @@ java_binary(
deps = [
":import_deps_checker",
"//src/main/java/com/google/devtools/common/options",
+ "//src/main/protobuf:deps_java_proto",
"//src/main/protobuf:worker_protocol_java_proto",
"//third_party:guava",
],
diff --git a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ClassCache.java b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ClassCache.java
index 9f905259e3..623863af8b 100644
--- a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ClassCache.java
+++ b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ClassCache.java
@@ -32,7 +32,9 @@ import java.io.InputStream;
import java.io.PrintStream;
import java.nio.file.Path;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.annotation.Nullable;
@@ -48,9 +50,12 @@ public final class ClassCache implements Closeable {
private final LazyClasspath lazyClasspath;
private boolean isClosed;
- public ClassCache(ImmutableList<Path> bootclasspath, ImmutableList<Path> regularClasspath)
+ public ClassCache(
+ ImmutableList<Path> bootclasspath,
+ ImmutableList<Path> regularClasspath,
+ ImmutableList<Path> inputJars)
throws IOException {
- lazyClasspath = new LazyClasspath(bootclasspath, regularClasspath);
+ lazyClasspath = new LazyClasspath(bootclasspath, regularClasspath, inputJars);
}
public AbstractClassEntryState getClassState(String internalName) {
@@ -62,6 +67,10 @@ public final class ClassCache implements Closeable {
return entry.getState(lazyClasspath);
}
+ public ImmutableList<Path> collectUsedJarsInRegularClasspath() {
+ return lazyClasspath.collectUsedJarsInRegularClasspath();
+ }
+
@Override
public void close() throws IOException {
lazyClasspath.close();
@@ -71,15 +80,17 @@ public final class ClassCache implements Closeable {
static class LazyClassEntry {
private final String internalName;
private final ZipFile zipFile;
+ private final Path jarPath;
/**
* The state of this class entry. If {@literal null}, then this class has not been resolved yet.
*/
@Nullable private AbstractClassEntryState state = null;
- private LazyClassEntry(String internalName, ZipFile zipFile) {
+ private LazyClassEntry(String internalName, ZipFile zipFile, Path jarPath) {
this.internalName = internalName;
this.zipFile = zipFile;
+ this.jarPath = jarPath;
}
ZipFile getZipFile() {
@@ -104,8 +115,12 @@ public final class ClassCache implements Closeable {
.toString();
}
+ boolean isResolved() {
+ return state != null;
+ }
+
private void resolveIfNot(LazyClasspath lazyClasspath) {
- if (state != null) {
+ if (isResolved()) {
return;
}
resolveClassEntry(this, lazyClasspath);
@@ -190,30 +205,43 @@ public final class ClassCache implements Closeable {
static final class LazyClasspath implements Closeable {
private final ClassIndex bootclasspath;
private final ClassIndex regularClasspath;
-
- public LazyClasspath(ImmutableList<Path> bootclasspath, ImmutableList<Path> regularClasspath)
+ private final ClassIndex inputJars;
+ private final ImmutableList<ClassIndex> orderedClasspath;
+ private final Closer closer = Closer.create();
+
+ public LazyClasspath(
+ ImmutableList<Path> bootclasspath,
+ ImmutableList<Path> regularClasspath,
+ ImmutableList<Path> inputJars)
throws IOException {
this.bootclasspath = new ClassIndex("boot classpath", bootclasspath);
this.regularClasspath = new ClassIndex("regular classpath", regularClasspath);
+ this.inputJars = new ClassIndex("input jars", inputJars);
+ this.orderedClasspath =
+ ImmutableList.of(this.bootclasspath, this.regularClasspath, this.inputJars);
+ this.orderedClasspath.forEach(closer::register);
}
public LazyClassEntry getLazyEntry(String internalName) {
- LazyClassEntry entry = bootclasspath.getClassEntry(internalName);
- if (entry != null) {
- return entry;
- }
- return regularClasspath.getClassEntry(internalName);
+ return orderedClasspath
+ .stream()
+ .map(classIndex -> classIndex.getClassEntry(internalName))
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElse(null);
+ }
+
+ public ImmutableList<Path> collectUsedJarsInRegularClasspath() {
+ return regularClasspath.collectUsedJarFiles();
}
public void printClasspath(PrintStream stream) {
- bootclasspath.printClasspath(stream);
- regularClasspath.printClasspath(stream);
+ orderedClasspath.forEach(c -> c.printClasspath(stream));
}
@Override
public void close() throws IOException {
- bootclasspath.close();
- regularClasspath.close();
+ closer.close();
}
}
@@ -242,6 +270,17 @@ public final class ClassCache implements Closeable {
return classIndex.get(internalName);
}
+ public ImmutableList<Path> collectUsedJarFiles() {
+ HashSet<Path> usedJars = new HashSet<>();
+ for (Map.Entry<String, LazyClassEntry> entry : classIndex.entrySet()) {
+ LazyClassEntry clazz = entry.getValue();
+ if (clazz.isResolved()) {
+ usedJars.add(clazz.jarPath);
+ }
+ }
+ return ImmutableList.sortedCopyOf(usedJars);
+ }
+
private void printClasspath(PrintStream stream) {
stream.println("Classpath: " + name);
int counter = 0;
@@ -265,7 +304,8 @@ public final class ClassCache implements Closeable {
return; // Not a class file.
}
String internalName = name.substring(0, name.lastIndexOf('.'));
- result.computeIfAbsent(internalName, key -> new LazyClassEntry(key, zipFile));
+ result.computeIfAbsent(
+ internalName, key -> new LazyClassEntry(key, zipFile, jarPath));
});
} catch (Throwable e) {
throw new RuntimeException("Error in reading zip file " + jarPath, e);
diff --git a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ImportDepsChecker.java b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ImportDepsChecker.java
index 433e0a825f..21089667c3 100644
--- a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ImportDepsChecker.java
+++ b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/ImportDepsChecker.java
@@ -18,6 +18,9 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.importdeps.AbstractClassEntryState.IncompleteState;
import com.google.devtools.build.importdeps.ResultCollector.MissingMember;
+import com.google.devtools.build.lib.view.proto.Deps.Dependencies;
+import com.google.devtools.build.lib.view.proto.Deps.Dependency;
+import com.google.devtools.build.lib.view.proto.Deps.Dependency.Kind;
import java.io.Closeable;
import java.io.IOError;
import java.io.IOException;
@@ -42,10 +45,7 @@ public final class ImportDepsChecker implements Closeable {
ImmutableList<Path> classpath,
ImmutableList<Path> inputJars)
throws IOException {
- this.classCache =
- new ClassCache(
- bootclasspath,
- ImmutableList.<Path>builder().addAll(classpath).addAll(inputJars).build());
+ this.classCache = new ClassCache(bootclasspath, classpath, inputJars);
this.resultCollector = new ResultCollector();
this.inputJars = inputJars;
}
@@ -86,9 +86,20 @@ public final class ImportDepsChecker implements Closeable {
return resultCollector.isEmpty();
}
+ /** Emit the jdeps proto. The parameter ruleLabel is optional, indicated with the empty string. */
+ public Dependencies emitJdepsProto(String ruleLabel) {
+ Dependencies.Builder builder = Dependencies.newBuilder();
+ ImmutableList<Path> paths = classCache.collectUsedJarsInRegularClasspath();
+ paths.forEach(
+ path ->
+ builder.addDependency(
+ Dependency.newBuilder().setKind(Kind.EXPLICIT).setPath(path.toString()).build()));
+ return builder.setRuleLabel(ruleLabel).setSuccess(true).build();
+ }
+
private static final String INDENT = " ";
- public String computeResultOutput() throws IOException {
+ public String computeResultOutput() {
StringBuilder builder = new StringBuilder();
ImmutableList<String> missingClasses = resultCollector.getSortedMissingClassInternalNames();
for (String missing : missingClasses) {
diff --git a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/Main.java b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/Main.java
index 7e7fd373b8..5df2eaa04d 100644
--- a/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/Main.java
+++ b/src/java_tools/import_deps_checker/java/com/google/devtools/build/importdeps/Main.java
@@ -19,6 +19,7 @@ import static com.google.common.io.MoreFiles.asCharSink;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.view.proto.Deps.Dependencies;
import com.google.devtools.common.options.Converter;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionDocumentationCategory;
@@ -27,7 +28,9 @@ import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor;
+import java.io.BufferedOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
@@ -95,6 +98,25 @@ public class Main {
public Path output;
@Option(
+ name = "jdeps_output",
+ defaultValue = "null",
+ category = "output",
+ documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+ effectTags = {OptionEffectTag.UNKNOWN},
+ converter = PathConverter.class,
+ help = "Output path to save the result.")
+ public Path jdepsOutput;
+
+ @Option(
+ name = "rule_label",
+ defaultValue = "",
+ category = "output",
+ documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
+ effectTags = {OptionEffectTag.UNKNOWN},
+ help = "The rule label of the current target under analysis.")
+ public String ruleLabel;
+
+ @Option(
name = "fail_on_errors",
defaultValue = "true",
documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
@@ -108,6 +130,11 @@ public class Main {
private static final int DEPS_ERROR_EXIT_CODE = 199;
public static void main(String[] args) throws IOException {
+ System.exit(checkDeps(args));
+ }
+
+ @VisibleForTesting
+ static int checkDeps(String[] args) throws IOException {
Options options = parseCommandLineOptions(args);
if (!Files.exists(options.output)) {
@@ -127,8 +154,15 @@ public class Main {
printErrorMessage(result, options);
asCharSink(options.output, StandardCharsets.UTF_8).write(result);
}
+ if (options.jdepsOutput != null) {
+ Dependencies dependencies = checker.emitJdepsProto(options.ruleLabel);
+ try (OutputStream os =
+ new BufferedOutputStream(Files.newOutputStream(options.jdepsOutput))) {
+ dependencies.writeTo(os);
+ }
+ }
}
- System.exit(exitCode);
+ return exitCode;
}
private static void printErrorMessage(String detailedErrorMessage, Options options) {
@@ -156,6 +190,10 @@ public class Main {
checkArgument(!options.inputJars.isEmpty(), "--input is required");
checkArgument(options.output != null, "--output is required");
checkArgument(!options.bootclasspath.isEmpty(), "--bootclasspath_entry is required");
+ checkArgument(
+ options.jdepsOutput == null || !Files.isDirectory(options.jdepsOutput),
+ "Invalid value of --jdeps_output: '%s'",
+ options.jdepsOutput);
return options;
}
diff --git a/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ClassCacheTest.java b/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ClassCacheTest.java
index a7cb666291..341fa013a0 100644
--- a/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ClassCacheTest.java
+++ b/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ClassCacheTest.java
@@ -36,7 +36,8 @@ public class ClassCacheTest extends AbstractClassCacheTest {
@Test
public void testLibraryJar() throws Exception {
try (ClassCache cache =
- new ClassCache(ImmutableList.of(bootclasspath), ImmutableList.of(libraryJar))) {
+ new ClassCache(
+ ImmutableList.of(bootclasspath), ImmutableList.of(libraryJar), ImmutableList.of())) {
assertCache(
cache,
libraryJarPositives,
@@ -52,7 +53,8 @@ public class ClassCacheTest extends AbstractClassCacheTest {
try (ClassCache cache =
new ClassCache(
ImmutableList.of(bootclasspath),
- ImmutableList.of(clientJar, libraryJar, libraryInterfaceJar))) {
+ ImmutableList.of(libraryJar, libraryInterfaceJar),
+ ImmutableList.of(clientJar))) {
assertCache(
cache,
clientJarPositives,
@@ -63,7 +65,8 @@ public class ClassCacheTest extends AbstractClassCacheTest {
@Test
public void testClientJarWithoutSuperClasses() throws IOException {
try (ClassCache cache =
- new ClassCache(ImmutableList.of(bootclasspath), ImmutableList.of(clientJar))) {
+ new ClassCache(
+ ImmutableList.of(bootclasspath), ImmutableList.of(), ImmutableList.of(clientJar))) {
// Client should be incomplete, as its parent class and interfaces are not available on the
// classpath. The following is the resolution path.
{
@@ -86,7 +89,10 @@ public class ClassCacheTest extends AbstractClassCacheTest {
@Test
public void testLibraryException() throws IOException {
try (ClassCache cache =
- new ClassCache(ImmutableList.of(bootclasspath), ImmutableList.of(libraryExceptionJar))) {
+ new ClassCache(
+ ImmutableList.of(bootclasspath),
+ ImmutableList.of(),
+ ImmutableList.of(libraryExceptionJar))) {
assertCache(
cache,
libraryExceptionJarPositives,
@@ -97,7 +103,10 @@ public class ClassCacheTest extends AbstractClassCacheTest {
@Test
public void testLibraryAnnotations() throws IOException {
try (ClassCache cache =
- new ClassCache(ImmutableList.of(bootclasspath), ImmutableList.of(libraryAnnotationsJar))) {
+ new ClassCache(
+ ImmutableList.of(bootclasspath),
+ ImmutableList.of(),
+ ImmutableList.of(libraryAnnotationsJar))) {
assertCache(
cache,
libraryAnnotationsJarPositives,
@@ -107,7 +116,7 @@ public class ClassCacheTest extends AbstractClassCacheTest {
@Test
public void testCannotAccessClosedCache() throws IOException {
- ClassCache cache = new ClassCache(ImmutableList.of(), ImmutableList.of());
+ ClassCache cache = new ClassCache(ImmutableList.of(), ImmutableList.of(), ImmutableList.of());
cache.close();
cache.close(); // Can close multiple times.
assertThrows(IllegalStateException.class, () -> cache.getClassState("empty"));
@@ -122,8 +131,8 @@ public class ClassCacheTest extends AbstractClassCacheTest {
try (ClassCache cache =
new ClassCache(
ImmutableList.of(),
- ImmutableList.of(
- libraryJar, libraryJar, libraryAnnotationsJar, libraryInterfaceJar, clientJar))) {
+ ImmutableList.of(libraryJar, libraryJar, libraryAnnotationsJar, libraryInterfaceJar),
+ ImmutableList.of(clientJar))) {
assertThat(
cache
.getClassState("com/google/devtools/build/importdeps/testdata/Library$Class9")
@@ -138,10 +147,45 @@ public class ClassCacheTest extends AbstractClassCacheTest {
}
@Test
+ public void testJdepsOutput() throws IOException {
+ try (ClassCache cache =
+ new ClassCache(
+ ImmutableList.of(),
+ ImmutableList.of(libraryJar, libraryJar, libraryAnnotationsJar, libraryInterfaceJar),
+ ImmutableList.of(clientJar))) {
+ assertThat(
+ cache
+ .getClassState("com/google/devtools/build/importdeps/testdata/Library$Class9")
+ .isIncompleteState())
+ .isTrue();
+ assertThat(cache.collectUsedJarsInRegularClasspath()).containsExactly(libraryJar);
+
+ assertThat(
+ cache
+ .getClassState("com/google/devtools/build/importdeps/testdata/LibraryAnnotations")
+ .isIncompleteState())
+ .isTrue();
+ assertThat(cache.collectUsedJarsInRegularClasspath())
+ .containsExactly(libraryJar, libraryAnnotationsJar);
+
+ assertThat(
+ cache
+ .getClassState("com/google/devtools/build/importdeps/testdata/LibraryInterface")
+ .isIncompleteState())
+ .isTrue();
+ assertThat(cache.collectUsedJarsInRegularClasspath())
+ .containsExactly(libraryJar, libraryAnnotationsJar, libraryInterfaceJar);
+ }
+ }
+
+ @Test
public void testLazyClasspathLoadsBootclasspathFirst() throws IOException {
{
LazyClasspath classpath =
- new LazyClasspath(ImmutableList.of(libraryJar), ImmutableList.of(libraryWoMembersJar));
+ new LazyClasspath(
+ ImmutableList.of(libraryJar),
+ ImmutableList.of(libraryWoMembersJar),
+ ImmutableList.of());
LazyClassEntry entry =
classpath.getLazyEntry("com/google/devtools/build/importdeps/testdata/Library$Class4");
AbstractClassEntryState state = entry.getState(classpath);
@@ -159,7 +203,10 @@ public class ClassCacheTest extends AbstractClassCacheTest {
}
{
LazyClasspath classpath =
- new LazyClasspath(ImmutableList.of(libraryWoMembersJar), ImmutableList.of(libraryJar));
+ new LazyClasspath(
+ ImmutableList.of(libraryWoMembersJar),
+ ImmutableList.of(libraryJar),
+ ImmutableList.of());
LazyClassEntry entry =
classpath.getLazyEntry("com/google/devtools/build/importdeps/testdata/Library$Class4");
AbstractClassEntryState state = entry.getState(classpath);
diff --git a/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/DepsCheckerClassVisitorTest.java b/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/DepsCheckerClassVisitorTest.java
index 3e25134700..c31b185178 100644
--- a/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/DepsCheckerClassVisitorTest.java
+++ b/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/DepsCheckerClassVisitorTest.java
@@ -112,7 +112,9 @@ public class DepsCheckerClassVisitorTest extends AbstractClassCacheTest {
PACKAGE_NAME + "Client$NestedAnnotation",
PACKAGE_NAME + "Client$InnerClassWithSyntheticConstructorParam");
ResultCollector resultCollector = new ResultCollector();
- try (ClassCache cache = new ClassCache(ImmutableList.copyOf(classpath), ImmutableList.of());
+ try (ClassCache cache =
+ new ClassCache(
+ ImmutableList.copyOf(classpath), ImmutableList.of(), ImmutableList.of());
ZipFile zipFile = new ZipFile(clientJar.toFile())) {
assertThat(cache.getClassState("java/lang/invoke/LambdaMetafactory").isExistingState())
.isTrue();
diff --git a/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ImportDepsCheckerTest.java b/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ImportDepsCheckerTest.java
new file mode 100644
index 0000000000..8d92a8fe19
--- /dev/null
+++ b/src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ImportDepsCheckerTest.java
@@ -0,0 +1,149 @@
+// 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.importdeps;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.view.proto.Deps.Dependencies;
+import com.google.devtools.build.lib.view.proto.Deps.Dependency;
+import com.google.devtools.build.lib.view.proto.Deps.Dependency.Kind;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link ImportDepsChecker} */
+@RunWith(JUnit4.class)
+public class ImportDepsCheckerTest extends AbstractClassCacheTest {
+
+ @Test
+ public void testJdepsProtos() throws IOException {
+ testJdepsProto(
+ ImmutableList.of(bootclasspath),
+ ImmutableList.of(libraryJar),
+ ImmutableList.of(clientJar),
+ /*expectedCheckResult=*/ false,
+ ImmutableList.of(libraryJar));
+ testJdepsProto(
+ ImmutableList.of(clientJar), // fake non-empty bootclasspath.
+ ImmutableList.of(libraryJar),
+ ImmutableList.of(clientJar),
+ false,
+ ImmutableList.of(libraryJar));
+ testJdepsProto(
+ ImmutableList.of(bootclasspath),
+ ImmutableList.of(libraryJar, libraryAnnotationsJar),
+ ImmutableList.of(clientJar),
+ false,
+ ImmutableList.of(libraryJar, libraryAnnotationsJar));
+ testJdepsProto(
+ ImmutableList.of(bootclasspath),
+ ImmutableList.of(libraryAnnotationsJar),
+ ImmutableList.of(libraryJar),
+ true,
+ ImmutableList.of());
+ testJdepsProto(
+ ImmutableList.of(bootclasspath),
+ ImmutableList.of(
+ libraryJar, libraryAnnotationsJar, libraryExceptionJar, libraryInterfaceJar),
+ ImmutableList.of(clientJar),
+ true,
+ ImmutableList.of(
+ libraryJar, libraryAnnotationsJar, libraryExceptionJar, libraryInterfaceJar));
+ }
+
+ private static final String DUMMY_RULE_LABEL = "empty";
+
+ private static void testJdepsProto(
+ ImmutableList<Path> bootclasspath,
+ ImmutableList<Path> regularClasspath,
+ ImmutableList<Path> inputJars,
+ boolean expectedCheckResult,
+ ImmutableList<Path> expectedJdeps)
+ throws IOException {
+ try (ImportDepsChecker checker =
+ new ImportDepsChecker(bootclasspath, regularClasspath, inputJars)) {
+ assertThat(checker.check()).isEqualTo(expectedCheckResult);
+ Dependencies deps = checker.emitJdepsProto(DUMMY_RULE_LABEL);
+ assertThat(deps.getDependencyList())
+ .containsExactlyElementsIn(
+ expectedJdeps
+ .stream()
+ .map(
+ path ->
+ Dependency.newBuilder()
+ .setKind(Kind.EXPLICIT)
+ .setPath(path.toString())
+ .build())
+ .collect(Collectors.toList()));
+ assertPathsAreRelative(deps);
+ assertThat(checker.check()).isEqualTo(expectedCheckResult);
+ Dependencies deps2 = checker.emitJdepsProto(DUMMY_RULE_LABEL);
+ assertThat(deps).isEqualTo(deps2);
+
+ System.err.println(deps2);
+
+ Dependencies depsFromMain =
+ getJdepsProtoWithMainEntry(bootclasspath, regularClasspath, inputJars);
+ assertThat(deps).isEqualTo(depsFromMain);
+ }
+ }
+
+ private static Dependencies getJdepsProtoWithMainEntry(
+ ImmutableList<Path> bootclasspath,
+ ImmutableList<Path> regularClasspath,
+ ImmutableList<Path> inputJars)
+ throws IOException {
+ ArrayList<String> args = new ArrayList<>();
+ bootclasspath.forEach(
+ s -> {
+ args.add("--bootclasspath_entry");
+ args.add(s.toString());
+ });
+ regularClasspath.forEach(
+ s -> {
+ args.add("--classpath_entry");
+ args.add(s.toString());
+ });
+ inputJars.forEach(
+ s -> {
+ args.add("--input");
+ args.add(s.toString());
+ });
+ args.add("--jdeps_output");
+ Path jdepsFile = Files.createTempFile("temp_importdeps", ".jdeps");
+ args.add(jdepsFile.toString());
+ args.add("--rule_label=" + DUMMY_RULE_LABEL);
+
+ args.add("--output");
+ args.add(Files.createTempFile("temp_output", ".txt").toString());
+ Main.checkDeps(args.toArray(new String[0]));
+
+ try (InputStream inputStream = Files.newInputStream(jdepsFile)) {
+ return Dependencies.parseFrom(inputStream);
+ }
+ }
+
+ private static void assertPathsAreRelative(Dependencies deps) {
+ for (Dependency dep : deps.getDependencyList()) {
+ assertThat(dep.getPath().startsWith("/")).isFalse();
+ }
+ }
+}