From 257ddab3bc80967bc88b52e5ea7b8b58d3d100a4 Mon Sep 17 00:00:00 2001 From: cnsun Date: Thu, 26 Apr 2018 15:15:10 -0700 Subject: Emit jdeps proto, that is, the used jars on the regular classpath. RELNOTES: PiperOrigin-RevId: 194461881 --- .../com/google/devtools/build/importdeps/BUILD | 2 + .../devtools/build/importdeps/ClassCache.java | 72 +++++++--- .../build/importdeps/ImportDepsChecker.java | 21 ++- .../com/google/devtools/build/importdeps/Main.java | 40 +++++- .../devtools/build/importdeps/ClassCacheTest.java | 67 +++++++-- .../importdeps/DepsCheckerClassVisitorTest.java | 4 +- .../build/importdeps/ImportDepsCheckerTest.java | 149 +++++++++++++++++++++ 7 files changed, 322 insertions(+), 33 deletions(-) create mode 100644 src/java_tools/import_deps_checker/javatests/com/google/devtools/build/importdeps/ImportDepsCheckerTest.java (limited to 'src/java_tools') 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 bootclasspath, ImmutableList regularClasspath) + public ClassCache( + ImmutableList bootclasspath, + ImmutableList regularClasspath, + ImmutableList 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 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 bootclasspath, ImmutableList regularClasspath) + private final ClassIndex inputJars; + private final ImmutableList orderedClasspath; + private final Closer closer = Closer.create(); + + public LazyClasspath( + ImmutableList bootclasspath, + ImmutableList regularClasspath, + ImmutableList 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 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 collectUsedJarFiles() { + HashSet usedJars = new HashSet<>(); + for (Map.Entry 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 classpath, ImmutableList inputJars) throws IOException { - this.classCache = - new ClassCache( - bootclasspath, - ImmutableList.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 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 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; @@ -94,6 +97,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", @@ -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") @@ -137,11 +146,46 @@ 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 bootclasspath, + ImmutableList regularClasspath, + ImmutableList inputJars, + boolean expectedCheckResult, + ImmutableList 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 bootclasspath, + ImmutableList regularClasspath, + ImmutableList inputJars) + throws IOException { + ArrayList 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(); + } + } +} -- cgit v1.2.3