From 6f195b7171868d6c5d77a16c1aa7c34bdfbb55c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Wed, 14 Feb 2024 13:26:29 +0100 Subject: [PATCH] Support loading of settings from other locations 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. --- .../org/eclipse/m2e/core/embedder/IMaven.java | 6 + .../core/embedder/IMavenConfiguration.java | 2 + .../core/embedder/MavenSettingsLocations.java | 25 +++ .../m2e/core/internal/embedder/MavenImpl.java | 143 +++++++++++------- .../preferences/MavenConfigurationImpl.java | 22 +++ 5 files changed, 141 insertions(+), 57 deletions(-) create mode 100644 org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenSettingsLocations.java diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java index b632ba2e06..7de8dadb21 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java @@ -187,6 +187,8 @@ T getMojoParameterValue(MavenProject project, String parameter, Class typ */ Settings getSettings() throws CoreException; + Settings getSettings(MavenSettingsLocations locations) throws CoreException; + String getLocalRepositoryPath(); ArtifactRepository getLocalRepository() throws CoreException; @@ -209,6 +211,10 @@ T getMojoParameterValue(MavenProject project, String parameter, Class typ List 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; diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java index a3611683fe..4858b3cc92 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMavenConfiguration.java @@ -134,6 +134,8 @@ public interface IMavenConfiguration { */ boolean buildWithNullSchedulingRule(); + MavenSettingsLocations getSettingsLocations(); + static IMavenConfiguration getWorkspaceConfiguration() { MavenPluginActivator activator = MavenPluginActivator.getDefault(); if(activator == null) { diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenSettingsLocations.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenSettingsLocations.java new file mode 100644 index 0000000000..5a72127b0b --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/MavenSettingsLocations.java @@ -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) { + +} diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java index 73e80b3363..e58327cc3d 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenImpl.java @@ -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; @@ -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; @@ -138,6 +137,7 @@ 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; @@ -145,7 +145,9 @@ 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; @@ -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 settingsCacheMap = new ConcurrentHashMap<>(); @Override public String getLocalRepositoryPath() { @@ -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 @@ -372,7 +327,8 @@ public List 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); @@ -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; + } + } + } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java index 40537fa807..d9d5d479fb 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenConfigurationImpl.java @@ -13,6 +13,7 @@ package org.eclipse.m2e.core.internal.preferences; +import java.io.File; import java.util.Map; import java.util.Objects; @@ -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; @@ -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) { }