in impl/maven-executor/src/main/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutor.java [202:336]
protected Context doCreate(Path mavenHome, ExecutorRequest executorRequest) {
if (!Files.isDirectory(mavenHome)) {
throw new IllegalArgumentException("Installation directory must point to existing directory: " + mavenHome);
}
if (!MVN4_MAIN_CLASSES.containsKey(executorRequest.command())) {
throw new IllegalArgumentException(
getClass().getSimpleName() + " does not support command " + executorRequest.command());
}
if (executorRequest.environmentVariables().isPresent()) {
throw new IllegalArgumentException(getClass().getSimpleName() + " does not support environment variables");
}
if (executorRequest.jvmArguments().isPresent()) {
throw new IllegalArgumentException(getClass().getSimpleName() + " does not support jvmArguments");
}
Path boot = mavenHome.resolve("boot");
Path m2conf = mavenHome.resolve("bin/m2.conf");
if (!Files.isDirectory(boot) || !Files.isRegularFile(m2conf)) {
throw new IllegalArgumentException(
"Installation directory does not point to Maven installation: " + mavenHome);
}
ArrayList<String> mavenArgs = new ArrayList<>();
String mavenArgsEnv = System.getenv("MAVEN_ARGS");
if (useMavenArgsEnv && mavenArgsEnv != null && !mavenArgsEnv.isEmpty()) {
Arrays.stream(mavenArgsEnv.split(" "))
.filter(s -> !s.trim().isEmpty())
.forEach(s -> mavenArgs.add(0, s));
}
Properties properties = prepareProperties(executorRequest);
// set ahead of time, if the mavenHome points to Maven4, as ClassWorld Launcher needs this property
properties.setProperty(
"maven.mainClass", requireNonNull(MVN4_MAIN_CLASSES.get(ExecutorRequest.MVN), "mainClass"));
System.setProperties(properties);
URLClassLoader bootClassLoader = createMavenBootClassLoader(boot, Collections.emptyList());
Thread.currentThread().setContextClassLoader(bootClassLoader);
try {
Class<?> launcherClass = bootClassLoader.loadClass("org.codehaus.plexus.classworlds.launcher.Launcher");
Object launcher = launcherClass.getDeclaredConstructor().newInstance();
Method configure = launcherClass.getMethod("configure", InputStream.class);
try (InputStream inputStream = Files.newInputStream(m2conf)) {
configure.invoke(launcher, inputStream);
}
Object classWorld = launcherClass.getMethod("getWorld").invoke(launcher);
Set<String> originalClassRealmIds = new HashSet<>();
// collect pre-created (in m2.conf) class realms as "original ones"; the rest are created at runtime
Method getRealms = classWorld.getClass().getMethod("getRealms");
List<Object> realms = (List<Object>) getRealms.invoke(classWorld);
for (Object realm : realms) {
Method realmGetId = realm.getClass().getMethod("getId");
originalClassRealmIds.add((String) realmGetId.invoke(realm));
}
Class<?> cliClass =
(Class<?>) launcherClass.getMethod("getMainClass").invoke(launcher);
String version = getMavenVersion(cliClass);
Map<String, Function<ExecutorRequest, Integer>> commands = new HashMap<>();
ArrayList<Object> keepAlive = new ArrayList<>();
if (version.startsWith("3.")) {
// 3.x
if (!ExecutorRequest.MVN.equals(executorRequest.command())) {
throw new IllegalArgumentException(getClass().getSimpleName() + " w/ mvn3 does not support command "
+ executorRequest.command());
}
keepAlive.add(cliClass.getClassLoader().loadClass("org.fusesource.jansi.internal.JansiLoader"));
Constructor<?> newMavenCli = cliClass.getConstructor(classWorld.getClass());
Object mavenCli = newMavenCli.newInstance(classWorld);
Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class};
Method doMain = cliClass.getMethod("doMain", parameterTypes);
commands.put(ExecutorRequest.MVN, r -> {
System.setProperties(prepareProperties(r));
try {
ArrayList<String> args = new ArrayList<>(mavenArgs);
args.addAll(r.arguments());
PrintStream stdout = r.stdOut().isEmpty()
? null
: new PrintStream(r.stdOut().orElseThrow(), true);
PrintStream stderr = r.stdErr().isEmpty()
? null
: new PrintStream(r.stdErr().orElseThrow(), true);
return (int) doMain.invoke(mavenCli, new Object[] {
args.toArray(new String[0]), r.cwd().toString(), stdout, stderr
});
} catch (Exception e) {
throw new ExecutorException("Failed to execute", e);
}
});
} else {
// assume 4.x
keepAlive.add(cliClass.getClassLoader().loadClass("org.jline.nativ.JLineNativeLoader"));
for (Map.Entry<String, String> cmdEntry : MVN4_MAIN_CLASSES.entrySet()) {
Class<?> cmdClass = cliClass.getClassLoader().loadClass(cmdEntry.getValue());
Method mainMethod = cmdClass.getMethod(
"main",
String[].class,
classWorld.getClass(),
InputStream.class,
OutputStream.class,
OutputStream.class);
commands.put(cmdEntry.getKey(), r -> {
System.setProperties(prepareProperties(r));
try {
ArrayList<String> args = new ArrayList<>(mavenArgs);
args.addAll(r.arguments());
return (int) mainMethod.invoke(
null,
args.toArray(new String[0]),
classWorld,
r.stdIn().orElse(null),
r.stdOut().orElse(null),
r.stdErr().orElse(null));
} catch (Exception e) {
throw new ExecutorException("Failed to execute", e);
}
});
}
}
return new Context(
bootClassLoader,
version,
classWorld,
originalClassRealmIds,
cliClass.getClassLoader(),
commands,
keepAlive);
} catch (Exception e) {
throw new ExecutorException("Failed to create executor", e);
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
System.setProperties(originalProperties);
}
}