[MNG-8283] More mvnd related changes (#1775)

Changes:
* there is only one parser for "just maven", no need for 3
* aligned scopes (public) of local context for simplicity, we can fix visibility later
* allow custom guice modules (unused, may undo this)
* split logging setup in two steps: config and activate

---

https://issues.apache.org/jira/browse/MNG-8283
This commit is contained in:
Tamas Cservenak 2024-10-04 17:33:25 +02:00 committed by GitHub
parent 533790bb4a
commit 60ae468a2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 174 additions and 633 deletions

View File

@ -1,32 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.cli.mvn.local;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.cli.mvn.MavenParser;
/**
* Local parser.
*
* @since 4.0.0
*/
@Experimental
public interface LocalMavenParser extends MavenParser<MavenInvokerRequest<MavenOptions>> {}

View File

@ -21,6 +21,8 @@ package org.apache.maven.api.cli.mvn.resident;
import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.mvn.MavenInvoker; import org.apache.maven.api.cli.mvn.MavenInvoker;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions;
/** /**
* Resident invoker. Instance is shut down when this instance is closed. * Resident invoker. Instance is shut down when this instance is closed.
@ -28,7 +30,7 @@ import org.apache.maven.api.cli.mvn.MavenInvoker;
* @since 4.0.0 * @since 4.0.0
*/ */
@Experimental @Experimental
public interface ResidentMavenInvoker extends MavenInvoker<ResidentMavenInvokerRequest> { public interface ResidentMavenInvoker extends MavenInvoker<MavenInvokerRequest<MavenOptions>> {
/** /**
* Closes cleanly the daemon. * Closes cleanly the daemon.
*/ */

View File

@ -1,36 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.cli.mvn.resident;
import java.util.List;
import java.util.Optional;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
public interface ResidentMavenInvokerRequest extends MavenInvokerRequest<ResidentMavenOptions> {
/**
* Returns the list of extra JVM arguments to be passed to the forked Maven process.
* These arguments allow for customization of the JVM environment in which Maven will run.
*
* @return an Optional containing the list of extra JVM arguments, or empty if not specified
*/
@Nonnull
Optional<List<String>> jvmArguments();
}

View File

@ -1,50 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.cli.mvn.resident;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.cli.mvn.MavenOptions;
/**
* Resident options.
*/
@Experimental
public interface ResidentMavenOptions extends MavenOptions {
/**
* Indicates whether raw streams should be used with daemon.
*
* @return an {@link Optional} containing true if raw streams are enabled, false if disabled, or empty if not specified
*/
@Nonnull
Optional<Boolean> rawStreams();
/**
* Returns a new instance of {@link MavenOptions} with values interpolated using the given properties.
*
* @param properties a collection of property maps to use for interpolation
* @return a new MavenOptions instance with interpolated values
*/
@Nonnull
ResidentMavenOptions interpolate(@Nonnull Collection<Map<String, String>> properties);
}

View File

@ -1,30 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.cli.mvn.resident;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.cli.mvn.MavenParser;
/**
* Resident parser.
*
* @since 4.0.0
*/
@Experimental
public interface ResidentMavenParser extends MavenParser<ResidentMavenInvokerRequest> {}

View File

@ -26,8 +26,8 @@ import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.cling.invoker.ProtoLogger;
import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.cling.invoker.mvn.DefaultMavenParser;
import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenInvoker; import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenInvoker;
import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenParser;
import org.apache.maven.jline.JLineMessageBuilderFactory; import org.apache.maven.jline.JLineMessageBuilderFactory;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
@ -67,6 +67,6 @@ public class MavenCling extends ClingSupport<MavenOptions, MavenInvokerRequest<M
@Override @Override
protected MavenInvokerRequest<MavenOptions> parseArguments(String[] args) throws ParserException, IOException { protected MavenInvokerRequest<MavenOptions> parseArguments(String[] args) throws ParserException, IOException {
return new DefaultLocalMavenParser().mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory()); return new DefaultMavenParser().mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory());
} }
} }

View File

@ -121,6 +121,7 @@ public abstract class LookupInvoker<
public Logger logger; public Logger logger;
public ILoggerFactory loggerFactory; public ILoggerFactory loggerFactory;
public Slf4jConfiguration slf4jConfiguration;
public Slf4jConfiguration.Level loggerLevel; public Slf4jConfiguration.Level loggerLevel;
public ContainerCapsule containerCapsule; public ContainerCapsule containerCapsule;
public Lookup lookup; public Lookup lookup;
@ -156,6 +157,7 @@ public abstract class LookupInvoker<
validate(context); validate(context);
prepare(context); prepare(context);
logging(context); logging(context);
activateLogging(context);
if (invokerRequest.options().help().isPresent()) { if (invokerRequest.options().help().isPresent()) {
invokerRequest.options().displayHelp(context.invokerRequest.parserRequest(), context.stdOut); invokerRequest.options().displayHelp(context.invokerRequest.parserRequest(), context.stdOut);
@ -231,7 +233,7 @@ public abstract class LookupInvoker<
} }
context.loggerFactory = LoggerFactory.getILoggerFactory(); context.loggerFactory = LoggerFactory.getILoggerFactory();
Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(context.loggerFactory); context.slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(context.loggerFactory);
context.loggerLevel = Slf4jConfiguration.Level.INFO; context.loggerLevel = Slf4jConfiguration.Level.INFO;
if (mavenOptions.verbose().orElse(false)) { if (mavenOptions.verbose().orElse(false)) {
@ -239,7 +241,7 @@ public abstract class LookupInvoker<
} else if (mavenOptions.quiet().orElse(false)) { } else if (mavenOptions.quiet().orElse(false)) {
context.loggerLevel = Slf4jConfiguration.Level.ERROR; context.loggerLevel = Slf4jConfiguration.Level.ERROR;
} }
slf4jConfiguration.setRootLoggerLevel(context.loggerLevel); context.slf4jConfiguration.setRootLoggerLevel(context.loggerLevel);
// else fall back to default log level specified in conf // else fall back to default log level specified in conf
// see https://issues.apache.org/jira/browse/MNG-2570 // see https://issues.apache.org/jira/browse/MNG-2570
@ -255,8 +257,13 @@ public abstract class LookupInvoker<
throw new InvokerException("Cannot set up log " + e.getMessage(), e); throw new InvokerException("Cannot set up log " + e.getMessage(), e);
} }
} }
}
slf4jConfiguration.activate(); protected void activateLogging(C context) throws Exception {
R invokerRequest = context.invokerRequest;
Options mavenOptions = invokerRequest.options();
context.slf4jConfiguration.activate();
org.slf4j.Logger l = context.loggerFactory.getLogger(this.getClass().getName()); org.slf4j.Logger l = context.loggerFactory.getLogger(this.getClass().getName());
context.logger = (level, message, error) -> l.atLevel(org.slf4j.event.Level.valueOf(level.name())) context.logger = (level, message, error) -> l.atLevel(org.slf4j.event.Level.valueOf(level.name()))
.setCause(error) .setCause(error)

View File

@ -28,6 +28,7 @@ import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Module;
import org.apache.maven.api.Constants; import org.apache.maven.api.Constants;
import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.InvokerRequest;
@ -103,16 +104,9 @@ public class PlexusContainerCapsuleFactory<
exportedArtifacts.addAll(extension.getExportedArtifacts()); exportedArtifacts.addAll(extension.getExportedArtifacts());
exportedPackages.addAll(extension.getExportedPackages()); exportedPackages.addAll(extension.getExportedPackages());
} }
final CoreExports exports = new CoreExports(containerRealm, exportedArtifacts, exportedPackages); CoreExports exports = new CoreExports(containerRealm, exportedArtifacts, exportedPackages);
Thread.currentThread().setContextClassLoader(containerRealm); Thread.currentThread().setContextClassLoader(containerRealm);
DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() { DefaultPlexusContainer container = new DefaultPlexusContainer(cc, getCustomModule(context, exports));
@Override
protected void configure() {
bind(ILoggerFactory.class).toInstance(context.loggerFactory);
bind(CoreExports.class).toInstance(exports);
bind(MessageBuilderFactory.class).toInstance(context.invokerRequest.messageBuilderFactory());
}
});
// NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups
container.setLookupRealm(null); container.setLookupRealm(null);
@ -157,6 +151,22 @@ public class PlexusContainerCapsuleFactory<
return container; return container;
} }
/**
* Note: overriding this method should be avoided. Preferred way to replace Maven components is the "normal" way
* where the components are on index (are annotated with JSR330 annotations and Sisu index is created) and, they
* have priorities set.
*/
protected Module getCustomModule(C context, CoreExports exports) {
return new AbstractModule() {
@Override
protected void configure() {
bind(ILoggerFactory.class).toInstance(context.loggerFactory);
bind(CoreExports.class).toInstance(exports);
bind(MessageBuilderFactory.class).toInstance(context.invokerRequest.messageBuilderFactory());
}
};
}
protected void customizeContainerConfiguration(C context, ContainerConfiguration configuration) throws Exception {} protected void customizeContainerConfiguration(C context, ContainerConfiguration configuration) throws Exception {}
protected void customizeContainer(C context, PlexusContainer container) throws Exception {} protected void customizeContainer(C context, PlexusContainer container) throws Exception {}

View File

@ -0,0 +1,87 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker.mvn;
import java.io.IOException;
import java.nio.charset.Charset;
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.stream.Stream;
import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserException;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.cli.mvn.MavenParser;
import org.apache.maven.cling.invoker.BaseParser;
public abstract class BaseMavenParser<O extends MavenOptions, R extends MavenInvokerRequest<O>> extends BaseParser<O, R>
implements MavenParser<R> {
@SuppressWarnings("ParameterNumber")
@Override
protected abstract R getInvokerRequest(
ParserRequest parserRequest,
Path cwd,
Path installationDirectory,
Path userHomeDirectory,
Map<String, String> userProperties,
Map<String, String> systemProperties,
Path topDirectory,
Path rootDirectory,
ArrayList<CoreExtension> extensions,
Options options);
@Override
protected List<O> parseCliOptions(Path rootDirectory, List<String> args) throws ParserException, IOException {
ArrayList<O> result = new ArrayList<>();
// CLI args
result.add(parseMavenCliOptions(args));
// maven.config; if exists
Path mavenConfig = rootDirectory.resolve(".mvn/maven.config");
if (Files.isRegularFile(mavenConfig)) {
result.add(parseMavenConfigOptions(mavenConfig));
}
return result;
}
protected O parseMavenCliOptions(List<String> args) throws ParserException {
return parseArgs(Options.SOURCE_CLI, args);
}
protected O parseMavenConfigOptions(Path configFile) throws ParserException, IOException {
try (Stream<String> lines = Files.lines(configFile, Charset.defaultCharset())) {
List<String> args =
lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#")).toList();
O options = parseArgs("maven.config", args);
if (options.goals().isPresent()) {
// This file can only contain options, not args (goals or phases)
throw new ParserException("Unrecognized maven.config file entries: "
+ options.goals().get());
}
return options;
}
}
protected abstract O parseArgs(String source, List<String> args) throws ParserException;
}

View File

@ -76,7 +76,7 @@ public abstract class DefaultMavenInvoker<
extends LookupInvoker<O, R, C> implements MavenInvoker<R> { extends LookupInvoker<O, R, C> implements MavenInvoker<R> {
@SuppressWarnings("VisibilityModifier") @SuppressWarnings("VisibilityModifier")
protected static class MavenContext< public static class MavenContext<
O extends MavenOptions, O extends MavenOptions,
R extends MavenInvokerRequest<O>, R extends MavenInvokerRequest<O>,
C extends DefaultMavenInvoker.MavenContext<O, R, C>> C extends DefaultMavenInvoker.MavenContext<O, R, C>>

View File

@ -18,15 +18,12 @@
*/ */
package org.apache.maven.cling.invoker.mvn; package org.apache.maven.cling.invoker.mvn;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream;
import org.apache.commons.cli.ParseException;
import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserException; import org.apache.maven.api.cli.ParserException;
import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.api.cli.ParserRequest;
@ -34,13 +31,12 @@ import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.cli.mvn.MavenParser; import org.apache.maven.api.cli.mvn.MavenParser;
import org.apache.maven.cling.invoker.BaseParser;
public abstract class DefaultMavenParser<O extends MavenOptions, R extends MavenInvokerRequest<O>> public class DefaultMavenParser extends BaseMavenParser<MavenOptions, MavenInvokerRequest<MavenOptions>>
extends BaseParser<O, R> implements MavenParser<R> { implements MavenParser<MavenInvokerRequest<MavenOptions>> {
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
@Override @Override
protected abstract R getInvokerRequest( protected DefaultMavenInvokerRequest<MavenOptions> getInvokerRequest(
ParserRequest parserRequest, ParserRequest parserRequest,
Path cwd, Path cwd,
Path installationDirectory, Path installationDirectory,
@ -50,38 +46,34 @@ public abstract class DefaultMavenParser<O extends MavenOptions, R extends Maven
Path topDirectory, Path topDirectory,
Path rootDirectory, Path rootDirectory,
ArrayList<CoreExtension> extensions, ArrayList<CoreExtension> extensions,
Options options); Options options) {
return new DefaultMavenInvokerRequest<>(
parserRequest,
cwd,
installationDirectory,
userHomeDirectory,
userProperties,
systemProperties,
topDirectory,
rootDirectory,
parserRequest.in(),
parserRequest.out(),
parserRequest.err(),
extensions,
(MavenOptions) options);
}
@Override @Override
protected List<O> parseCliOptions(Path rootDirectory, List<String> args) throws ParserException, IOException { protected MavenOptions parseArgs(String source, List<String> args) throws ParserException {
ArrayList<O> result = new ArrayList<>(); try {
// CLI args return CommonsCliMavenOptions.parse(source, args.toArray(new String[0]));
result.add(parseMavenCliOptions(args)); } catch (ParseException e) {
// maven.config; if exists throw new ParserException("Failed to parse source " + source, e.getCause());
Path mavenConfig = rootDirectory.resolve(".mvn/maven.config");
if (Files.isRegularFile(mavenConfig)) {
result.add(parseMavenConfigOptions(mavenConfig));
}
return result;
}
protected O parseMavenCliOptions(List<String> args) throws ParserException {
return parseArgs(Options.SOURCE_CLI, args);
}
protected O parseMavenConfigOptions(Path configFile) throws ParserException, IOException {
try (Stream<String> lines = Files.lines(configFile, Charset.defaultCharset())) {
List<String> args =
lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#")).toList();
O options = parseArgs("maven.config", args);
if (options.goals().isPresent()) {
// This file can only contain options, not args (goals or phases)
throw new ParserException("Unrecognized maven.config file entries: "
+ options.goals().get());
}
return options;
} }
} }
protected abstract O parseArgs(String source, List<String> args) throws ParserException; @Override
protected MavenOptions assembleOptions(List<MavenOptions> parsedOptions) {
return LayeredMavenOptions.layerMavenOptions(parsedOptions);
}
} }

View File

@ -31,11 +31,11 @@ import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.cli.mvn.forked.ForkedMavenInvokerRequest; import org.apache.maven.api.cli.mvn.forked.ForkedMavenInvokerRequest;
import org.apache.maven.api.cli.mvn.forked.ForkedMavenParser; import org.apache.maven.api.cli.mvn.forked.ForkedMavenParser;
import org.apache.maven.cling.invoker.mvn.BaseMavenParser;
import org.apache.maven.cling.invoker.mvn.CommonsCliMavenOptions; import org.apache.maven.cling.invoker.mvn.CommonsCliMavenOptions;
import org.apache.maven.cling.invoker.mvn.DefaultMavenParser;
import org.apache.maven.cling.invoker.mvn.LayeredMavenOptions; import org.apache.maven.cling.invoker.mvn.LayeredMavenOptions;
public class DefaultForkedMavenParser extends DefaultMavenParser<MavenOptions, ForkedMavenInvokerRequest> public class DefaultForkedMavenParser extends BaseMavenParser<MavenOptions, ForkedMavenInvokerRequest>
implements ForkedMavenParser { implements ForkedMavenParser {
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
@ -76,6 +76,7 @@ public class DefaultForkedMavenParser extends DefaultMavenParser<MavenOptions, F
return null; return null;
} }
// TODO: same is in DefaultMavenParser!!! (duplication)
@Override @Override
protected MavenOptions parseArgs(String source, List<String> args) throws ParserException { protected MavenOptions parseArgs(String source, List<String> args) throws ParserException {
try { try {
@ -85,6 +86,7 @@ public class DefaultForkedMavenParser extends DefaultMavenParser<MavenOptions, F
} }
} }
// TODO: same is in DefaultMavenParser!!! (duplication)
@Override @Override
protected MavenOptions assembleOptions(List<MavenOptions> parsedOptions) { protected MavenOptions assembleOptions(List<MavenOptions> parsedOptions) {
return LayeredMavenOptions.layerMavenOptions(parsedOptions); return LayeredMavenOptions.layerMavenOptions(parsedOptions);

View File

@ -29,7 +29,7 @@ public class DefaultLocalMavenInvoker
MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultLocalMavenInvoker.LocalContext> MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultLocalMavenInvoker.LocalContext>
implements LocalMavenInvoker { implements LocalMavenInvoker {
protected static class LocalContext public static class LocalContext
extends DefaultMavenInvoker.MavenContext< extends DefaultMavenInvoker.MavenContext<
MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultLocalMavenInvoker.LocalContext> { MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultLocalMavenInvoker.LocalContext> {
protected LocalContext(DefaultLocalMavenInvoker invoker, MavenInvokerRequest<MavenOptions> invokerRequest) { protected LocalContext(DefaultLocalMavenInvoker invoker, MavenInvokerRequest<MavenOptions> invokerRequest) {

View File

@ -1,83 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker.mvn.local;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.cli.ParseException;
import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserException;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.cli.mvn.local.LocalMavenParser;
import org.apache.maven.cling.invoker.mvn.CommonsCliMavenOptions;
import org.apache.maven.cling.invoker.mvn.DefaultMavenInvokerRequest;
import org.apache.maven.cling.invoker.mvn.DefaultMavenParser;
import org.apache.maven.cling.invoker.mvn.LayeredMavenOptions;
public class DefaultLocalMavenParser extends DefaultMavenParser<MavenOptions, MavenInvokerRequest<MavenOptions>>
implements LocalMavenParser {
@SuppressWarnings("ParameterNumber")
@Override
protected DefaultMavenInvokerRequest<MavenOptions> getInvokerRequest(
ParserRequest parserRequest,
Path cwd,
Path installationDirectory,
Path userHomeDirectory,
Map<String, String> userProperties,
Map<String, String> systemProperties,
Path topDirectory,
Path rootDirectory,
ArrayList<CoreExtension> extensions,
Options options) {
return new DefaultMavenInvokerRequest<>(
parserRequest,
cwd,
installationDirectory,
userHomeDirectory,
userProperties,
systemProperties,
topDirectory,
rootDirectory,
parserRequest.in(),
parserRequest.out(),
parserRequest.err(),
extensions,
(MavenOptions) options);
}
@Override
protected MavenOptions parseArgs(String source, List<String> args) throws ParserException {
try {
return CommonsCliMavenOptions.parse(source, args.toArray(new String[0]));
} catch (ParseException e) {
throw new ParserException("Failed to parse source " + source, e.getCause());
}
}
@Override
protected MavenOptions assembleOptions(List<MavenOptions> parsedOptions) {
return LayeredMavenOptions.layerMavenOptions(parsedOptions);
}
}

View File

@ -1,100 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker.mvn.resident;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions;
import org.apache.maven.cling.invoker.mvn.CommonsCliMavenOptions;
import org.codehaus.plexus.interpolation.BasicInterpolator;
import org.codehaus.plexus.interpolation.InterpolationException;
import static org.apache.maven.cling.invoker.Utils.createInterpolator;
public class CommonsCliResidentMavenOptions extends CommonsCliMavenOptions implements ResidentMavenOptions {
public static CommonsCliResidentMavenOptions parse(String source, String[] args) throws ParseException {
CLIManager cliManager = new CLIManager();
return new CommonsCliResidentMavenOptions(source, cliManager, cliManager.parse(args));
}
protected CommonsCliResidentMavenOptions(String source, CLIManager cliManager, CommandLine commandLine) {
super(source, cliManager, commandLine);
}
@Override
public Optional<Boolean> rawStreams() {
if (commandLine.hasOption(CLIManager.RAW_STREAMS)) {
return Optional.of(Boolean.TRUE);
}
return Optional.empty();
}
private static CommonsCliResidentMavenOptions interpolate(
CommonsCliResidentMavenOptions options, Collection<Map<String, String>> properties) {
try {
// now that we have properties, interpolate all arguments
BasicInterpolator interpolator = createInterpolator(properties);
CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
commandLineBuilder.setDeprecatedHandler(o -> {});
for (Option option : options.commandLine.getOptions()) {
if (!CLIManager.USER_PROPERTY.equals(option.getOpt())) {
List<String> values = option.getValuesList();
for (ListIterator<String> it = values.listIterator(); it.hasNext(); ) {
it.set(interpolator.interpolate(it.next()));
}
}
commandLineBuilder.addOption(option);
}
for (String arg : options.commandLine.getArgList()) {
commandLineBuilder.addArg(interpolator.interpolate(arg));
}
return new CommonsCliResidentMavenOptions(
options.source, (CLIManager) options.cliManager, commandLineBuilder.build());
} catch (InterpolationException e) {
throw new IllegalArgumentException("Could not interpolate CommonsCliOptions", e);
}
}
@Override
public ResidentMavenOptions interpolate(Collection<Map<String, String>> properties) {
return interpolate(this, properties);
}
protected static class CLIManager extends CommonsCliMavenOptions.CLIManager {
public static final String RAW_STREAMS = "ras";
@Override
protected void prepareOptions(Options options) {
super.prepareOptions(options);
options.addOption(Option.builder(RAW_STREAMS)
.longOpt("raw-streams")
.hasArg()
.desc("Use raw-streams for daemon communication")
.build());
}
}
}

View File

@ -22,9 +22,9 @@ import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvoker; import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvoker;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvokerRequest;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions;
import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.cling.invoker.mvn.DefaultMavenInvoker; import org.apache.maven.cling.invoker.mvn.DefaultMavenInvoker;
@ -34,14 +34,14 @@ import org.apache.maven.cling.invoker.mvn.DefaultMavenInvoker;
*/ */
public class DefaultResidentMavenInvoker public class DefaultResidentMavenInvoker
extends DefaultMavenInvoker< extends DefaultMavenInvoker<
ResidentMavenOptions, ResidentMavenInvokerRequest, DefaultResidentMavenInvoker.LocalContext> MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultResidentMavenInvoker.LocalContext>
implements ResidentMavenInvoker { implements ResidentMavenInvoker {
protected static class LocalContext public static class LocalContext
extends DefaultMavenInvoker.MavenContext< extends DefaultMavenInvoker.MavenContext<
ResidentMavenOptions, ResidentMavenInvokerRequest, DefaultResidentMavenInvoker.LocalContext> { MavenOptions, MavenInvokerRequest<MavenOptions>, DefaultResidentMavenInvoker.LocalContext> {
protected LocalContext(DefaultResidentMavenInvoker invoker, ResidentMavenInvokerRequest invokerRequest) { protected LocalContext(DefaultResidentMavenInvoker invoker, MavenInvokerRequest<MavenOptions> invokerRequest) {
super(invoker, invokerRequest); super(invoker, invokerRequest);
} }
@ -54,7 +54,7 @@ public class DefaultResidentMavenInvoker
super.close(); super.close();
} }
public LocalContext copy(ResidentMavenInvokerRequest invokerRequest) { public LocalContext copy(MavenInvokerRequest<MavenOptions> invokerRequest) {
LocalContext shadow = new LocalContext((DefaultResidentMavenInvoker) invoker, invokerRequest); LocalContext shadow = new LocalContext((DefaultResidentMavenInvoker) invoker, invokerRequest);
shadow.logger = logger; shadow.logger = logger;
@ -107,7 +107,7 @@ public class DefaultResidentMavenInvoker
} }
@Override @Override
protected LocalContext createContext(ResidentMavenInvokerRequest invokerRequest) { protected LocalContext createContext(MavenInvokerRequest<MavenOptions> invokerRequest) {
return residentContext return residentContext
.computeIfAbsent(getContextId(invokerRequest), k -> { .computeIfAbsent(getContextId(invokerRequest), k -> {
LocalContext master = new LocalContext(this, invokerRequest); LocalContext master = new LocalContext(this, invokerRequest);
@ -125,7 +125,7 @@ public class DefaultResidentMavenInvoker
.copy(invokerRequest); .copy(invokerRequest);
} }
protected String getContextId(ResidentMavenInvokerRequest invokerRequest) { protected String getContextId(MavenInvokerRequest<MavenOptions> invokerRequest) {
// TODO: in a moment Maven stop pushing user properties to system properties (and maybe something more) // TODO: in a moment Maven stop pushing user properties to system properties (and maybe something more)
// and allow multiple instances per JVM, this may become a pool? // and allow multiple instances per JVM, this may become a pool?
return "resident"; return "resident";

View File

@ -1,78 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker.mvn.resident;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvokerRequest;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions;
import org.apache.maven.cling.invoker.mvn.DefaultMavenInvokerRequest;
/**
* Maven execution request.
*/
public class DefaultResidentMavenInvokerRequest extends DefaultMavenInvokerRequest<ResidentMavenOptions>
implements ResidentMavenInvokerRequest {
private final List<String> jvmArguments;
@SuppressWarnings("ParameterNumber")
public DefaultResidentMavenInvokerRequest(
ParserRequest parserRequest,
Path cwd,
Path installationDirectory,
Path userHomeDirectory,
Map<String, String> userProperties,
Map<String, String> systemProperties,
Path topDirectory,
Path rootDirectory,
InputStream in,
OutputStream out,
OutputStream err,
List<CoreExtension> coreExtensions,
List<String> jvmArguments,
ResidentMavenOptions options) {
super(
parserRequest,
cwd,
installationDirectory,
userHomeDirectory,
userProperties,
systemProperties,
topDirectory,
rootDirectory,
in,
out,
err,
coreExtensions,
options);
this.jvmArguments = jvmArguments;
}
@Override
public Optional<List<String>> jvmArguments() {
return Optional.of(jvmArguments);
}
}

View File

@ -1,91 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker.mvn.resident;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.cli.ParseException;
import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserException;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvokerRequest;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenParser;
import org.apache.maven.cling.invoker.mvn.DefaultMavenParser;
public class DefaultResidentMavenParser extends DefaultMavenParser<ResidentMavenOptions, ResidentMavenInvokerRequest>
implements ResidentMavenParser {
@SuppressWarnings("ParameterNumber")
@Override
protected DefaultResidentMavenInvokerRequest getInvokerRequest(
ParserRequest parserRequest,
Path cwd,
Path installationDirectory,
Path userHomeDirectory,
Map<String, String> userProperties,
Map<String, String> systemProperties,
Path topDirectory,
Path rootDirectory,
ArrayList<CoreExtension> extensions,
Options options) {
return new DefaultResidentMavenInvokerRequest(
parserRequest,
cwd,
installationDirectory,
userHomeDirectory,
userProperties,
systemProperties,
topDirectory,
rootDirectory,
parserRequest.in(),
parserRequest.out(),
parserRequest.err(),
extensions,
getJvmArguments(rootDirectory),
(ResidentMavenOptions) options);
}
protected List<String> getJvmArguments(Path rootDirectory) {
if (rootDirectory != null) {
// TODO: do this
return Collections.emptyList();
}
return null;
}
@Override
protected ResidentMavenOptions parseArgs(String source, List<String> args) throws ParserException {
try {
return CommonsCliResidentMavenOptions.parse(source, args.toArray(new String[0]));
} catch (ParseException e) {
throw new ParserException("Failed to parse source " + source, e.getCause());
}
}
@Override
protected ResidentMavenOptions assembleOptions(List<ResidentMavenOptions> parsedOptions) {
return LayeredResidentMavenOptions.layerResidentMavenOptions(parsedOptions);
}
}

View File

@ -1,61 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker.mvn.resident;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions;
import org.apache.maven.cling.invoker.mvn.LayeredMavenOptions;
public class LayeredResidentMavenOptions extends LayeredMavenOptions<ResidentMavenOptions>
implements ResidentMavenOptions {
public static ResidentMavenOptions layerResidentMavenOptions(Collection<ResidentMavenOptions> options) {
List<ResidentMavenOptions> o = options.stream().filter(Objects::nonNull).toList();
if (o.isEmpty()) {
throw new IllegalArgumentException("No options specified (or all were null)");
} else if (o.size() == 1) {
return o.get(0);
} else {
return new LayeredResidentMavenOptions(o);
}
}
private LayeredResidentMavenOptions(List<ResidentMavenOptions> options) {
super(options);
}
@Override
public Optional<Boolean> rawStreams() {
return Optional.empty();
}
@Override
public ResidentMavenOptions interpolate(Collection<Map<String, String>> properties) {
ArrayList<ResidentMavenOptions> interpolatedOptions = new ArrayList<>(options.size());
for (ResidentMavenOptions o : options) {
interpolatedOptions.add(o.interpolate(properties));
}
return layerResidentMavenOptions(interpolatedOptions);
}
}

View File

@ -29,6 +29,7 @@ import org.apache.maven.api.cli.Parser;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.cling.invoker.mvn.DefaultMavenParser;
import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
@ -50,7 +51,7 @@ public class DefaultLocalMavenInvokerTest
@Override @Override
protected Parser<MavenInvokerRequest<MavenOptions>> createParser() { protected Parser<MavenInvokerRequest<MavenOptions>> createParser() {
return new DefaultLocalMavenParser(); return new DefaultMavenParser();
} }
@Test @Test

View File

@ -26,9 +26,10 @@ import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs; import com.google.common.jimfs.Jimfs;
import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Invoker;
import org.apache.maven.api.cli.Parser; import org.apache.maven.api.cli.Parser;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.cling.invoker.mvn.DefaultMavenParser;
import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
@ -40,18 +41,18 @@ import org.junit.jupiter.api.io.TempDir;
* Resident UT. * Resident UT.
*/ */
public class DefaultResidentMavenInvokerTest public class DefaultResidentMavenInvokerTest
extends MavenInvokerTestSupport<ResidentMavenOptions, ResidentMavenInvokerRequest> { extends MavenInvokerTestSupport<MavenOptions, MavenInvokerRequest<MavenOptions>> {
@Override @Override
protected Invoker<ResidentMavenInvokerRequest> createInvoker() { protected Invoker<MavenInvokerRequest<MavenOptions>> createInvoker() {
return new DefaultResidentMavenInvoker(ProtoLookup.builder() return new DefaultResidentMavenInvoker(ProtoLookup.builder()
.addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader())) .addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader()))
.build()); .build());
} }
@Override @Override
protected Parser<ResidentMavenInvokerRequest> createParser() { protected Parser<MavenInvokerRequest<MavenOptions>> createParser() {
return new DefaultResidentMavenParser(); return new DefaultMavenParser();
} }
@Test @Test