This is an automated email from the ASF dual-hosted git repository. sseifert pushed a commit to branch feature/SLING-13075-attached-artifacts in repository https://gitbox.apache.org/repos/asf/sling-feature-launcher-maven-plugin.git
commit 00b17cc636f8925bcde109b482684faacd239f4f Author: Stefan Seifert <[email protected]> AuthorDate: Tue Jan 27 09:42:23 2026 +0100 SLING-13075 Provide attached artifacts of current Maven build to launcher --- .../maven/feature/launcher/ProcessTracker.java | 33 +++++++++ .../sling/maven/feature/launcher/StartMojo.java | 80 ++++++++++++++++++++-- .../sling/maven/feature/launcher/StopMojo.java | 50 ++++++++++++++ 3 files changed, 159 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java b/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java index efa54e1..b459d6b 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/ProcessTracker.java @@ -21,6 +21,7 @@ package org.apache.sling.maven.feature.launcher; import javax.inject.Named; import javax.inject.Singleton; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -114,6 +115,38 @@ public class ProcessTracker { private boolean hookAdded = false; private final Map<String, Process> processes = new HashMap<>(); + private Path tempRepository; + + /** + * Sets the path to the temporary repository containing attached artifacts. + * + * @param tempRepository the path to the temporary repository + */ + public void setTempRepository(Path tempRepository) { + synchronized (sync) { + this.tempRepository = tempRepository; + } + } + + /** + * Gets the path to the temporary repository containing attached artifacts. + * + * @return the path to the temporary repository, or null if not set + */ + public Path getTempRepository() { + synchronized (sync) { + return tempRepository; + } + } + + /** + * Clears the temporary repository reference. + */ + public void clearTempRepository() { + synchronized (sync) { + this.tempRepository = null; + } + } public void startTracking(String launchId, Process process) { synchronized (sync) { diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java b/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java index f3be1ca..32020fb 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.lang.ProcessBuilder.Redirect; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -158,6 +159,10 @@ public class StartMojo extends AbstractMojo { File workDir = new File(outputDirectory, "launchers"); workDir.mkdirs(); + // Create temp repository with attached artifacts from current build + Path tempRepo = createTempRepositoryWithAttachedArtifacts(); + processes.setTempRepository(tempRepo); + File launcher; if (useAssembly) { // fetch the assembly artifact @@ -261,17 +266,19 @@ public class StartMojo extends AbstractMojo { args.add(launcher.getAbsolutePath()); } - List<String> repositoryUrls; + List<String> repositoryUrls = new ArrayList<>(); + + // Add temp repository with attached artifacts as first repository + repositoryUrls.add(tempRepo.toUri().toString()); if (launch.getRepositoryUrls() != null && !launch.getRepositoryUrls().isEmpty()) { - repositoryUrls = launch.getRepositoryUrls(); + repositoryUrls.addAll(launch.getRepositoryUrls()); } else { // replicate the behaviour from org.apache.sling.feature.io.artifacts.ArtifactManager // but pass in the currently configured local repository. The ArtifactManager checks for the local // configuration file $HOME/.m2/settings.xml but cannot find out if the Maven process was invoked // with a maven.repo.local argument - repositoryUrls = new ArrayList<>(); repositoryUrls.add( new File(localRepository.getBasedir()).toURI().toString()); repositoryUrls.add("https://repo1.maven.org/maven2"); @@ -367,7 +374,7 @@ public class StartMojo extends AbstractMojo { } } - private Artifact toArtifact(Dependency dependency) { + private org.eclipse.aether.artifact.Artifact toArtifact(Dependency dependency) { return new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), @@ -375,4 +382,69 @@ public class StartMojo extends AbstractMojo { dependency.getType(), dependency.getVersion()); } + + /** + * Creates a temporary directory and stores all artifacts attached to the current Maven build + * in that directory following the Maven2 repository layout. + * + * @return the path to the temporary repository directory + * @throws IOException if the directory creation or file copying fails + */ + private Path createTempRepositoryWithAttachedArtifacts() throws IOException { + Path tempRepo = Files.createTempDirectory("feature-launcher-repo"); + getLog().info("Created temporary repository at: " + tempRepo); + + // Store the main project artifact if it has a file + org.apache.maven.artifact.Artifact mainArtifact = project.getArtifact(); + if (mainArtifact != null + && mainArtifact.getFile() != null + && mainArtifact.getFile().exists()) { + copyArtifactToRepository(mainArtifact, tempRepo); + } + + // Store all attached artifacts + for (org.apache.maven.artifact.Artifact attachedArtifact : project.getAttachedArtifacts()) { + if (attachedArtifact.getFile() != null && attachedArtifact.getFile().exists()) { + copyArtifactToRepository(attachedArtifact, tempRepo); + } + } + + return tempRepo; + } + + /** + * Copies an artifact to the repository following Maven2 repository layout. + * Layout: groupId/artifactId/version/artifactId-version[-classifier].extension + * + * @param artifact the artifact to copy + * @param repoPath the path to the repository root + * @throws IOException if the copy fails + */ + private void copyArtifactToRepository(org.apache.maven.artifact.Artifact artifact, Path repoPath) + throws IOException { + // Build the path following Maven2 layout: groupId/artifactId/version/ + String groupPath = artifact.getGroupId().replace('.', '/'); + Path artifactDir = + repoPath.resolve(groupPath).resolve(artifact.getArtifactId()).resolve(artifact.getVersion()); + + Files.createDirectories(artifactDir); + + // Build the filename: artifactId-version[-classifier].extension + StringBuilder filename = new StringBuilder(); + filename.append(artifact.getArtifactId()).append("-").append(artifact.getVersion()); + if (artifact.getClassifier() != null && !artifact.getClassifier().isEmpty()) { + filename.append("-").append(artifact.getClassifier()); + } + String extension = artifact.getType(); + if (artifact.getArtifactHandler() != null + && artifact.getArtifactHandler().getExtension() != null) { + extension = artifact.getArtifactHandler().getExtension(); + } + filename.append(".").append(extension); + + Path targetFile = artifactDir.resolve(filename.toString()); + Files.copy(artifact.getFile().toPath(), targetFile); + + getLog().debug("Copied artifact " + artifact + " to " + targetFile); + } } diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java b/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java index 2b3c46d..eff88f4 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/StopMojo.java @@ -18,6 +18,12 @@ */ package org.apache.sling.maven.feature.launcher; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.List; import org.apache.maven.execution.MavenExecutionRequest; @@ -92,11 +98,55 @@ public class StopMojo extends AbstractMojo { getLog().info("Stopping launch with id " + launch.getId()); processes.stop(launch.getId()); } + + // Clean up the temporary repository + cleanupTempRepository(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } + /** + * Cleans up the temporary repository directory created by the StartMojo. + */ + private void cleanupTempRepository() { + Path tempRepo = processes.getTempRepository(); + if (tempRepo != null) { + try { + getLog().info("Cleaning up temporary repository at: " + tempRepo); + deleteDirectoryRecursively(tempRepo); + processes.clearTempRepository(); + } catch (IOException e) { + getLog().warn("Failed to clean up temporary repository at " + tempRepo + ": " + e.getMessage()); + } + } + } + + /** + * Recursively deletes a directory and all its contents. + * + * @param path the path to the directory to delete + * @throws IOException if the deletion fails + */ + private void deleteDirectoryRecursively(Path path) throws IOException { + if (!Files.exists(path)) { + return; + } + Files.walkFileTree(path, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + protected void waitForUserInput() throws MojoFailureException { // http://stackoverflow.com/a/21977269/5155923 try {
