Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
cstamas committed Mar 21, 2024
1 parent d5e34d4 commit 9bf6561
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 18 deletions.
51 changes: 51 additions & 0 deletions cli/src/main/java/eu/maveniverse/maven/toolbox/cli/CopyAll.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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.cli;

import eu.maveniverse.maven.mima.context.Context;
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;

/**
* Resolves transitively a given GAV and copies resulting artifacts to target.
*/
@CommandLine.Command(name = "copyAll", description = "Resolves Maven Artifact and copies them to target")
public final class CopyAll extends ResolverCommandSupport {
@CommandLine.Parameters(index = "0", description = "The GAV to resolve", arity = "1")
private String gav;

@CommandLine.Parameters(index = "1", description = "The target", arity = "1")
private Path target;

@CommandLine.Option(
names = {"--resolutionScope"},
defaultValue = "runtime",
description = "Resolution scope to resolve (default main-runtime)")
private String resolutionScope;

@CommandLine.Option(
names = {"--boms"},
defaultValue = "",
split = ",",
description = "Comma separated list of BOMs to apply")
private java.util.List<String> boms;

@Override
protected boolean doCall(Context context) throws Exception {
Path targetPath = target.toAbsolutePath();
ToolboxCommando toolboxCommando = ToolboxCommando.getOrCreate(context);
return toolboxCommando.copyAll(
ResolutionScope.parse(resolutionScope),
toolboxCommando.toolboxResolver().loadGav(gav, boms),
DirectorySink.flat(output, targetPath),
output);
}
}
5 changes: 3 additions & 2 deletions cli/src/main/java/eu/maveniverse/maven/toolbox/cli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@
name = "toolbox",
subcommands = {
Classpath.class,
CopyAll.class,
Deploy.class,
DeployRecorded.class,
Dump.class,
Exists.class,
Identify.class,
Install.class,
List.class,
ListRepositories.class,
ListAvailablePlugins.class,
Search.class,
ListRepositories.class,
Record.class,
Repl.class,
Resolve.class,
Search.class,
Tree.class,
Test.class,
Verify.class
Expand Down
Binary file added foo/hamcrest-core-1.3.jar
Binary file not shown.
Binary file added foo/junit-4.13.2.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* 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;

import static java.util.Objects.requireNonNull;

import eu.maveniverse.maven.toolbox.shared.internal.ArtifactMapper;
import eu.maveniverse.maven.toolbox.shared.internal.ArtifactMatcher;
import eu.maveniverse.maven.toolbox.shared.internal.ArtifactNameMapper;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Collection;
import java.util.HashSet;
import java.util.function.Consumer;
import org.eclipse.aether.artifact.Artifact;

/**
* Construction to accept collection of artifacts, for example like a filesystem directory.
*/
public final class DirectorySink implements Consumer<Collection<Artifact>> {

public static DirectorySink flat(Output output, Path path) throws IOException {
return new DirectorySink(output, path);
}

private final Output output;
private final Path directory;
private final ArtifactMatcher artifactMatcher;
private final ArtifactMapper artifactMapper;
private final ArtifactNameMapper artifactNameMapper;
private final boolean allowOverwrite;
private final HashSet<Path> writtenPaths;

private DirectorySink(Output output, Path directory) throws IOException {
this.output = requireNonNull(output, "output");
this.directory = requireNonNull(directory, "directory");
if (Files.exists(directory) && !Files.isDirectory(directory)) {
throw new IllegalArgumentException("directory must not exists, or be a directory");
}
if (!Files.exists(directory)) {
Files.createDirectories(directory);
}

this.artifactMatcher = ArtifactMatcher.any();
this.artifactMapper = ArtifactMapper.identity();
this.artifactNameMapper = ArtifactNameMapper.ACVE();
this.allowOverwrite = false;
this.writtenPaths = new HashSet<>();
}

@Override
public void accept(Collection<Artifact> artifacts) {
requireNonNull(artifacts, "artifacts");
output.verbose("Copying {} artifacts to directory {}", artifacts.size(), directory);
try {
for (Artifact artifact : artifacts) {
accept(artifact);
}
} catch (IOException e) {
cleanup(artifacts, e);
}
}

private void accept(Artifact artifact) throws IOException {
output.verbose("Artifact {} processed", artifact);
if (artifactMatcher.test(artifact)) {
output.verbose(" matched");
String name = artifactNameMapper.map(artifactMapper.map(artifact));
output.verbose(" mapped to name {}", name);
Path target = directory.resolve(name);
if (!writtenPaths.add(target) && !allowOverwrite) {
throw new IOException("Overwrite prevented: check mappings");
}
output.verbose(" copied to file {}", target);
Files.copy(
artifact.getFile().toPath(),
target,
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES);
}
}

private void cleanup(Collection<Artifact> artifacts, IOException e) {
output.error("IO error happened, cleaning up", e);
writtenPaths.forEach(p -> {
try {
Files.deleteIfExists(p);
} catch (IOException ex) {
// ignore
}
});
throw new UncheckedIOException(e);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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;

/**
* Null Output.
*/
public final class NullOutput implements Output {
public NullOutput() {}

@Override
public boolean isVerbose() {
return false;
}

@Override
public void verbose(String msg, Object... params) {}

@Override
public void normal(String msg, Object... params) {}

@Override
public void warn(String msg, Object... params) {}

@Override
public void error(String msg, Object... params) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.slf4j.Logger;

/**
* Output.
* Slf4j Logger backed Output.
*/
public final class Slf4jOutput implements Output {
private final Logger logger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.io.Closeable;
import java.io.IOException;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.repository.RemoteRepository;
Expand Down Expand Up @@ -71,6 +72,12 @@ static void unset(Context context) {

boolean classpath(ResolutionScope resolutionScope, ResolutionRoot resolutionRoot, Output output);

boolean copyAll(
ResolutionScope resolutionScope,
ResolutionRoot resolutionRoot,
Consumer<Collection<Artifact>> consumer,
Output output);

boolean deploy(String remoteRepositorySpec, Supplier<Collection<Artifact>> artifactSupplier, Output output);

boolean deployAllRecorded(String remoteRepositorySpec, boolean stopRecording, Output output);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,16 @@ public Artifact map(Artifact artifact) {
};
}

static ArtifactMapper bV() {
static ArtifactMapper identity() {
return new ArtifactMapper() {
@Override
public Artifact map(Artifact artifact) {
return artifact;
}
};
}

static ArtifactMapper baseVersion() {
return new ArtifactMapper() {
@Override
public Artifact map(Artifact artifact) {
Expand All @@ -47,7 +56,7 @@ public Artifact map(Artifact artifact) {
};
}

static ArtifactMapper woC() {
static ArtifactMapper omitClassifier() {
return new ArtifactMapper() {
@Override
public Artifact map(Artifact artifact) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ public boolean test(Artifact artifact) {
};
}

static ArtifactMatcher withoutClassifier() {
return a -> a.getClassifier() == null || a.getClassifier().trim().isEmpty();
}

static ArtifactMatcher artifact(String coordinate) {
Artifact prototype = parsePrototype(coordinate);
return a -> matches(prototype.getGroupId(), a.getGroupId())
&& matches(prototype.getArtifactId(), a.getArtifactId())
&& matches(prototype.getVersion(), a.getVersion())
&& matches(prototype.getExtension(), a.getExtension())
&& matches(prototype.getClassifier(), a.getClassifier());
}

static ArtifactMatcher any() {
return a -> true;
}

private static boolean isAny(String str) {
return "*".equals(str);
}
Expand Down Expand Up @@ -108,17 +125,4 @@ private static Artifact parsePrototype(String coordinate) {
}
return s;
}

static Predicate<Artifact> withoutClassifier() {
return a -> a.getClassifier() == null || a.getClassifier().trim().isEmpty();
}

static Predicate<Artifact> artifactPredicate(String coordinate) {
Artifact prototype = parsePrototype(coordinate);
return a -> matches(prototype.getGroupId(), a.getGroupId())
&& matches(prototype.getArtifactId(), a.getArtifactId())
&& matches(prototype.getVersion(), a.getVersion())
&& matches(prototype.getExtension(), a.getExtension())
&& matches(prototype.getClassifier(), a.getClassifier());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,40 @@
*/
package eu.maveniverse.maven.toolbox.shared.internal;

import static java.util.Objects.requireNonNull;

import java.util.Arrays;
import java.util.Collection;
import org.eclipse.aether.artifact.Artifact;

public interface ArtifactNameMapper {
String map(Artifact artifact);

static ArtifactNameMapper compose(ArtifactNameMapper... mappers) {
return compose(Arrays.asList(mappers));
}

static ArtifactNameMapper compose(Collection<ArtifactNameMapper> mappers) {
return new ArtifactNameMapper() {
@Override
public String map(Artifact artifact) {
String result = "";
for (ArtifactNameMapper mapper : mappers) {
result += mapper.map(artifact);
}
return result;
}
};
}

static ArtifactNameMapper prefix(String prefix) {
requireNonNull(prefix, "prefix");
if (prefix.trim().isEmpty()) {
throw new IllegalArgumentException("invalid prefix");
}
return artifact -> prefix;
}

static ArtifactNameMapper GACVE() {
return artifact -> {
String result = artifact.getGroupId() + ".";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -138,6 +139,28 @@ public boolean classpath(ResolutionScope resolutionScope, ResolutionRoot resolut
}
}

@Override
public boolean copyAll(
ResolutionScope resolutionScope,
ResolutionRoot resolutionRoot,
Consumer<Collection<Artifact>> consumer,
Output output) {
try {
DependencyResult dependencyResult = toolboxResolver.resolve(
resolutionScope,
resolutionRoot.getArtifact(),
resolutionRoot.getDependencies(),
resolutionRoot.getManagedDependencies());

consumer.accept(dependencyResult.getArtifactResults().stream()
.map(ArtifactResult::getArtifact)
.collect(Collectors.toList()));
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
public boolean deploy(String remoteRepositorySpec, Supplier<Collection<Artifact>> artifactSupplier, Output output) {
try {
Expand Down

0 comments on commit 9bf6561

Please sign in to comment.