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 {

Reply via email to