Skip to content

Commit

Permalink
Support loading of settings from other locations
Browse files Browse the repository at this point in the history
Currently there is only one cached settings object for the all projects
but it is possible for projects to carry individual settings.

This now enhances the settings handling in a way to support providing a
composite key of global and local settings to be loaded an cached.
  • Loading branch information
laeubi committed Feb 14, 2024
1 parent 830c305 commit 6f195b7
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ <T> T getMojoParameterValue(MavenProject project, String parameter, Class<T> typ
*/
Settings getSettings() throws CoreException;

Settings getSettings(MavenSettingsLocations locations) throws CoreException;

String getLocalRepositoryPath();

ArtifactRepository getLocalRepository() throws CoreException;
Expand All @@ -209,6 +211,10 @@ <T> T getMojoParameterValue(MavenProject project, String parameter, Class<T> typ

List<ArtifactRepository> getPluginArtifactRepositories(boolean injectSettings) throws CoreException;

/**
* @deprecated use {@link #getSettings(MavenSettingsLocations)} instead
*/
@Deprecated(forRemoval = true)
Settings buildSettings(String globalSettings, String userSettings) throws CoreException;

void writeSettings(Settings settings, OutputStream out) throws CoreException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ public interface IMavenConfiguration {
*/
boolean buildWithNullSchedulingRule();

MavenSettingsLocations getSettingsLocations();

static IMavenConfiguration getWorkspaceConfiguration() {
MavenPluginActivator activator = MavenPluginActivator.getDefault();
if(activator == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/********************************************************************************
* Copyright (c) 2024 Christoph Läubrich and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
********************************************************************************/

package org.eclipse.m2e.core.embedder;

import java.io.File;


/**
* This recored encapsulates the combination of a global and a user settings files as defined in
* https://maven.apache.org/settings.html
*/
public record MavenSettingsLocations(File globalSettings, File userSettings) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

package org.eclipse.m2e.core.internal.embedder;

import static org.eclipse.m2e.core.internal.M2EUtils.copyProperties;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
Expand All @@ -36,6 +34,7 @@
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.osgi.service.component.annotations.Component;
Expand Down Expand Up @@ -138,14 +137,17 @@
import org.apache.maven.wagon.proxy.ProxyInfo;

import org.eclipse.m2e.core.embedder.ICallable;
import org.eclipse.m2e.core.embedder.IComponentLookup;
import org.eclipse.m2e.core.embedder.ILocalRepositoryListener;
import org.eclipse.m2e.core.embedder.IMaven;
import org.eclipse.m2e.core.embedder.IMavenConfiguration;
import org.eclipse.m2e.core.embedder.IMavenConfigurationChangeListener;
import org.eclipse.m2e.core.embedder.IMavenExecutionContext;
import org.eclipse.m2e.core.embedder.ISettingsChangeListener;
import org.eclipse.m2e.core.embedder.MavenConfigurationChangeEvent;
import org.eclipse.m2e.core.embedder.MavenSettingsLocations;
import org.eclipse.m2e.core.internal.IMavenConstants;
import org.eclipse.m2e.core.internal.M2EUtils;
import org.eclipse.m2e.core.internal.Messages;
import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;

Expand All @@ -169,15 +171,9 @@ public class MavenImpl implements IMaven, IMavenConfigurationChangeListener {
private PlexusContainerManager containerManager;

/**
* Cached parsed settings.xml instance
* Cached parsed settingsCacheMap.xml instance
*/
private Settings settings;

/** File length of cached user settings */
private long settingsLength;

/** Last modified timestamp of cached user settings */
private long settingsTimestamp;
private Map<MavenSettingsLocations, MavenSettings> settingsCacheMap = new ConcurrentHashMap<>();

@Override
public String getLocalRepositoryPath() {
Expand Down Expand Up @@ -274,54 +270,13 @@ public ArtifactRepository getLocalRepository() throws CoreException {

@Override
public Settings getSettings() throws CoreException {
return getSettings(false);
return getSettings(mavenConfiguration.getSettingsLocations());
}

public synchronized Settings getSettings(boolean forceReload) throws CoreException {
// MUST NOT use createRequest!

File userSettingsFile = SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE;
if(mavenConfiguration.getUserSettingsFile() != null) {
userSettingsFile = new File(mavenConfiguration.getUserSettingsFile());
}

boolean reload = forceReload || settings == null;

if(!reload && userSettingsFile != null) {
reload = userSettingsFile.lastModified() != settingsTimestamp || userSettingsFile.length() != settingsLength;
}

if(reload) {
// TODO: Can't that delegate to buildSettings()?
SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
// 440696 guard against ConcurrentModificationException
Properties systemProperties = new Properties();
copyProperties(systemProperties, System.getProperties());
request.setSystemProperties(systemProperties);
if(mavenConfiguration.getGlobalSettingsFile() != null) {
request.setGlobalSettingsFile(new File(mavenConfiguration.getGlobalSettingsFile()));
}
if(userSettingsFile != null) {
request.setUserSettingsFile(userSettingsFile);
}
try {
settings = lookup(SettingsBuilder.class).build(request).getEffectiveSettings();
} catch(SettingsBuildingException ex) {
String msg = "Could not read settings.xml, assuming default values";
log.error(msg, ex);
/*
* NOTE: This method provides input for various other core functions, just bailing out would make m2e highly
* unusuable. Instead, we fail gracefully and just ignore the broken settings, using defaults.
*/
settings = new Settings();
}

if(userSettingsFile != null) {
settingsLength = userSettingsFile.length();
settingsTimestamp = userSettingsFile.lastModified();
}
}
return settings;
@Override
public Settings getSettings(MavenSettingsLocations locations) throws CoreException {
MavenSettings cache = settingsCacheMap.computeIfAbsent(locations, key -> new MavenSettings(key, MavenImpl.this));
return cache.getSettings();
}

@Override
Expand Down Expand Up @@ -372,7 +327,8 @@ public List<SettingsProblem> validateSettings(String settings) {

@Override
public void reloadSettings() throws CoreException {
Settings reloadedSettings = getSettings(true);
settingsCacheMap.clear();
Settings reloadedSettings = getSettings(mavenConfiguration.getSettingsLocations());
for(ISettingsChangeListener listener : settingsListeners) {
try {
listener.settingsChanged(reloadedSettings);
Expand Down Expand Up @@ -1103,4 +1059,77 @@ public MavenExecutionContext createExecutionContext() {
return new MavenExecutionContext(this, null, null);
}

private static final class MavenSettings {
private long userSettingsLength;

private long userSettingsTimestamp;

private long globalSettingsLength;

private long globalSettingsTimestamp;

private MavenSettingsLocations locations;

private Settings settings;

private IComponentLookup lookup;

public MavenSettings(MavenSettingsLocations locations, IComponentLookup lookup) {
this.locations = locations;
this.lookup = lookup;
}

private synchronized Settings getSettings() throws CoreException {
File global = locations.globalSettings();
long gs;
long gt;
if(global != null && global.isFile()) {
gs = global.length();
gt = global.lastModified();
} else {
gs = -1;
gt = -1;
}
File user = locations.userSettings();
long us;
long ut;
if(user != null && user.isFile()) {
us = user.length();
ut = user.lastModified();
} else {
us = -1;
ut = -1;
}
boolean reload = settings == null || gs != globalSettingsLength || gt != globalSettingsTimestamp
|| us != userSettingsLength || ut != userSettingsTimestamp;
if(reload) {
SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
Properties systemProperties = new Properties();
M2EUtils.copyProperties(systemProperties, System.getProperties());
request.setSystemProperties(systemProperties);
if(global != null) {
request.setGlobalSettingsFile(global);
}
if(user != null) {
request.setUserSettingsFile(user);
}
try {
settings = lookup.lookup(SettingsBuilder.class).build(request).getEffectiveSettings();
} catch(SettingsBuildingException ex) {
log.error("Could not read settingsCacheMap.xml, assuming default values", ex);
/*
* NOTE: This method provides input for various other core functions, just bailing out would make m2e highly
* unusable. Instead, we fail gracefully and just ignore the broken settingsCacheMap, using defaults.
*/
settings = new Settings();
}
globalSettingsLength = gs;
globalSettingsTimestamp = gt;
userSettingsLength = us;
userSettingsTimestamp = ut;
}
return settings;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

package org.eclipse.m2e.core.internal.preferences;

import java.io.File;
import java.util.Map;
import java.util.Objects;

Expand Down Expand Up @@ -41,10 +42,12 @@
import org.eclipse.core.runtime.preferences.PreferenceFilterEntry;

import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor;

import org.eclipse.m2e.core.embedder.IMavenConfiguration;
import org.eclipse.m2e.core.embedder.IMavenConfigurationChangeListener;
import org.eclipse.m2e.core.embedder.MavenConfigurationChangeEvent;
import org.eclipse.m2e.core.embedder.MavenSettingsLocations;
import org.eclipse.m2e.core.internal.IMavenConstants;
import org.eclipse.m2e.core.internal.MavenPluginActivator;
import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingFactory;
Expand Down Expand Up @@ -206,6 +209,25 @@ public void preferenceChange(PreferenceChangeEvent event) {
}
}

@Override
public MavenSettingsLocations getSettingsLocations() {
File userSettings;
File globalSettings;
String configSettingsFile = getUserSettingsFile();
if (configSettingsFile==null) {
userSettings = SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE;
} else {
userSettings = new File(configSettingsFile);
}
String configGlobalSettingsFile = getGlobalSettingsFile();
if(configGlobalSettingsFile == null) {
globalSettings = null;
} else {
globalSettings = new File(configGlobalSettingsFile);
}
return new MavenSettingsLocations(globalSettings, userSettings);
}

@Override
public void added(NodeChangeEvent event) {
}
Expand Down

0 comments on commit 6f195b7

Please sign in to comment.