diff --git a/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/Copy.java b/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/Copy.java index 22e92449..64ef7403 100644 --- a/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/Copy.java +++ b/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/Copy.java @@ -7,9 +7,7 @@ */ package eu.maveniverse.maven.toolbox.cli; -import eu.maveniverse.maven.toolbox.shared.DirectorySink; import eu.maveniverse.maven.toolbox.shared.ToolboxCommando; -import java.nio.file.Path; import java.util.stream.Collectors; import org.eclipse.aether.artifact.DefaultArtifact; import picocli.CommandLine; @@ -19,8 +17,8 @@ */ @CommandLine.Command(name = "copy", description = "Resolves Maven Artifact and copies it to target") public final class Copy extends ResolverCommandSupport { - @CommandLine.Parameters(index = "0", description = "The target", arity = "1") - private Path target; + @CommandLine.Parameters(index = "0", description = "The target spec", arity = "1") + private String targetSpec; @CommandLine.Parameters(index = "1..*", description = "The GAVs to resolve", arity = "1") private java.util.List gav; @@ -34,10 +32,9 @@ public final class Copy extends ResolverCommandSupport { @Override protected boolean doExecute(ToolboxCommando toolboxCommando) throws Exception { - Path targetPath = target.toAbsolutePath(); return toolboxCommando.copy( gav.stream().map(DefaultArtifact::new).collect(Collectors.toList()), - DirectorySink.flat(output, targetPath), + toolboxCommando.artifactSink(output, targetSpec), output); } } diff --git a/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/CopyTransitive.java b/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/CopyTransitive.java index 88d0d973..992117a6 100644 --- a/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/CopyTransitive.java +++ b/cli/src/main/java/eu/maveniverse/maven/toolbox/cli/CopyTransitive.java @@ -7,10 +7,8 @@ */ package eu.maveniverse.maven.toolbox.cli; -import eu.maveniverse.maven.toolbox.shared.DirectorySink; import eu.maveniverse.maven.toolbox.shared.ResolutionScope; import eu.maveniverse.maven.toolbox.shared.ToolboxCommando; -import java.nio.file.Path; import picocli.CommandLine; /** @@ -20,8 +18,8 @@ name = "copyTransitive", description = "Resolves Maven Artifact transitively and copies all of them to target") public final class CopyTransitive extends ResolverCommandSupport { - @CommandLine.Parameters(index = "0", description = "The target", arity = "1") - private Path target; + @CommandLine.Parameters(index = "0", description = "The target spec", arity = "1") + private String targetSpec; @CommandLine.Parameters(index = "1..*", description = "The GAVs to resolve", arity = "1") private java.util.List gav; @@ -41,11 +39,10 @@ public final class CopyTransitive extends ResolverCommandSupport { @Override protected boolean doExecute(ToolboxCommando toolboxCommando) throws Exception { - Path targetPath = target.toAbsolutePath(); return toolboxCommando.copyTransitive( ResolutionScope.parse(resolutionScope), toolboxCommando.loadGavs(gav, boms), - DirectorySink.flat(output, targetPath), + toolboxCommando.artifactSink(output, targetSpec), output); } } diff --git a/shared/pom.xml b/shared/pom.xml index 76eb36f0..08ee0454 100644 --- a/shared/pom.xml +++ b/shared/pom.xml @@ -89,6 +89,21 @@ junit-jupiter-api test + + eu.maveniverse.maven.mima.runtime + standalone-static-uber + test + + + org.slf4j + slf4j-simple + test + + + org.slf4j + jcl-over-slf4j + test + diff --git a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DeployingSink.java b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DeployingSink.java index 2d10670e..9e8e8dbe 100644 --- a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DeployingSink.java +++ b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DeployingSink.java @@ -45,6 +45,10 @@ private DeployingSink( this.deployRequest.setTrace(RequestTrace.newChild(null, this)); } + public RemoteRepository getRemoteRepository() { + return deployRequest.getRepository(); + } + @Override public void accept(Collection artifacts) { requireNonNull(artifacts, "artifacts"); diff --git a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DirectorySink.java b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DirectorySink.java index 84b475df..18dfbfb9 100644 --- a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DirectorySink.java +++ b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/DirectorySink.java @@ -114,6 +114,10 @@ private DirectorySink( : new StandardCopyOption[] {StandardCopyOption.COPY_ATTRIBUTES}; } + public Path getDirectory() { + return directory; + } + @Override public void accept(Artifact artifact) throws IOException { requireNonNull(artifact, "artifact"); diff --git a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/InstallingSink.java b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/InstallingSink.java index 279fd278..c9cfea32 100644 --- a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/InstallingSink.java +++ b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/InstallingSink.java @@ -16,6 +16,7 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.installation.InstallRequest; import org.eclipse.aether.installation.InstallationException; +import org.eclipse.aether.repository.LocalRepository; /** * Construction to accept collection of artifacts and install them into local repository. @@ -41,6 +42,10 @@ private InstallingSink(Output output, RepositorySystem system, RepositorySystemS this.installRequest.setTrace(RequestTrace.newChild(null, this)); } + public LocalRepository getLocalRepository() { + return session.getLocalRepository(); + } + @Override public void accept(Collection artifacts) { requireNonNull(artifacts, "artifacts"); diff --git a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/ToolboxCommando.java b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/ToolboxCommando.java index df738929..ad29086e 100644 --- a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/ToolboxCommando.java +++ b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/ToolboxCommando.java @@ -52,6 +52,11 @@ static ToolboxCommando create(Runtime runtime, Context context) { // Resolver related commands: they target current context contained RemoteRepository + /** + * Provides {@link ArtifactSink} according to spec. + */ + ArtifactSink artifactSink(Output output, String spec) throws IOException; + /** * Shorthand method, creates {@link ResolutionRoot} out of passed in artifact. */ diff --git a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImpl.java b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImpl.java index 4fd9efac..f349e3f2 100644 --- a/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImpl.java +++ b/shared/src/main/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImpl.java @@ -20,6 +20,8 @@ import eu.maveniverse.maven.mima.context.Runtime; import eu.maveniverse.maven.mima.context.internal.RuntimeSupport; import eu.maveniverse.maven.toolbox.shared.ArtifactSink; +import eu.maveniverse.maven.toolbox.shared.DeployingSink; +import eu.maveniverse.maven.toolbox.shared.DirectorySink; import eu.maveniverse.maven.toolbox.shared.Output; import eu.maveniverse.maven.toolbox.shared.ResolutionRoot; import eu.maveniverse.maven.toolbox.shared.ResolutionScope; @@ -102,11 +104,6 @@ public ToolboxCommandoImpl(Runtime runtime, Context context) { new ToolboxResolverImpl(context.repositorySystem(), session, context.remoteRepositories()); } - @Override - public ResolutionRoot loadGav(String gav, Collection boms) throws ArtifactDescriptorException { - return toolboxResolver.loadGav(gav, boms); - } - @Override public String getVersion() { return discoverArtifactVersion("eu.maveniverse.maven.toolbox", "shared", "unknown"); @@ -188,6 +185,33 @@ public boolean dump(boolean verbose, Output output) { return true; } + @Override + public ArtifactSink artifactSink(Output output, String spec) throws IOException { + String prefix = spec.contains(":") ? spec.substring(0, spec.indexOf(":")) : "flatImplied"; + switch (prefix) { + case "flatImplied": + return DirectorySink.flat(output, context.basedir().resolve(spec)); + case "flat": + return DirectorySink.flat(output, context.basedir().resolve(spec.substring("flat:".length()))); + case "repository": + return DirectorySink.repository( + output, context.basedir().resolve(spec.substring("repository:".length()))); + case "deploy": + return DeployingSink.deploying( + output, + context.repositorySystem(), + context.repositorySystemSession(), + toolboxResolver.parseDeploymentRemoteRepository(spec.substring("deploy:".length()))); + default: + throw new IllegalArgumentException("unknown artifact sink spec"); + } + } + + @Override + public ResolutionRoot loadGav(String gav, Collection boms) throws ArtifactDescriptorException { + return toolboxResolver.loadGav(gav, boms); + } + @Override public boolean classpath(ResolutionScope resolutionScope, ResolutionRoot resolutionRoot, Output output) throws Exception { diff --git a/shared/src/test/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImplTest.java b/shared/src/test/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImplTest.java new file mode 100644 index 00000000..e5843494 --- /dev/null +++ b/shared/src/test/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImplTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023-2024 Maveniverse Org. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + */ +package eu.maveniverse.maven.toolbox.shared.internal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +import eu.maveniverse.maven.mima.context.Context; +import eu.maveniverse.maven.mima.context.ContextOverrides; +import eu.maveniverse.maven.mima.context.Runtime; +import eu.maveniverse.maven.mima.context.Runtimes; +import eu.maveniverse.maven.toolbox.shared.ArtifactSink; +import eu.maveniverse.maven.toolbox.shared.DeployingSink; +import eu.maveniverse.maven.toolbox.shared.DirectorySink; +import eu.maveniverse.maven.toolbox.shared.NullOutput; +import java.io.IOException; +import java.nio.file.Path; +import org.eclipse.aether.repository.RemoteRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +public class ToolboxCommandoImplTest { + @Test + void artifactSinkSpec(@TempDir Path tempDir) throws IOException { + Runtime runtime = Runtimes.INSTANCE.getRuntime(); + try (Context context = runtime.create(ContextOverrides.create().build())) { + ToolboxCommandoImpl commando = new ToolboxCommandoImpl(runtime, context); + ArtifactSink sink; + + sink = commando.artifactSink(new NullOutput(), tempDir.toString()); + assertInstanceOf(DirectorySink.class, sink); + assertEquals(((DirectorySink) sink).getDirectory(), tempDir); + + sink = commando.artifactSink(new NullOutput(), "flat:" + tempDir); + assertInstanceOf(DirectorySink.class, sink); + assertEquals(((DirectorySink) sink).getDirectory(), tempDir); + + sink = commando.artifactSink(new NullOutput(), "repository:" + tempDir); + assertInstanceOf(DirectorySink.class, sink); + assertEquals(((DirectorySink) sink).getDirectory(), tempDir); + + sink = commando.artifactSink(new NullOutput(), "deploy:id::https://somewhere.com/"); + assertInstanceOf(DeployingSink.class, sink); + assertEquals( + ((DeployingSink) sink).getRemoteRepository(), + new RemoteRepository.Builder("id", "default", "https://somewhere.com/").build()); + } + } +}