eu.maveniverse.maven.mima.runtime.shared.StandaloneRuntimeSupport Maven / Gradle / Ivy
/*
* Copyright (c) 2023-2024 Maveniverse Org.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*/
package eu.maveniverse.maven.mima.runtime.shared;
import static java.util.stream.Collectors.toMap;
import eu.maveniverse.maven.mima.context.Context;
import eu.maveniverse.maven.mima.context.ContextOverrides;
import eu.maveniverse.maven.mima.context.HTTPProxy;
import eu.maveniverse.maven.mima.context.Lookup;
import eu.maveniverse.maven.mima.context.MavenSystemHome;
import eu.maveniverse.maven.mima.context.MavenUserHome;
import eu.maveniverse.maven.mima.context.internal.MavenSystemHomeImpl;
import eu.maveniverse.maven.mima.context.internal.MavenUserHomeImpl;
import eu.maveniverse.maven.mima.context.internal.RuntimeSupport;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.model.ActivationFile;
import org.apache.maven.model.building.ModelProblemCollector;
import org.apache.maven.model.building.ModelProblemCollectorRequest;
import org.apache.maven.model.profile.DefaultProfileActivationContext;
import org.apache.maven.model.profile.ProfileSelector;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.apache.maven.settings.Activation;
import org.apache.maven.settings.ActivationOS;
import org.apache.maven.settings.ActivationProperty;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Profile;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Repository;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.TrackableBase;
import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
import org.apache.maven.settings.building.SettingsBuilder;
import org.apache.maven.settings.building.SettingsBuildingException;
import org.apache.maven.settings.building.SettingsProblem;
import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
import org.apache.maven.settings.crypto.SettingsDecrypter;
import org.apache.maven.settings.crypto.SettingsDecryptionResult;
import org.apache.maven.settings.merge.MavenSettingsMerger;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.aether.ConfigurationProperties;
import org.eclipse.aether.DefaultRepositoryCache;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.util.artifact.DefaultArtifactTypeRegistry;
import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
import org.eclipse.aether.util.repository.DefaultMirrorSelector;
import org.eclipse.aether.util.repository.DefaultProxySelector;
import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class StandaloneRuntimeSupport extends RuntimeSupport {
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected StandaloneRuntimeSupport(String name, int priority) {
super(name, discoverVersion(), priority, discoverMavenVersion());
}
private static String discoverVersion() {
Map version =
loadClasspathProperties("/eu/maveniverse/maven/mima/runtime/shared/internal/version.properties");
String result = version.get("version");
if (result == null || result.trim().isEmpty() || result.startsWith("${")) {
return UNKNOWN;
}
return result;
}
protected PreBoot preBoot(ContextOverrides overrides) {
Map systemProperties = defaultSystemProperties();
systemProperties.putAll(overrides.getSystemProperties());
Map userProperties = new HashMap<>(overrides.getUserProperties());
Map configProperties = new HashMap<>(systemProperties);
configProperties.putAll(userProperties);
configProperties.putAll(overrides.getConfigProperties());
Path localRepositoryOverride = safeAbsolute(overrides.getLocalRepositoryOverride());
if (localRepositoryOverride == null) {
String localRepoPath = (String) configProperties.get("maven.repo.local");
if (localRepoPath != null) {
localRepositoryOverride = Paths.get(localRepoPath).toAbsolutePath();
}
}
Path mavenSystemHome = safeAbsolute(overrides.getMavenSystemHomeOverride());
if (mavenSystemHome == null) {
String mavenHome = (String) configProperties.get("maven.home");
if (mavenHome == null) {
mavenHome = (String) configProperties.get("env.MAVEN_HOME");
}
if (mavenHome != null) {
mavenSystemHome = Paths.get(mavenHome).toAbsolutePath();
}
}
ContextOverrides alteredOverrides = overrides.toBuilder()
.systemProperties(systemProperties)
.userProperties(userProperties)
.configProperties(configProperties)
.withLocalRepositoryOverride(localRepositoryOverride)
.build();
MavenUserHomeImpl mavenUserHomeImpl = defaultMavenUserHome().derive(alteredOverrides);
MavenSystemHomeImpl mavenSystemHomeImpl =
mavenSystemHome != null ? new MavenSystemHomeImpl(mavenSystemHome).derive(alteredOverrides) : null;
Path baseDir =
alteredOverrides.getBasedirOverride() != null ? alteredOverrides.getBasedirOverride() : DEFAULT_BASEDIR;
return new PreBoot(alteredOverrides, mavenUserHomeImpl, mavenSystemHomeImpl, baseDir);
}
protected Context buildContext(
StandaloneRuntimeSupport runtime,
PreBoot preBoot,
RepositorySystem repositorySystem,
SettingsBuilder settingsBuilder,
SettingsDecrypter settingsDecrypter,
ProfileSelector profileSelector,
Lookup lookup,
Runnable managedCloser) {
try {
ContextOverrides alteredOverrides = preBoot.getOverrides();
MavenUserHomeImpl mavenUserHomeImpl = preBoot.getMavenUserHome();
MavenSystemHomeImpl mavenSystemHomeImpl = preBoot.getMavenSystemHome();
Path baseDir = preBoot.getBaseDir();
Settings settings =
newEffectiveSettings(alteredOverrides, mavenUserHomeImpl, mavenSystemHomeImpl, settingsBuilder);
// settings: local repository
if (settings.getLocalRepository() != null && alteredOverrides.getLocalRepositoryOverride() == null) {
mavenUserHomeImpl = mavenUserHomeImpl.withLocalRepository(
Paths.get(settings.getLocalRepository()).toAbsolutePath());
}
// settings: active proxy
Proxy proxy = settings.getActiveProxy();
HTTPProxy httpProxy = null;
if (proxy != null) {
httpProxy = toHTTPProxy(proxy);
}
// settings: active profiles
List activeProfiles =
activeProfilesByActivation(alteredOverrides, baseDir, settings, profileSelector);
if (!activeProfiles.isEmpty()) {
alteredOverrides = alteredOverrides.toBuilder()
.withActiveProfileIds(
activeProfiles.stream().map(Profile::getId).collect(Collectors.toList()))
.build();
}
// settings: active profile properties
// In MIMA there is no "project context", but to support Resolver configuration
// via settings.xml (MNG-7590) we push them into user properties.
// Note: putIfAbsent used, as if key is present, it means it was added via override already
HashMap profileProperties = new HashMap<>();
for (Profile profile : activeProfiles) {
profile.getProperties()
.stringPropertyNames()
.forEach(n ->
profileProperties.put(n, profile.getProperties().getProperty(n)));
}
if (!profileProperties.isEmpty()) {
Map profileUserProperties = new HashMap<>(alteredOverrides.getUserProperties());
profileProperties.forEach(profileUserProperties::putIfAbsent);
alteredOverrides = alteredOverrides.toBuilder()
.userProperties(profileUserProperties)
.build();
}
DefaultRepositorySystemSession session = newRepositorySession(
alteredOverrides, mavenUserHomeImpl, repositorySystem, settings, settingsDecrypter);
// settings: active profile repositories (if enabled), strictly preserve order
final LinkedHashMap remoteRepositories = new LinkedHashMap<>();
if (alteredOverrides.addRepositoriesOp() != ContextOverrides.AddRepositoriesOp.REPLACE) {
if (alteredOverrides.addRepositoriesOp() == ContextOverrides.AddRepositoriesOp.PREPEND) {
alteredOverrides.getRepositories().forEach(r -> remoteRepositories.put(r.getId(), r));
}
for (Profile profile : activeProfiles) {
for (Repository repository : profile.getRepositories()) {
RemoteRepository.Builder builder = new RemoteRepository.Builder(
repository.getId(), repository.getLayout(), repository.getUrl());
if (repository.getReleases() != null) {
builder.setReleasePolicy(new RepositoryPolicy(
repository.getReleases().isEnabled(),
RepositoryPolicy.UPDATE_POLICY_DAILY,
RepositoryPolicy.CHECKSUM_POLICY_WARN));
} else {
builder.setReleasePolicy(new RepositoryPolicy());
}
if (repository.getSnapshots() != null) {
builder.setSnapshotPolicy(new RepositoryPolicy(
repository.getSnapshots().isEnabled(),
RepositoryPolicy.UPDATE_POLICY_DAILY,
RepositoryPolicy.CHECKSUM_POLICY_WARN));
} else {
builder.setSnapshotPolicy(new RepositoryPolicy(false, null, null));
}
RemoteRepository remoteRepository = builder.build();
remoteRepositories.put(remoteRepository.getId(), remoteRepository);
}
}
if (alteredOverrides.addRepositoriesOp() == ContextOverrides.AddRepositoriesOp.APPEND) {
alteredOverrides.getRepositories().forEach(r -> remoteRepositories.put(r.getId(), r));
}
} else {
alteredOverrides.getRepositories().forEach(r -> remoteRepositories.put(r.getId(), r));
}
return new Context(
runtime,
alteredOverrides,
baseDir,
mavenUserHomeImpl,
mavenSystemHomeImpl,
repositorySystem,
session,
repositorySystem.newResolutionRepositories(session, new ArrayList<>(remoteRepositories.values())),
httpProxy,
lookup,
managedCloser);
} catch (Exception e) {
throw new IllegalStateException("Cannot create context from scratch", e);
}
}
private HTTPProxy toHTTPProxy(Proxy proxy) {
HashMap data = new HashMap<>();
if (proxy.getUsername() != null) {
data.put("username", proxy.getUsername());
}
if (proxy.getPassword() != null) {
data.put("password", proxy.getPassword());
}
return new HTTPProxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), proxy.getNonProxyHosts(), data);
}
protected Settings newEffectiveSettings(
ContextOverrides overrides,
MavenUserHome mavenUserHome,
MavenSystemHome mavenSystemHome,
SettingsBuilder settingsBuilder)
throws SettingsBuildingException {
if (!overrides.isWithUserSettings()) {
return new Settings();
}
if (overrides.getEffectiveSettings() instanceof Settings) {
return (Settings) overrides.getEffectiveSettings();
}
DefaultSettingsBuildingRequest settingsBuilderRequest = new DefaultSettingsBuildingRequest();
Properties systemProperties = new Properties();
systemProperties.putAll(overrides.getSystemProperties());
settingsBuilderRequest.setSystemProperties(systemProperties);
Properties userProperties = new Properties();
userProperties.putAll(overrides.getUserProperties());
settingsBuilderRequest.setUserProperties(userProperties);
if (mavenSystemHome != null) {
settingsBuilderRequest.setGlobalSettingsFile(
mavenSystemHome.settingsXml().toFile());
}
settingsBuilderRequest.setUserSettingsFile(mavenUserHome.settingsXml().toFile());
Settings result = settingsBuilder.build(settingsBuilderRequest).getEffectiveSettings();
if (overrides.getEffectiveSettingsMixin() instanceof Settings) {
settingsMixin(result, (Settings) overrides.getEffectiveSettingsMixin());
}
return result;
}
protected void settingsMixin(Settings settings, Settings mixin) {
// Special care for mixin that is about to add Proxy:
// - disable all other proxies, if exists
// Hence:
// - if mixin proxy is active, it prevails
// - if mixin proxy is inactive, shuts down proxy
boolean mixinAddsProxy = !mixin.getProxies().isEmpty();
if (mixinAddsProxy) {
for (Proxy proxy : settings.getProxies()) {
proxy.setActive(false);
}
settings.flushActiveProxy();
}
new MavenSettingsMerger().merge(settings, mixin, TrackableBase.GLOBAL_LEVEL);
}
protected List activeProfilesByActivation(
ContextOverrides overrides, Path basedir, Settings settings, ProfileSelector profileSelector) {
if (profileSelector == null) {
return activeProfiles(settings);
} else {
DefaultProfileActivationContext context = new DefaultProfileActivationContext();
context.setProjectDirectory(basedir.toFile());
context.setActiveProfileIds(
Stream.concat(settings.getActiveProfiles().stream(), overrides.getActiveProfileIds().stream())
.distinct()
.collect(Collectors.toList()));
context.setInactiveProfileIds(overrides.getInactiveProfileIds());
context.setSystemProperties(overrides.getSystemProperties());
context.setUserProperties(overrides.getUserProperties());
ModelProblemCollector collector = new ModelProblemCollector() {
@Override
public void add(ModelProblemCollectorRequest req) {}
};
return profileSelector
.getActiveProfiles(
settings.getProfiles().stream()
.map(StandaloneRuntimeSupport::convertFromSettingsProfile)
.collect(Collectors.toList()),
context,
collector)
.stream()
.map(StandaloneRuntimeSupport::convertToSettingsProfile)
.collect(Collectors.toList());
}
}
protected List activeProfiles(Settings settings) {
HashMap result = new HashMap<>();
Map profileMap = settings.getProfilesAsMap();
// explicitly activated: settings/activeProfiles
for (String profileId : settings.getActiveProfiles()) {
Profile profile = profileMap.get(profileId);
if (profile != null) {
result.put(profile.getId(), profile);
}
}
// implicitly activated: currently only activeByDefault
for (Profile profile : settings.getProfiles()) {
Activation activation = profile.getActivation();
if (activation != null) {
if (activation.isActiveByDefault()) {
result.put(profile.getId(), profile);
}
}
}
return new ArrayList<>(result.values());
}
protected DefaultRepositorySystemSession newRepositorySession(
ContextOverrides overrides,
MavenUserHome mavenUserHome,
RepositorySystem repositorySystem,
Settings settings,
SettingsDecrypter settingsDecrypter) {
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
if (!overrides.extraArtifactTypes().isEmpty()) {
DefaultArtifactTypeRegistry registry = (DefaultArtifactTypeRegistry) session.getArtifactTypeRegistry();
overrides.extraArtifactTypes().forEach(registry::add);
}
session.setCache(new DefaultRepositoryCache());
LinkedHashMap
© 2015 - 2024 Weber Informatics LLC | Privacy Policy