This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch issue/SLING-11387 in repository https://gitbox.apache.org/repos/asf/sling-feature-launcher-maven-plugin.git
commit 843f625b1b23efbb050d7547be14786b94bc9911 Author: Robert Munteanu <[email protected]> AuthorDate: Mon Jun 13 16:05:54 2022 +0200 SLING-11387 - Allow overriding the version selected artifact ids when launching Add an 'additionalBundles' configuration section that can be used to configure extra bundles and ensures that the defined version is used. --- .../sling/maven/feature/launcher/Launch.java | 29 ++++--- .../maven/feature/launcher/LauncherArguments.java | 4 +- .../sling/maven/feature/launcher/StartMojo.java | 94 +++++++++++++++++----- src/main/resources/override-bundles-template.json | 6 ++ 4 files changed, 100 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java b/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java index a0c3d10..6fba085 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java @@ -18,15 +18,17 @@ */ package org.apache.sling.maven.feature.launcher; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.apache.maven.model.Dependency; public class Launch { - + private static final Pattern ID_PATTERN = Pattern.compile("[a-zA-Z0-9_\\-\\.]+"); private String id; @@ -35,6 +37,7 @@ public class Launch { private int startTimeoutSeconds = 30; private boolean skip = false; private Map<String,String> environmentVariables = new HashMap<>(); + private List<String> additionalBundles = new ArrayList<>(); public String getId() { return id; @@ -59,11 +62,11 @@ public class Launch { public void setLauncherArguments(LauncherArguments launcherArguments) { this.launcherArguments = launcherArguments; } - + public int getStartTimeoutSeconds() { return startTimeoutSeconds; } - + public void setStartTimeoutSeconds(int startTimeoutSeconds) { this.startTimeoutSeconds = startTimeoutSeconds; } @@ -86,23 +89,31 @@ public class Launch { this.environmentVariables = environmentVariables; } + public List<String> getAdditionalBundles() { + return additionalBundles; + } + + public void setAdditionalBundles(List<String> additionalBundles) { + this.additionalBundles = additionalBundles; + } + public void validate() { - if ( id == null || id.trim().isEmpty() ) + if ( id == null || id.trim().isEmpty() ) throw new IllegalArgumentException("Missing id"); - + if ( !ID_PATTERN.matcher(id).matches() ) throw new IllegalArgumentException("Invalid id '" + id + "'. Allowed characters are digits, numbers, '-','_' and '.'."); - + if ( startTimeoutSeconds < 0 ) throwInvalid("startTimeout value '" + startTimeoutSeconds + "' is negative" ); - + if ( feature == null ) throwInvalid("required field 'feature' is missing"); - + if ( ! "slingosgifeature".equals(feature.getType()) ) throwInvalid("type must be 'slingosgifeature' but is '" + feature.getType()+"'"); } - + private void throwInvalid(String reason) { throw new IllegalArgumentException("Invalid launch '" + id + "': " + reason); } diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/LauncherArguments.java b/src/main/java/org/apache/sling/maven/feature/launcher/LauncherArguments.java index 3693172..e70c68f 100644 --- a/src/main/java/org/apache/sling/maven/feature/launcher/LauncherArguments.java +++ b/src/main/java/org/apache/sling/maven/feature/launcher/LauncherArguments.java @@ -26,7 +26,7 @@ public class LauncherArguments { private String[] vmOptions = new String[0]; private Map<String, String> frameworkProperties = new HashMap<>(); private Map<String, String> variables = new HashMap<>(); - + public String[] getVmOptions() { return vmOptions; } @@ -38,7 +38,7 @@ public class LauncherArguments { public Map<String, String> getFrameworkProperties() { return frameworkProperties; } - + public void setFrameworkProperties(Map<String, String> frameworkProperties) { this.frameworkProperties = frameworkProperties; } 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 b25849e..b8965a8 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 @@ -22,14 +22,20 @@ package org.apache.sling.maven.feature.launcher; import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.lang.ProcessBuilder.Redirect; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.apache.commons.io.IOUtils; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; import org.apache.maven.plugin.AbstractMojo; @@ -51,7 +57,7 @@ import org.eclipse.aether.resolution.ArtifactResult; @Mojo( name = "start", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST ) public class StartMojo extends AbstractMojo { - + /** * Location of the file. */ @@ -60,10 +66,10 @@ public class StartMojo extends AbstractMojo { @Parameter( required = true, defaultValue = "1.1.4") private String featureLauncherVersion; - + @Parameter(required = true) private List<Launch> launches; - + // <launches> // <launch> // <id>...</id> @@ -92,13 +98,15 @@ public class StartMojo extends AbstractMojo { @Parameter(property = "session", readonly = true, required = true) protected MavenSession mavenSession; - + @Component private ProcessTracker processes; - + + @Override public void execute() throws MojoExecutionException, MojoFailureException { Artifact launcherArtifact = new DefaultArtifact("org.apache.sling:org.apache.sling.feature.launcher:" + featureLauncherVersion); + List<Path> cleanupPaths = new ArrayList<>(); try { RepositorySystemSession repositorySession = mavenSession.getRepositorySession(); @@ -106,10 +114,10 @@ public class StartMojo extends AbstractMojo { .resolveArtifact(repositorySession, new ArtifactRequest(launcherArtifact, remoteRepos, null)) .getArtifact() .getFile(); - + File workDir = new File(outputDirectory, "launchers"); workDir.mkdirs(); - + for ( Launch launch : launches ) { if (launch.isSkip()) { getLog().info("Skipping starting launch with id " + launch.getId()); @@ -119,10 +127,10 @@ public class StartMojo extends AbstractMojo { launch.validate(); Artifact artifact = toArtifact(launch.getFeature()); - + ArtifactResult result = resolver.resolveArtifact(repositorySession, new ArtifactRequest(artifact, remoteRepos, null)); File featureFile = result.getArtifact().getFile(); - + List<String> args = new ArrayList<>(); String javahome = System.getenv("JAVA_HOME"); if (javahome == null || javahome.isEmpty()) { @@ -133,25 +141,36 @@ public class StartMojo extends AbstractMojo { args.add(javahome + File.separatorChar + "bin" + File.separatorChar + "java"); // SLING-9994 - if any extra vm options were supplied, apply them here String[] vmOptions = launch.getLauncherArguments().getVmOptions(); - if (vmOptions != null) { - for (String vmOption : vmOptions) { - if (vmOption != null && !vmOption.isEmpty()) { - args.add(vmOption); - } + for (String vmOption : vmOptions) { + if (vmOption != null && !vmOption.isEmpty()) { + args.add(vmOption); } } args.add("-jar"); args.add(launcher.getAbsolutePath()); args.add("-f"); - args.add(featureFile.getAbsolutePath()); + if ( ! launch.getAdditionalBundles().isEmpty() ) { + Path overridePath = createOverrideFeatureFile(launch.getAdditionalBundles(), cleanupPaths); + args.add(featureFile.getAbsolutePath() + "," + overridePath.toString()); + } else { + args.add(featureFile.getAbsolutePath()); + } + + launch.getAdditionalBundles().stream() + .map( DefaultArtifact::new ) + .forEach( a -> { + args.add("-C"); + args.add(a.getGroupId() + ":" + a.getArtifactId() + ":*:*:LATEST"); + }); + args.add("-p"); args.add(launch.getId()); - + for ( Map.Entry<String, String> frameworkProperty : launch.getLauncherArguments().getFrameworkProperties().entrySet() ) { args.add("-D"); args.add(frameworkProperty.getKey()+"="+frameworkProperty.getValue()); } - + for ( Map.Entry<String, String> variable : launch.getLauncherArguments().getVariables().entrySet() ) { args.add("-V"); args.add(variable.getKey()+"="+variable.getValue()); @@ -164,13 +183,13 @@ public class StartMojo extends AbstractMojo { pb.directory(workDir); launch.getEnvironmentVariables().entrySet() .forEach( e -> pb.environment().put(e.getKey(), e.getValue()) ); - + getLog().info("Starting launch with id '" + launch.getId() + "', args=" + args); - + CountDownLatch latch = new CountDownLatch(1); - + Process process = pb.start(); - + Thread monitor = new Thread("launch-monitor-" + launch.getId()) { @Override public void run() { @@ -196,7 +215,7 @@ public class StartMojo extends AbstractMojo { ProcessTracker.stop(process); throw new MojoExecutionException("Launch " + launch.getId() + " failed to start in " + launch.getStartTimeoutSeconds() + " seconds."); } - + processes.startTracking(launch.getId(), process); } @@ -205,7 +224,38 @@ public class StartMojo extends AbstractMojo { } catch ( InterruptedException e ) { Thread.currentThread().interrupt(); throw new MojoExecutionException("Execution interrupted", e); + } finally { + for ( Path cleanupPath : cleanupPaths ) { + try { + if ( cleanupPath.toFile().exists() ) + Files.delete(cleanupPath); + } catch (IOException e) { + getLog().warn("Failed deleting " + cleanupPath, e); + } + } + } + } + + // we strive to not pull in dependencies on the feature model and only retrieve it at runtime + // therefore we don't use the feature model API here + private Path createOverrideFeatureFile(List<String> overrideArtifacts, List<Path> cleanupPaths) throws IOException { + Path overridePath = Files.createTempFile("launcher-override-", ".json"); + cleanupPaths.add(overridePath); + String jsonFragment = overrideArtifacts.stream() + .map( a -> "{ \"id\": \"" + a + "\" }\n" ) + .collect(Collectors.joining(",")); + + + try ( InputStream inputStream = getClass().getResourceAsStream("/override-bundles-template.json") ) { + if ( inputStream == null ) + throw new IllegalArgumentException("Failed to locate feature template for artifact override"); + List<String> inputLines = IOUtils.readLines(inputStream, StandardCharsets.UTF_8); + List<String> outputLines = inputLines.stream() + .map( s -> s.replace("##BUNDLES##", jsonFragment) ) + .collect(Collectors.toList()); + Files.write(overridePath, outputLines); } + return overridePath; } private Artifact toArtifact(Dependency dependency) { diff --git a/src/main/resources/override-bundles-template.json b/src/main/resources/override-bundles-template.json new file mode 100644 index 0000000..510bfce --- /dev/null +++ b/src/main/resources/override-bundles-template.json @@ -0,0 +1,6 @@ +{ + "id":"org.apache.sling:org.apache.sling.tmp.synthetic-feature:slingosgifeature:1-SNAPSHOT", + "bundles":[ + ##BUNDLES## + ] +} \ No newline at end of file
