diff --git a/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/BuildToolTest.java b/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/BuildToolTest.java index 29d9de9..640ee48 100644 --- a/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/BuildToolTest.java +++ b/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/BuildToolTest.java @@ -260,6 +260,28 @@ void codeInsightUsesTheSelectedMavenAndGradleContexts() throws Exception { } } + @Test + void verboseSourceQueriesPreserveBuildSubcommands() throws Exception { + for (var type : List.of("maven", "gradle")) { + Files.deleteIfExists(directory.resolve("pom.xml")); + Files.deleteIfExists(directory.resolve("settings.gradle")); + var fixture = fixture(type, Set.of("class-path", "source-path")); + fixture.definition = new ToolDefinition("jist", Launch.PROVIDER, Optional.empty(), Optional.empty(), "jist", + Optional.empty(), Set.of("class-path", "source-path"), List.of()); + fixture.additionalTools = List.of(provider("jdocserver", (_, _) -> 0)); + + assertEquals(0, fixture.run("--verbose", "-p", type.equals("maven") ? "example:app" : ":app", "source", "java.lang.String")); + + assertEquals(2, fixture.queries.size(), fixture.queries.toString()); + for (var query : fixture.queries) { + assertEquals(type, query.getFirst(), query.toString()); + assertEquals("--verbose", query.get(1), query.toString()); + } + assertEquals(List.of("--class-path", "dependencies", "--source-path", "sources", "--source", "symbol", "java.lang.String"), + fixture.received); + } + } + @Test void documentationBrowsingPassesTheContextToTheDocumentationTool() throws Exception { var fixture = fixture("gradle", Set.of("class-path", "source-path")); diff --git a/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/CommandRunnerTest.java b/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/CommandRunnerTest.java index 1cfb706..4fbeba9 100644 --- a/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/CommandRunnerTest.java +++ b/src/com.netflix.tools.ja.test/com/netflix/tools/ja/test/CommandRunnerTest.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -56,6 +57,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -1569,6 +1571,54 @@ void verboseIsPassedOnlyToToolsDeclaringSupport() throws Exception { assertEquals(List.of(), unsupportedArguments); } + @Test + void verboseToolArgumentsPreserveSubcommandsAndOperandSeparators() throws Exception { + var cases = Map.of( + List.of("inspect", "value"), List.of("inspect", "value", "--verbose"), + List.of("inspect", "--format", "tsv"), List.of("inspect", "--verbose", "--format", "tsv"), + List.of("--create", "--file", "archive.jar", "-C", "sources", "."), List.of("--verbose", "--create", "--file", "archive.jar", "-C", "sources", "."), + List.of("inspect", "--", "value"), List.of("inspect", "--verbose", "--", "value"), + List.of("inspect", "--", "--verbose"), List.of("inspect", "--verbose", "--", "--verbose"), + List.of("inspect", "--verbose", "--", "value"), List.of("inspect", "--verbose", "--", "value")); + for (var entry : cases.entrySet()) { + var received = new ArrayList(); + var tools = ToolRuntime.of(tool("probe", (_, arguments) -> { + received.addAll(arguments); + return 0; + })); + var definition = ToolDefinition.read("probe", new ByteArrayInputStream("provider=probe\noptions=verbose\n".getBytes(StandardCharsets.UTF_8))); + var runner = new CommandRunner(ModuleLayer.boot(), tools, new ToolCatalog(List.of(definition)), () -> null); + var arguments = new ArrayList<>(List.of("--verbose", "tool", "probe")); + arguments.addAll(entry.getKey()); + + int status = runner.run(JaInvocation.parse(temporaryDirectory, arguments.toArray(String[]::new)), InputStream.nullInputStream(), + new PrintStream(new ByteArrayOutputStream()), new PrintStream(new ByteArrayOutputStream())); + + assertEquals(0, status); + assertEquals(entry.getValue(), received, entry.getKey().toString()); + } + } + + @Test + void verboseJarCreationKeepsOptionsBeforeFileInputs() throws Exception { + var sources = Files.createDirectories(temporaryDirectory.resolve("sources")); + Files.writeString(sources.resolve("example.txt"), "example"); + var archive = temporaryDirectory.resolve("example.jar"); + var tools = ToolRuntime.of(ToolProvider.findFirst("jar").orElseThrow()); + var definition = ToolDefinition.read("jar", new ByteArrayInputStream("provider=jar\noptions=verbose\n".getBytes(StandardCharsets.UTF_8))); + var runner = new CommandRunner(ModuleLayer.boot(), tools, new ToolCatalog(List.of(definition)), () -> null); + var error = new ByteArrayOutputStream(); + + int status = runner.run(JaInvocation.parse(temporaryDirectory, + new String[] {"--verbose", "tool", "jar", "--create", "--file", archive.toString(), "-C", sources.toString(), "."}), + InputStream.nullInputStream(), new PrintStream(new ByteArrayOutputStream()), new PrintStream(error)); + + assertEquals(0, status, error.toString(StandardCharsets.UTF_8)); + try (var jar = new java.util.jar.JarFile(archive.toFile())) { + assertNotNull(jar.getJarEntry("example.txt")); + } + } + @Test void compileDelegatesMaterializationToJig() throws Exception { var source = Files.createDirectories(temporaryDirectory.resolve("src/com.example.app")); diff --git a/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolArguments.java b/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolArguments.java index 819c313..b7ea43b 100644 --- a/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolArguments.java +++ b/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolArguments.java @@ -34,6 +34,21 @@ public final class ToolArguments { private ToolArguments() {} + static List withVerbose(List arguments) { + int separator = arguments.indexOf("--"); + int position = separator < 0 ? arguments.size() : separator; + if (arguments.subList(0, position).contains("--verbose")) { + return arguments; + } + int option = 0; + while (option < position && !arguments.get(option).startsWith("-")) { + option++; + } + var verboseArguments = new ArrayList<>(arguments); + verboseArguments.add(option, "--verbose"); + return List.copyOf(verboseArguments); + } + static List selectedModules(List arguments) { return optionValues(arguments, "--module").stream() .flatMap(value -> java.util.Arrays.stream(value.split(","))) diff --git a/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRunner.java b/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRunner.java index 7ecc73f..efcc625 100644 --- a/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRunner.java +++ b/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRunner.java @@ -378,13 +378,7 @@ private static Launch style(ToolDefinition definition) { private List arguments(JaInvocation commandLine, ToolDefinition definition) { var arguments = commandLine.toolArguments(); - if (!commandLine.verbose() || !supportsVerbose(definition) || arguments.contains("--verbose")) { - return arguments; - } - var verboseArguments = new ArrayList(); - verboseArguments.add("--verbose"); - verboseArguments.addAll(arguments); - return List.copyOf(verboseArguments); + return commandLine.verbose() && supportsVerbose(definition) ? ToolArguments.withVerbose(arguments) : arguments; } private int runJava(ToolDefinition definition, List nativeArguments, List runtimeArguments, diff --git a/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRuntime.java b/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRuntime.java index 2ed4090..d1827ca 100644 --- a/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRuntime.java +++ b/src/com.netflix.tools.ja/com/netflix/tools/ja/ToolRuntime.java @@ -446,11 +446,8 @@ public int run(String name, InputStream in, PrintStream out, private int run(Invocation invocation, String name, InputStream in, PrintStream out, PrintStream err, String... arguments) { - if (verbose && supportsVerbose(name) && !List.of(arguments).contains("--verbose")) { - var verboseArguments = new String[arguments.length + 1]; - verboseArguments[0] = "--verbose"; - System.arraycopy(arguments, 0, verboseArguments, 1, arguments.length); - arguments = verboseArguments; + if (verbose && supportsVerbose(name)) { + arguments = ToolArguments.withVerbose(List.of(arguments)).toArray(String[]::new); } if (verbose) { if (invocation == Invocation.RESOLUTION) {