diff --git a/org.eclipse.m2e.core.tests/META-INF/MANIFEST.MF b/org.eclipse.m2e.core.tests/META-INF/MANIFEST.MF index 60603f825e..e57a9b8fe6 100644 --- a/org.eclipse.m2e.core.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.m2e.core.tests/META-INF/MANIFEST.MF @@ -13,6 +13,9 @@ Require-Bundle: org.eclipse.m2e.tests.common, org.eclipse.debug.core, org.eclipse.jdt.core Import-Package: org.apache.commons.io, + org.hamcrest;version="[2.2.0,3.0.0]", + org.hamcrest.collection;version="[2.2.0,3.0.0]", + org.hamcrest.core;version="[2.2.0,3.0.0]", org.junit, org.mockito, org.mockito.stubbing diff --git a/org.eclipse.m2e.core.tests/resources/settings/empty_settings/settings_empty.xml b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/settings_empty.xml new file mode 100644 index 0000000000..dc89d52c9f --- /dev/null +++ b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/settings_empty.xml @@ -0,0 +1,2 @@ + + diff --git a/org.eclipse.m2e.core.tests/resources/settings/empty_settings/settings_other.xml b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/settings_other.xml new file mode 100644 index 0000000000..dc89d52c9f --- /dev/null +++ b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/settings_other.xml @@ -0,0 +1,2 @@ + + diff --git a/org.eclipse.m2e.core.tests/resources/settings/empty_settings/toolchains_empty.xml b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/toolchains_empty.xml new file mode 100644 index 0000000000..abf1b6c01b --- /dev/null +++ b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/toolchains_empty.xml @@ -0,0 +1,2 @@ + + diff --git a/org.eclipse.m2e.core.tests/resources/settings/empty_settings/toolchains_other.xml b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/toolchains_other.xml new file mode 100644 index 0000000000..abf1b6c01b --- /dev/null +++ b/org.eclipse.m2e.core.tests/resources/settings/empty_settings/toolchains_other.xml @@ -0,0 +1,2 @@ + + diff --git a/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/core/CoreBiConsumer.java b/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/core/CoreBiConsumer.java new file mode 100644 index 0000000000..f5b43ae02a --- /dev/null +++ b/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/core/CoreBiConsumer.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2024 Georg Tsakumagos and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Georg Tsakumagos - initial declaration + *******************************************************************************/ +package org.eclipse.m2e.core; + +import java.util.function.Consumer; + +import org.eclipse.core.runtime.CoreException; + +/** + * Represents an operation that accepts two input arguments, returns no + * result and throws a {@link CoreException}. + * This is the two-arity specialization of {@link Consumer}. + * Unlike most other functional interfaces, {@code BiConsumer} is expected + * to operate via side-effects. + * + * + * @param the type of the first argument to the operation + * @param the type of the second argument to the operation + * + * @see Consumer + * @author Georg Tsakumagos + */ +@FunctionalInterface +public interface CoreBiConsumer { + + /** + * Performs this operation on the given arguments. + * + * @param t the first input argument + * @param u the second input argument + * @throws CoreException If something went wrong. + */ + void accept(T t, U u) throws CoreException; +} \ No newline at end of file diff --git a/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegateTest.java b/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegateTest.java index f1b4162150..899efadca5 100644 --- a/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegateTest.java +++ b/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegateTest.java @@ -10,6 +10,7 @@ * Contributors: * Hannes Wellmann - initial API and implementation * Konrad Windszus - Add tests for required java runtime version implied by enforcer rule + * Georg Tsakumagos - Add tests for global- & user- settings and toolchains. *******************************************************************************/ package org.eclipse.m2e.internal.launch; @@ -19,13 +20,17 @@ import java.io.File; import java.util.List; +import java.util.Optional; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.cli.CLIManager; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.Launch; import org.eclipse.jdt.internal.launching.StandardVMType; import org.eclipse.jdt.launching.AbstractVMInstall; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; @@ -33,7 +38,13 @@ import org.eclipse.jdt.launching.IVMInstallType; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.m2e.actions.MavenLaunchConstants; +import org.eclipse.m2e.core.CoreBiConsumer; +import org.eclipse.m2e.core.MavenPlugin; +import org.eclipse.m2e.core.embedder.IMavenConfiguration; import org.eclipse.m2e.tests.common.AbstractMavenProjectTestCase; +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; import org.junit.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; @@ -47,6 +58,8 @@ public class MavenLaunchDelegateTest extends AbstractMavenProjectTestCase { private static final String DEFAULT_VM = "defaultVM"; private static final List AVAILABLE_VM_VERSIONS = List.of("17.0.4", "11.0.7", "13.0.5", "11.0.1", "1.8.0"); + + @Test public void testGetBestMatchingVM_majorOnly() throws InvalidVersionSpecificationException { try (var mock = mockJavaRuntime()) { @@ -75,6 +88,63 @@ public void testGetBestMatchingVM_1XversionRange() throws InvalidVersionSpecific } } + /** + * Tests rendering of maven cli args for global settings (-gs,--global-settings). + * @throws Exception On errors. + */ + @Test + public void testGlobalSettings() throws Exception { + assertMavenLaunchFileSetting(IMavenConfiguration::setGlobalSettingsFile, CLIManager.ALTERNATE_GLOBAL_SETTINGS, "./resources/settings/empty_settings/settings_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global settings (-gs,--global-settings) + * if setting is overridden by direct parameterization in the goal input + * @throws Exception On errors. + */ + @Test + public void testGlobalSettings_GoalOverride() throws Exception { + assertMavenLaunchFileSettingGoalOverride(IMavenConfiguration::setGlobalSettingsFile, CLIManager.ALTERNATE_GLOBAL_SETTINGS, "./resources/settings/empty_settings/settings_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global settings (-gs,--global-settings) + * if an invalid path was provided. + * @throws Exception On errors. + */ + @Test + public void testGlobalSettings_Invalid() throws Exception { + assertMavenLaunchFileSettingPathInvalid(IMavenConfiguration::setGlobalSettingsFile); + } + + /** + * Tests rendering of maven cli args for global toolchains (-gt,--global-toolchains). + * @throws Exception On errors. + */ + @Test + public void testGlobalToolchains() throws Exception { + assertMavenLaunchFileSetting(IMavenConfiguration::setGlobalToolchainsFile, CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS, "./resources/settings/empty_settings/toolchains_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global toolchains (-gt,--global-toolchains) + * if setting is overridden by direct parameterization in the goal input + * @throws Exception On errors. + */ + @Test + public void testGlobalToolchains_GoalOverride() throws Exception { + assertMavenLaunchFileSettingGoalOverride(IMavenConfiguration::setGlobalToolchainsFile, CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS, "./resources/settings/empty_settings/toolchains_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global toolchains (-gt,--global-toolchains) if an invalid path was provided. + * @throws Exception On errors. + */ + @Test + public void testGlobalToolchains_Invalid() throws Exception { + assertMavenLaunchFileSettingPathInvalid(IMavenConfiguration::setGlobalToolchainsFile); + } + @Test public void testRequiredJavaVersionFromEnforcerRule_Version() throws Exception { IProject project = importProject("resources/projects/enforcerSettingsWithVersion/pom.xml"); @@ -93,6 +163,179 @@ public void testRequiredJavaVersionFromEnforcerRule_NoVersionRange() throws Exce assertRequiredJavaBuildVersion(project, null, DEFAULT_VM); } + /** + * Tests rendering of maven cli args for global settings (-s,--settings) + * @throws Exception On errors. + */ + @Test + public void testUserSettings() throws Exception { + assertMavenLaunchFileSetting(IMavenConfiguration::setUserSettingsFile, String.valueOf(CLIManager.ALTERNATE_USER_SETTINGS), "./resources/settings/empty_settings/settings_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global settings (-s,--settings) + * if setting is overridden by direct parameterization in the goal input + * @throws Exception On errors. + */ + @Test + public void testUserSettings_GoalOverride() throws Exception { + assertMavenLaunchFileSettingGoalOverride(IMavenConfiguration::setUserSettingsFile, String.valueOf(CLIManager.ALTERNATE_USER_SETTINGS), "./resources/settings/empty_settings/settings_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global settings (-s,--settings) + * if an invalid path was provided. + * @throws Exception On errors. + */ + @Test + public void testUserSettings_Invalid() throws Exception { + assertMavenLaunchFileSettingPathInvalid(IMavenConfiguration::setUserSettingsFile); + } + + + /** + * Tests rendering of maven cli args for global toolchains (-t,--toolchains). + * @throws Exception On errors. + */ + @Test + public void testUserToolchains() throws Exception { + assertMavenLaunchFileSetting(IMavenConfiguration::setUserToolchainsFile, String.valueOf(CLIManager.ALTERNATE_USER_TOOLCHAINS), "./resources/settings/empty_settings/toolchains_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global toolchains (-t,--toolchains). + * if setting is overridden by direct parameterization in the goal input + * @throws Exception On errors. + */ + @Test + public void testUserToolchains_GoalOverride() throws Exception { + assertMavenLaunchFileSettingGoalOverride(IMavenConfiguration::setUserToolchainsFile, String.valueOf(CLIManager.ALTERNATE_USER_TOOLCHAINS), "./resources/settings/empty_settings/toolchains_empty.xml"); + } + + /** + * Tests rendering of maven cli args for global toolchains (-t,--toolchains) + * if an invalid path was provided. + * @throws Exception On errors. + */ + @Test + public void testUserToolchains_Invalid() throws Exception { + assertMavenLaunchFileSettingPathInvalid(IMavenConfiguration::setUserToolchainsFile); + } + + + /** + * assertion shortcut for launch configuration. + * @param configSetter Setter for the configuration accepting the relativePath. Must not be null. + * @param key Key of the configuration. Must not be null. + * @param relativePath Relative path for the file. Must not be null. + * @throws Exception Usually only on missed assertions. + */ + private void assertMavenLaunchConfig(CoreBiConsumer configSetter, String goal, CoreBiConsumer verifier, String relativePath) + throws Exception { + + waitForJobsToComplete(); + IProject project = importProject("resources/projects/simplePomOK/pom.xml"); + String pomDir = "${workspace_loc:/" + project.getName() + "}"; + + try (var mock = mockJavaRuntime()) { + IMavenConfiguration mavenConfig = MavenPlugin.getMavenConfiguration(); + + try { + configSetter.accept(mavenConfig, relativePath); + ILaunchConfigurationWorkingCopy config = createMavenLaunchConfig(pomDir); + + try { + Optional.ofNullable(goal).ifPresent((g) -> config.setAttribute(MavenLaunchConstants.ATTR_GOALS, g)); + + // Prepare Mocks to capture VM configuration + Launch launch = new Launch(config, "run", new MavenSourceLocator()); + NullProgressMonitor mockMonitor = Mockito.spy(new NullProgressMonitor()); + Mockito.doReturn(true).when(mockMonitor).isCanceled(); + + // mock launch + MavenLaunchDelegate launcher = new MavenLaunchDelegate(); + launcher.launch(config, "run", launch, mockMonitor); + + verifier.accept(launcher, config); + } finally { + Optional.ofNullable(goal).ifPresent((g) -> config.removeAttribute(MavenLaunchConstants.ATTR_GOALS)); + } + } finally { + // Reset property to avoid conflicts with other test cases. + configSetter.accept(mavenConfig, null); + } + } + } + + /** + * assertion shortcut for launch configuration. + * @param configSetter Setter for the configuration accepting the relativePath. Must not be null. + * @param key Key of the configuration. Must not be null. + * @param relativePath Relative path for the file. Must not be null. + * @throws Exception Usually only on missed assertions. + */ + private void assertMavenLaunchFileSetting(CoreBiConsumer configSetter, String key, String relativePath) + throws Exception { + final String param = "-" + key; + this.assertMavenLaunchConfig(configSetter, null, (launcher, config) -> { + String programArguments = launcher.getProgramArguments(config); + + // prepare assert + Matcher allSettings = CoreMatchers.allOf( + CoreMatchers.containsString(param), + CoreMatchers.containsString(new File(relativePath).getAbsolutePath()) + ); + + // assert + MatcherAssert.assertThat(programArguments, allSettings); + }, relativePath); + } + + /** + * assertion shortcut for launch configuration. + * @param configSetter Setter for the configuration accepting the relativePath. Must not be null. + * @param key Key of the configuration. Must not be null. + * @param relativePath Relative path for the file. Must not be null. + * @throws Exception Usually only on missed assertions. + */ + private void assertMavenLaunchFileSettingGoalOverride(CoreBiConsumer configSetter, String key, String relativePath) + throws Exception { + final String userDerivedPath = "./resources/settings/empty_settings/this_do_not_exists.xml"; + final String param = "-" + key; + final String goalConfig = "clean " + param + " " + userDerivedPath; + + this.assertMavenLaunchConfig(configSetter, goalConfig, (launcher, config) -> { + String programArguments = launcher.getProgramArguments(config); + + // prepare assert + Matcher allSettings = CoreMatchers.allOf( + CoreMatchers.containsString(param), + CoreMatchers.containsString(userDerivedPath), + CoreMatchers.not(CoreMatchers.containsString(relativePath)) + ); + + // assert + MatcherAssert.assertThat(programArguments, allSettings); + }, relativePath); + } + + + /** + * assertion shortcut for launch configuration if an invalid path was provided. + * @param configSetter Setter for the configuration accepting the relativePath. Must not be null. + * @param key Key of the configuration. Must not be null. + * @throws Exception Usually only on missed assertions. + */ + private void assertMavenLaunchFileSettingPathInvalid(CoreBiConsumer configSetter) throws Exception { + final String path = "./resources/settings/empty_settings/this_do_not_exists.xml"; + try { + this.assertMavenLaunchConfig(configSetter, null, (launcher, config) -> {}, path); + } catch(IllegalArgumentException expected) { + MatcherAssert.assertThat(expected.getMessage(), CoreMatchers.containsString(path)); + } + } + + private void assertRequiredJavaBuildVersion(IProject project, String expectedVersionRange, String expectedVMVersion) throws Exception { diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java index d53592a15f..0a48922440 100644 --- a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/Messages.java @@ -557,16 +557,26 @@ public class Messages extends NLS { public static String MavenRepositoryView_update_one; - public static String MavenSettingsPreferencePage_settingsBrowseButton_text; + public static String MavenSettingsPreferencePage_btnEdit_text; - public static String MavenSettingsPreferencePage_btnUpdate; + public static String MavenSettingsPreferencePage_btnEdit_tooltip; - public static String MavenSettingsPreferencePage_error_globalSettingsMissing; + public static String MavenSettingsPreferencePage_btnBrowse_text; - public static String MavenSettingsPreferencePage_error_userSettingsMissing; + public static String MavenSettingsPreferencePage_btnBrowse_tooltip; + + public static String MavenSettingsPreferencePage_btnUpdate_text; + + public static String MavenSettingsPreferencePage_error_globalSettingsMissing; public static String MavenSettingsPreferencePage_error_globalSettingsParse; + public static String MavenSettingsPreferencePage_error_globalToolchainsMissing; + + public static String MavenSettingsPreferencePage_error_globalToolchainsParse; + + public static String MavenSettingsPreferencePage_error_userSettingsMissing; + public static String MavenSettingsPreferencePage_error_userSettingsParse; public static String MavenSettingsPreferencePage_error_userToolchainsMissing; @@ -577,19 +587,21 @@ public class Messages extends NLS { public static String MavenSettingsPreferencePage_job_updating; - public static String MavenSettingsPreferencePage_lblLocal; + public static String MavenSettingsPreferencePage_localRepoLabel; + + public static String MavenSettingsPreferencePage_mergedSettings; - public static String MavenSettingsPreferencePage_userSettingslink_tooltip; + public static String MavenSettingsPreferencePage_globalPreferences; - public static String MavenSettingsPreferencePage_userSettingslink1; + public static String MavenSettingsPreferencePage_globalSettingsLabel; - public static String MavenSettingsPreferencePage_userSettingslink2; + public static String MavenSettingsPreferencePage_globalToolchainsLabel; - public static String MavenSettingsPreferencePage_globalSettingslink_tooltip; + public static String MavenSettingsPreferencePage_UserPreferences; - public static String MavenSettingsPreferencePage_globalSettingslink1; + public static String MavenSettingsPreferencePage_userSettingsLabel; - public static String MavenSettingsPreferencePage_globalSettingslink2; + public static String MavenSettingsPreferencePage_userToolchainsLabel; public static String MavenSettingsPreferencePage_task_updating; diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties index b88dee250c..4849c6fda4 100644 --- a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/messages.properties @@ -309,26 +309,29 @@ MavenRepositoryView_reload_msg=This will reload the settings.xml and rebuild the MavenRepositoryView_reload_title=Reload settings.xml MavenRepositoryView_update_more=Update Indexes MavenRepositoryView_update_one=Update Index -MavenSettingsPreferencePage_settingsBrowseButton_text=Browse... -MavenSettingsPreferencePage_btnUpdate=Update Settings +MavenSettingsPreferencePage_btnBrowse_text=Browse... +MavenSettingsPreferencePage_btnBrowse_tooltip=Browse for settings file +MavenSettingsPreferencePage_btnEdit_text=Edit... +MavenSettingsPreferencePage_btnEdit_tooltip=Open editor for settings +MavenSettingsPreferencePage_btnUpdate_text=Update Settings MavenSettingsPreferencePage_error_globalSettingsMissing=Global settings file doesn't exist -MavenSettingsPreferencePage_error_userSettingsMissing=User settings file doesn't exist MavenSettingsPreferencePage_error_globalSettingsParse=Unable to parse global settings file {0} +MavenSettingsPreferencePage_error_globalToolchainsMissing=Global toolchains file doesn't exist +MavenSettingsPreferencePage_error_globalToolchainsParse=Unable to parse toolchains file {0} +MavenSettingsPreferencePage_error_userSettingsMissing=User settings file doesn't exist MavenSettingsPreferencePage_error_userSettingsParse=Unable to parse user settings file {0} MavenSettingsPreferencePage_error_userToolchainsMissing=User toolchains file doesn't exist MavenSettingsPreferencePage_error_userToolchainsParse=Unable to parse user toolchains file {0} MavenSettingsPreferencePage_job_indexing=Indexing Local Repository... MavenSettingsPreferencePage_job_updating=Updating Maven settings -MavenSettingsPreferencePage_lblLocal=Local Repository (From merged user and global settings)\: -MavenSettingsPreferencePage_userSettingslink1=User &Settings\: -MavenSettingsPreferencePage_userSettingslink2=User &Settings (open file)\: -MavenSettingsPreferencePage_userSettingslink_tooltip=Open editor for user settings -MavenSettingsPreferencePage_userToolchainslink1=User &Toolchains\: -MavenSettingsPreferencePage_userToolchainslink2=User &Toolchains (open file)\: -MavenSettingsPreferencePage_userToolchainslink_tooltip=Open editor for user toolchains -MavenSettingsPreferencePage_globalSettingslink1=Global &Settings\: -MavenSettingsPreferencePage_globalSettingslink2=Global &Settings (open file)\: -MavenSettingsPreferencePage_globalSettingslink_tooltip=Open editor for global settings +MavenSettingsPreferencePage_globalSettingsLabel=Settings: +MavenSettingsPreferencePage_globalToolchainsLabel=Toolchains: +MavenSettingsPreferencePage_globalPreferences=&Global Settings: +MavenSettingsPreferencePage_localRepoLabel=Local Repository: +MavenSettingsPreferencePage_mergedSettings=Merged user and global settings +MavenSettingsPreferencePage_userSettingsLabel=Settings: +MavenSettingsPreferencePage_UserPreferences=&User Settings: +MavenSettingsPreferencePage_userToolchainsLabel=Toolchains: MavenSettingsPreferencePage_task_updating=Updating progress for {0} MavenSettingsPreferencePage_title=Maven User Settings MavenWarningsPreferencePage_Error=Error diff --git a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java index a31a766017..58533ca5d5 100644 --- a/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java +++ b/org.eclipse.m2e.core.ui/src/org/eclipse/m2e/core/ui/internal/preferences/MavenSettingsPreferencePage.java @@ -19,7 +19,6 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Stream; import org.slf4j.Logger; @@ -44,7 +43,6 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorInput; @@ -69,6 +67,9 @@ import org.eclipse.m2e.core.embedder.IMaven; import org.eclipse.m2e.core.embedder.IMavenConfiguration; import org.eclipse.m2e.core.internal.IMavenToolbox; +import org.eclipse.m2e.core.internal.MavenPluginActivator; +import org.eclipse.m2e.core.internal.launch.AbstractMavenRuntime; +import org.eclipse.m2e.core.internal.launch.MavenRuntimeManagerImpl; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.MavenUpdateRequest; import org.eclipse.m2e.core.ui.internal.Messages; @@ -78,34 +79,37 @@ * Maven installations preference page * * @author Eugene Kuleshov + * @author Georg Tsakumagos */ +@SuppressWarnings("restriction") public class MavenSettingsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { private static final Logger log = LoggerFactory.getLogger(MavenSettingsPreferencePage.class); - final IMavenConfiguration mavenConfiguration; + private final IMavenConfiguration mavenConfiguration; - final IMaven maven; + private final IMaven maven; - Text globalSettingsText; + private final MavenRuntimeManagerImpl runtimeManager; - Text userSettingsText; + private Text globalSettingsText; - Text localRepositoryText; + private Text globalToolchainsText; - boolean dirty = false; + private Text userSettingsText; - private Link globalSettingsLink; + private Text userToolchainsText; - private Link userSettingsLink; + Text localRepositoryText; + + boolean dirty = false; - private Link userToolchainsLink; - private Text userToolchainsText; public MavenSettingsPreferencePage() { setTitle(Messages.MavenSettingsPreferencePage_title); this.mavenConfiguration = MavenPlugin.getMavenConfiguration(); + this.runtimeManager = MavenPluginActivator.getDefault().getMavenRuntimeManager(); this.maven = MavenPlugin.getMaven(); } @@ -118,6 +122,7 @@ public void setVisible(boolean visible) { super.setVisible(visible); if(visible) { updateLocalRepository(); + updateGlobalSettingsDefaultFiles(); } } @@ -128,8 +133,10 @@ protected void updateSettings(boolean updateMavenDependencies) { String userSettings = getUserSettings(); String userToolchains = getUserToolchains(); String globalSettings = getGlobalSettings(); + String globalToolchains = getGlobalToolchains(); if(Objects.equals(globalSettings, mavenConfiguration.getGlobalSettingsFile()) + && Objects.equals(globalToolchains, mavenConfiguration.getGlobalToolchainsFile()) && Objects.equals(userSettings, mavenConfiguration.getUserSettingsFile()) && Objects.equals(userToolchains, mavenConfiguration.getUserToolchainsFile())) { return; // current preferences not changed @@ -195,63 +202,83 @@ public boolean performOk() { @Override protected Control createContents(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); - composite.setLayout(new GridLayout(2, false)); + GridLayout gl_composite = new GridLayout(4, false); + gl_composite.horizontalSpacing = 10; + composite.setLayout(gl_composite); - globalSettingsLink = createLink(composite, Messages.MavenSettingsPreferencePage_globalSettingslink2, - Messages.MavenSettingsPreferencePage_globalSettingslink_tooltip, this::getGlobalSettings, null); - globalSettingsText = createFileSelectionWidgets(composite, mavenConfiguration.getGlobalSettingsFile(), null); + createHeading(composite, Messages.MavenSettingsPreferencePage_globalPreferences, false); - userSettingsLink = createLink(composite, Messages.MavenSettingsPreferencePage_userSettingslink2, - Messages.MavenSettingsPreferencePage_userSettingslink_tooltip, this::getUserSettings, - SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE); - userSettingsText = createFileSelectionWidgets(composite, mavenConfiguration.getUserSettingsFile(), + this.globalSettingsText = this.createFileSelectionWidgets(composite, + Messages.MavenSettingsPreferencePage_globalSettingsLabel, this.mavenConfiguration.getGlobalSettingsFile(), + this.getDefaultGlobalSettingsFile()); + + this.globalToolchainsText = this.createFileSelectionWidgets(composite, + Messages.MavenSettingsPreferencePage_globalToolchainsLabel, mavenConfiguration.getGlobalToolchainsFile(), + this.getDefaultGlobalToolchainsFile()); + + createHeading(composite, Messages.MavenSettingsPreferencePage_UserPreferences, true); + + this.userSettingsText = this.createFileSelectionWidgets(composite, + Messages.MavenSettingsPreferencePage_userSettingsLabel, this.mavenConfiguration.getUserSettingsFile(), SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE); - userToolchainsLink = createLink(composite, Messages.MavenSettingsPreferencePage_userToolchainslink2, - Messages.MavenSettingsPreferencePage_userToolchainslink_tooltip, this::getUserToolchains, - MavenCli.DEFAULT_USER_TOOLCHAINS_FILE); - userToolchainsText = createFileSelectionWidgets(composite, mavenConfiguration.getUserToolchainsFile(), + this.userToolchainsText = this.createFileSelectionWidgets(composite, + Messages.MavenSettingsPreferencePage_userToolchainsLabel, this.mavenConfiguration.getUserToolchainsFile(), MavenCli.DEFAULT_USER_TOOLCHAINS_FILE); - Button updateSettings = new Button(composite, SWT.NONE); - updateSettings.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - updateSettings.setText(Messages.MavenSettingsPreferencePage_btnUpdate); - updateSettings.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> updateSettings(true))); + createHeading(composite, Messages.MavenSettingsPreferencePage_mergedSettings, true); - Label localRepositoryLabel = new Label(composite, SWT.NONE); - GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1); - gd.verticalIndent = 25; - localRepositoryLabel.setLayoutData(gd); - localRepositoryLabel.setText(Messages.MavenSettingsPreferencePage_lblLocal); + Label lblCaption = new Label(composite, SWT.NONE); + lblCaption.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + lblCaption.setText(Messages.MavenSettingsPreferencePage_localRepoLabel); localRepositoryText = new Text(composite, SWT.READ_ONLY | SWT.BORDER); localRepositoryText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); localRepositoryText.setData("name", "localRepositoryText"); //$NON-NLS-1$ //$NON-NLS-2$ localRepositoryText.setEditable(false); + Button updateSettings = new Button(composite, SWT.NONE); + updateSettings.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + updateSettings.setText(Messages.MavenSettingsPreferencePage_btnUpdate_text); + updateSettings.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> updateSettings(true))); + checkSettings(); updateLocalRepository(); return composite; } - private Link createLink(Composite composite, String text, String tooltip, Supplier selectedFile, - File defaultFile) { - Link link = new Link(composite, SWT.NONE); - link.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); - link.setText(text); - link.setToolTipText(tooltip); - link.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { - File file = Optional.ofNullable(selectedFile.get()).map(File::new).orElse(defaultFile); - if(file != null) { - openEditor(file); - } - })); - return link; + /** + * @param composite + * @param mavenSettingsPreferencePage_globalPreferences + */ + private void createHeading(Composite composite, String caption, boolean sep) { + if(sep) { + Label lblSpace = new Label(composite, SWT.NONE); + GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 4, 1); + gridData.heightHint = 20; + lblSpace.setLayoutData(gridData); + } + + Label lblCaption = new Label(composite, SWT.NONE); + lblCaption.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 4, 1)); + lblCaption.setText(caption); + + Label separator = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.SHADOW_NONE); + GridData gd_separator = new GridData(SWT.FILL, SWT.TOP, true, false, 4, 1); + gd_separator.heightHint = 10; + separator.setLayoutData(gd_separator); } - private Text createFileSelectionWidgets(Composite composite, String selectedFile, File defaultFile) { + + + private Text createFileSelectionWidgets(Composite composite, String label, String selectedFile, File defaultFile) { + Label lbSetting = new Label(composite, SWT.NONE); + lbSetting.setLayoutData(new GridData(SWT.LEFT, SWT.LEFT, false, false, 1, 1)); + lbSetting.setText(label); + Text fileText = new Text(composite, SWT.BORDER); fileText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); if(defaultFile != null) { @@ -266,16 +293,23 @@ private Text createFileSelectionWidgets(Composite composite, String selectedFile }); Button browseButton = new Button(composite, SWT.NONE); - browseButton.setLayoutData(new GridData(SWT.FILL, SWT.RIGHT, false, false, 1, 1)); - browseButton.setText(Messages.MavenSettingsPreferencePage_settingsBrowseButton_text); + browseButton.setLayoutData(new GridData(SWT.LEFT, SWT.LEFT, false, false, 1, 1)); + browseButton.setText(Messages.MavenSettingsPreferencePage_btnBrowse_text); + browseButton.setToolTipText(Messages.MavenSettingsPreferencePage_btnBrowse_tooltip); browseButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> browseSettingsAction(fileText))); - return fileText; - } - private void updateLink(Link link, String path, File defaultFile, String activeText, String inactiveText) { - File file = path != null ? new File(path) : defaultFile; - boolean active = file != null && file.canRead(); - link.setText(active ? activeText : inactiveText); + Button editButton = new Button(composite, SWT.NONE); + editButton.setLayoutData(new GridData(SWT.FILL, SWT.LEFT, false, false, 1, 1)); + editButton.setText(Messages.MavenSettingsPreferencePage_btnEdit_text); + editButton.setToolTipText(Messages.MavenSettingsPreferencePage_btnEdit_tooltip); + editButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { + final String path = fileText.getText(); + final File file = (path.isBlank()) ? defaultFile : new File(path); + if(file != null) { + openEditor(file); + } + })); + return fileText; } protected void updateLocalRepository() { @@ -295,6 +329,7 @@ protected void updateLocalRepository() { } } + protected void checkSettings() { setErrorMessage(null); setMessage(null); @@ -302,22 +337,18 @@ protected void checkSettings() { // NB: enable/disable links regardless of validation errors String globalSettings = getGlobalSettings(); - updateLink(globalSettingsLink, globalSettings, null, Messages.MavenSettingsPreferencePage_globalSettingslink2, - Messages.MavenSettingsPreferencePage_globalSettingslink1); - + String globalToolchains = getGlobalToolchains(); String userSettings = getUserSettings(); - updateLink(userSettingsLink, userSettings, SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE, - Messages.MavenSettingsPreferencePage_userSettingslink2, Messages.MavenSettingsPreferencePage_userSettingslink1); - String userToolchains = getUserToolchains(); - updateLink(userToolchainsLink, userToolchains, MavenCli.DEFAULT_USER_TOOLCHAINS_FILE, - Messages.MavenSettingsPreferencePage_userToolchainslink2, - Messages.MavenSettingsPreferencePage_userToolchainslink1); setMessage(null); checkSettings(globalSettings, Messages.MavenSettingsPreferencePage_error_globalSettingsMissing, l -> maven.validateSettings(l).stream().map(SettingsProblem::getMessage), Messages.MavenSettingsPreferencePage_error_globalSettingsParse); + checkSettings(globalToolchains, Messages.MavenSettingsPreferencePage_error_globalToolchainsMissing, + l -> IMavenToolbox.of(maven).validateToolchains(l).stream().map(Problem::getMessage), + Messages.MavenSettingsPreferencePage_error_globalToolchainsParse); + checkSettings(userSettings, Messages.MavenSettingsPreferencePage_error_userSettingsMissing, l -> maven.validateSettings(l).stream().map(SettingsProblem::getMessage), Messages.MavenSettingsPreferencePage_error_userSettingsParse); @@ -343,10 +374,8 @@ void openEditor(File file) { IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage(); - - IEditorDescriptor desc = workbench.getEditorRegistry().getDefaultEditor("settings.xml"); //$NON-NLS-1$ - - IEditorInput input = new FileStoreEditorInput(EFS.getLocalFileSystem().fromLocalFile(file)); + IEditorDescriptor desc = workbench.getEditorRegistry().getDefaultEditor(file.getName()); //$NON-NLS-1$ + IEditorInput input = new FileStoreEditorInput(EFS.getLocalFileSystem().fromLocalFile(file.getAbsoluteFile())); try { IEditorPart editor = IDE.openEditor(page, input, desc.getId()); if(editor == null) { @@ -363,6 +392,29 @@ void openEditor(File file) { } } + private File getDefaultGlobalSettingsFile() { + return this.getRuntimeBasedFile("conf/settings.xml"); + } + + private File getDefaultGlobalToolchainsFile() { + return this.getRuntimeBasedFile("conf/toolchains.xml"); + } + + /** + * Calcuate relative path of an file to the configured maven runtime. + * + * @param relativePath the expected relative path. + * @return null if the runtime has no accessible location e.g. EMBEDDED. + */ + private File getRuntimeBasedFile(String relativePath) { + final AbstractMavenRuntime runtime = this.runtimeManager.getRuntime(MavenRuntimeManagerImpl.DEFAULT); + final String location = runtime.getLocation(); + if(null != location && !location.isBlank() && runtime.isEditable()) { + return new File(location, relativePath); + } + return null; + } + private String getUserSettings() { return getSettings(userSettingsText); } @@ -375,6 +427,10 @@ private String getGlobalSettings() { return getSettings(globalSettingsText); } + private String getGlobalToolchains() { + return getSettings(globalToolchainsText); + } + private String getSettings(Text settings) { String location = settings.getText().trim(); return location.length() > 0 ? location : null; @@ -392,4 +448,12 @@ protected void browseSettingsAction(Text settings) { checkSettings(); } } + + protected void updateGlobalSettingsDefaultFiles() { + this.globalSettingsText + .setMessage(Optional.ofNullable(this.getDefaultGlobalSettingsFile()).map(File::getAbsolutePath).orElse("")); + + this.globalToolchainsText + .setMessage(Optional.ofNullable(this.getDefaultGlobalToolchainsFile()).map(File::getAbsolutePath).orElse("")); + } } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/CoreSupplier.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/CoreSupplier.java new file mode 100644 index 0000000000..dc456b0751 --- /dev/null +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/CoreSupplier.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2024 Georg Tsakumagos and others + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Georg Tsakumagos - initial declaration + *******************************************************************************/ + +package org.eclipse.m2e.core.embedder; + +import org.eclipse.core.runtime.CoreException; + + +/** + * Represents a supplier of results that throws a {@link CoreException} + *

+ * There is no requirement that a new or distinct result be returned each time the supplier is invoked. + *

+ * This is a functional interface whose functional method is {@link #get()}. + * + * @param the type of results supplied by this supplier + * @since 2.1.0 + * @author Georg Tsakumagos + */ +@FunctionalInterface +public interface CoreSupplier { + + /** + * Gets a result. + * + * @return a result + * @throws CoreException If something went wrong. + */ + T get() 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 4858b3cc92..397e951896 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 @@ -51,6 +51,10 @@ public interface IMavenConfiguration { //settable for embedded maven void setGlobalSettingsFile(String absolutePath) throws CoreException; + String getGlobalToolchainsFile(); + + void setGlobalToolchainsFile(String absolutePath) throws CoreException; + String getUserSettingsFile(); void setUserSettingsFile(String absolutePath) throws CoreException; diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExecutionContext.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExecutionContext.java index edf5cb23a2..0ce802f0d0 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExecutionContext.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/MavenExecutionContext.java @@ -208,6 +208,9 @@ static MavenExecutionRequest createExecutionRequest(IMavenConfiguration mavenCon updateSettingsFiles(request, settingsLocations); //and settings are actually derived from IMavenConfiguration File userToolchainsFile = MavenCli.DEFAULT_USER_TOOLCHAINS_FILE; + if(mavenConfiguration.getGlobalToolchainsFile() != null) { + request.setGlobalToolchainsFile(new File(mavenConfiguration.getGlobalToolchainsFile())); + } if(mavenConfiguration.getUserToolchainsFile() != null) { userToolchainsFile = new File(mavenConfiguration.getUserToolchainsFile()); } 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 e58327cc3d..f45a510388 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 @@ -127,6 +127,7 @@ import org.apache.maven.settings.building.SettingsBuilder; import org.apache.maven.settings.building.SettingsBuildingException; import org.apache.maven.settings.building.SettingsBuildingRequest; +import org.apache.maven.settings.building.SettingsBuildingResult; import org.apache.maven.settings.building.SettingsProblem; import org.apache.maven.settings.building.SettingsProblem.Severity; import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest; @@ -310,7 +311,8 @@ public List validateSettings(String settings) { SettingsBuildingRequest request = new DefaultSettingsBuildingRequest(); request.setUserSettingsFile(settingsFile); try { - lookup(SettingsBuilder.class).build(request); + SettingsBuildingResult result = lookup(SettingsBuilder.class).build(request); + problems.addAll(result.getProblems()); } catch(SettingsBuildingException ex) { problems.addAll(ex.getProblems()); } catch(CoreException ex) { 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 d9d5d479fb..8f778d80ec 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 @@ -100,6 +100,11 @@ public String getGlobalSettingsFile() { return getStringPreference(MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE, null); } + @Override + public String getGlobalToolchainsFile() { + return getStringPreference(MavenPreferenceConstants.P_GLOBAL_TOOLCHAINS_FILE, null); + } + @Override public String getUserSettingsFile() { return getStringPreference(MavenPreferenceConstants.P_USER_SETTINGS_FILE, null); @@ -157,6 +162,11 @@ public void setGlobalSettingsFile(String globalSettingsFile) throws CoreExceptio setSettingsFile(globalSettingsFile, MavenPreferenceConstants.P_GLOBAL_SETTINGS_FILE); } + @Override + public void setGlobalToolchainsFile(String globalToolchainsFile) throws CoreException { + setSettingsFile(globalToolchainsFile, MavenPreferenceConstants.P_GLOBAL_TOOLCHAINS_FILE); + } + @Override public void setUserToolchainsFile(String settingsFile) throws CoreException { setSettingsFile(settingsFile, MavenPreferenceConstants.P_USER_TOOLCHAINS_FILE); diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java index f5d1297ef8..7ace01f635 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/preferences/MavenPreferenceConstants.java @@ -58,6 +58,9 @@ public interface MavenPreferenceConstants { /** String */ String P_GLOBAL_SETTINGS_FILE = PREFIX + "globalSettingsFile"; //$NON-NLS-1$ + /** String */ + String P_GLOBAL_TOOLCHAINS_FILE = PREFIX + "globalToolchainsFile"; //$NON-NLS-1$ + /** String */ String P_USER_SETTINGS_FILE = PREFIX + "userSettingsFile"; //$NON-NLS-1$ diff --git a/org.eclipse.m2e.launching/META-INF/MANIFEST.MF b/org.eclipse.m2e.launching/META-INF/MANIFEST.MF index 523d712280..9d3d8c5799 100644 --- a/org.eclipse.m2e.launching/META-INF/MANIFEST.MF +++ b/org.eclipse.m2e.launching/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: org.eclipse.m2e.launching;singleton:=true -Bundle-Version: 2.0.601.qualifier +Bundle-Version: 2.0.602.qualifier Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.27.0,4.0.0)", org.eclipse.core.variables, diff --git a/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegate.java b/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegate.java index 3fad7104e1..4d20cf620a 100644 --- a/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegate.java +++ b/org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenLaunchDelegate.java @@ -58,11 +58,13 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.maven.cli.CLIManager; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; import org.eclipse.m2e.actions.MavenLaunchConstants; import org.eclipse.m2e.core.MavenPlugin; +import org.eclipse.m2e.core.embedder.CoreSupplier; import org.eclipse.m2e.core.embedder.IMavenConfiguration; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.internal.launch.AbstractMavenRuntime; @@ -113,6 +115,40 @@ public MavenLaunchDelegate() { allowAdvancedSourcelookup(); } + /** + * Appends file based configuration key if not already set. + * + * @param name The name of the setting. + * @param arg The argument without dash. Must not be null. + * @param sb The target. Must not be null. + * @param goals The configured goals. Used to override settings. + * @param substitute true , if variables in settings should be substituted. + * @param source Source for the settings. Must not be null. + * @throws CoreException If something went wrong. + * @throws IllegalArgumentException If the configured file does not exists. + */ + private void appendFileSetting(String name, String arg, StringBuilder sb, String goals, boolean substitute, + CoreSupplier source) throws CoreException, IllegalArgumentException { + final String key = "-" + arg + " "; + if(!goals.contains(key) && 0 >= sb.indexOf(key)) { + String setting = source.get(); + + if(substitute && null != setting) { + setting = LaunchingUtils.substituteVar(setting); + } + + if(null != setting && !setting.isBlank()) { + final File file = new File(setting.trim()); + if(file.exists()) { + sb.append(" "); //$NON-NLS-1$ + sb.append(key).append(quote(file.getAbsolutePath())); + } else { + throw new IllegalArgumentException("invalid path for " + name + ": " + file.getAbsolutePath()); + } + } + } + } + @Override public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException { @@ -433,7 +469,7 @@ private void getProperties(StringBuilder sb, ILaunchConfiguration configuration) try { String profiles = configuration.getAttribute(ATTR_PROFILES, (String) null); if(profiles != null && profiles.trim().length() > 0) { - sb.append(" -P").append(profiles.replaceAll("\\s+", ",")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + sb.append(" -P").append(profiles.replaceAll("\\s+", ",")); ////$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } catch(CoreException ex) { log.error("Exception while getting configuration attribute " + ATTR_PROFILES, ex); @@ -494,28 +530,19 @@ private void getPreferences(StringBuilder sb, ILaunchConfiguration configuration "Unexpected value for" + MavenLaunchConstants.ATTR_COLOR + ": " + colors); }; sb.append(" -Dstyle.color=" + enableColor); - - if(!goals.contains("-gs ")) { //$NON-NLS-1$ - String globalSettings = launchSupport.getSettings(); - if(globalSettings != null && !globalSettings.trim().isEmpty() && !new File(globalSettings.trim()).exists()) { - globalSettings = null; - } - if(globalSettings != null && !globalSettings.trim().isEmpty()) { - sb.append(" -gs ").append(quote(globalSettings)); //$NON-NLS-1$ - } - } - - String settings = configuration.getAttribute(MavenLaunchConstants.ATTR_USER_SETTINGS, (String) null); - settings = LaunchingUtils.substituteVar(settings); - if(settings == null || settings.trim().isEmpty()) { - settings = mavenConfiguration.getUserSettingsFile(); - if(settings != null && !settings.trim().isEmpty() && !new File(settings.trim()).exists()) { - settings = null; - } - } - if(settings != null && !settings.trim().isEmpty()) { - sb.append(" -s ").append(quote(settings)); //$NON-NLS-1$ - } + this.appendFileSetting("global settings", CLIManager.ALTERNATE_GLOBAL_SETTINGS, sb, goals, false, //$NON-NLS-1$ + mavenConfiguration::getGlobalSettingsFile); + this.appendFileSetting("global settings", CLIManager.ALTERNATE_GLOBAL_SETTINGS, sb, goals, false, //$NON-NLS-1$ + launchSupport::getSettings); //$NON-NLS-2$ + this.appendFileSetting("global toolchains", CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS, sb, goals, false, //$NON-NLS-1$ + mavenConfiguration::getGlobalToolchainsFile); //$NON-NLS-2$ + + this.appendFileSetting("user settings", String.valueOf(CLIManager.ALTERNATE_USER_SETTINGS), sb, goals, false, //$NON-NLS-1$ //$NON-NLS-2$ + () -> configuration.getAttribute(MavenLaunchConstants.ATTR_USER_SETTINGS, (String) null)); + this.appendFileSetting("user settings", String.valueOf(CLIManager.ALTERNATE_USER_SETTINGS), sb, goals, false, //$NON-NLS-1$ + mavenConfiguration::getUserSettingsFile); //$NON-NLS-2$ + this.appendFileSetting("user toolchains", String.valueOf(CLIManager.ALTERNATE_USER_TOOLCHAINS), sb, goals, false, //$NON-NLS-1$ + mavenConfiguration::getUserToolchainsFile); //$NON-NLS-2$ // boolean b = preferenceStore.getBoolean(MavenPreferenceConstants.P_CHECK_LATEST_PLUGIN_VERSION); // sb.append(" -D").append(MavenPreferenceConstants.P_CHECK_LATEST_PLUGIN_VERSION).append("=").append(b); diff --git a/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF b/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF index ad1cf50843..0647f1e1fa 100644 --- a/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF +++ b/org.eclipse.m2e.model.edit/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-Name: M2E Maven Project Model Edit Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-Vendor: Eclipse.org - m2e -Bundle-Version: 2.0.400.qualifier +Bundle-Version: 2.0.401.qualifier Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.m2e.model.edit;singleton:=true Require-Bundle: org.eclipse.core.runtime, diff --git a/org.eclipse.m2e.model.edit/plugin.xml b/org.eclipse.m2e.model.edit/plugin.xml index b843e7c1df..f0aec4987e 100644 --- a/org.eclipse.m2e.model.edit/plugin.xml +++ b/org.eclipse.m2e.model.edit/plugin.xml @@ -30,6 +30,14 @@ uri="xsd/maven-v4_0_0.xsd"/> + + + + + + + + + + + + + 1.0.0+ + + Root element of the user configuration file. + + + + + + 1.0.0+ + + Root element of the user configuration file. + + + + + + 1.0.0+ + + + The local repository.<br><b>Default value is:</b> <code>${user.home}/.m2/repository</code> + + + + + + + 1.0.0+ + + + Whether Maven should attempt to interact with the user for input. + + + + + + + 1.0.0+ + + + Whether Maven should use the plugin-registry.xml file to manage plugin versions. + + + + + + + 1.0.0+ + + + Indicate whether maven should operate in offline mode full-time. + + + + + + + 1.0.0+ + + + Configuration for different proxy profiles. Multiple proxy profiles + might come in handy for anyone working from a notebook or other + mobile platform, to enable easy switching of entire proxy + configurations by simply specifying the profile id, again either from + the command line or from the defaults section below. + + + + + + + + + + + + 1.0.0+ + + + Configuration of server-specific settings, mainly authentication + method. This allows configuration of authentication on a per-server + basis. + + + + + + + + + + + + 1.0.0+ + + Configuration of download mirrors for repositories. + + + + + + + + + + + 1.0.0+ + + + Configuration of build profiles for adjusting the build + according to environmental parameters. + + + + + + + + + + + + 1.0.0+ + + + List of manually-activated build profiles, specified in the order in which + they should be applied. + + + + + + + + + + + + 1.0.0+ + + List of groupIds to search for a plugin when that plugin + groupId is not explicitly provided. + + + + + + + + + + + + + 1.0.0+ + + + The <code>&lt;proxy&gt;</code> element contains informations required to a proxy settings. + + + + + + 1.0.0+ + + + Whether this proxy configuration is the active one. + + + + + + + 1.0.0+ + + + The proxy protocol. + + + + + + + 1.0.0+ + + + The proxy user. + + + + + + + 1.0.0+ + + + The proxy password. + + + + + + + 1.0.0+ + + + The proxy port. + + + + + + + 1.0.0+ + + + The proxy host. + + + + + + + 1.0.0+ + + + The list of non-proxied hosts (delimited by |). + + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + + The <code>&lt;server&gt;</code> element contains informations required to a server settings. + + + + + + 1.0.0+ + + + The username used to authenticate. + + + + + + + 1.0.0+ + + + The password used in conjunction with the username to authenticate. + + + + + + + 1.0.0+ + + + The private key location used to authenticate. + + + + + + + 1.0.0+ + + + The passphrase used in conjunction with the privateKey to authenticate. + + + + + + + 1.0.0+ + + + The permissions for files when they are created. + + + + + + + 1.0.0+ + + + The permissions for directories when they are created. + + + + + + + 0.0.0+ + + + Extra configuration for the transport layer. + + + + + + + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + A download mirror for a given repository. + + + + + + 1.0.0+ + + The server ID of the repository being mirrored, e.g., + "central". This MUST NOT match the mirror id. + + + + + + 1.0.0+ + + The optional name that describes the mirror. + + + + + + 1.0.0+ + The URL of the mirror repository. + + + + + 1.1.0+ + The layout of the mirror repository. Since Maven 3. + + + + + 1.1.0+ + + The layouts of repositories being mirrored. This value can be used to restrict the usage + of the mirror to repositories with a matching layout (apart from a matching id). Since Maven 3. + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + + Modifications to the build process which is keyed on some + sort of environmental parameter. + + + + + + + 1.0.0+ + + + The conditional logic which will automatically + trigger the inclusion of this profile. + + + + + + + 0.0.0+ + + + Extended configuration specific to this profile goes here. + Contents take the form of + <code>&lt;property.name&gt;property.value&lt;/property.name&gt;</code> + + + + + + + + + + + + 1.0.0+ + + + The lists of the remote repositories. + + + + + + + + + + + + 1.0.0+ + + + The lists of the remote repositories for discovering plugins. + + + + + + + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + Repository contains the information needed for establishing + connections with remote repository + + + + + + 1.0.0+ + + How to handle downloading of releases from this repository + + + + + + 1.0.0+ + + How to handle downloading of snapshots from this repository + + + + + + 1.0.0+ + + + A unique identifier for a repository. + + + + + + + 1.0.0+ + + + Human readable name of the repository. + + + + + + + 1.0.0+ + + + The url of the repository. + + + + + + + 1.0.0+ + + The type of layout this repository uses for locating and + storing artifacts - can be "legacy" or "default". + + + + + + + + 1.0.0+ + Download policy + + + + + 1.0.0+ + + Whether to use this repository for downloading this type of + artifact. + + + + + + 1.0.0+ + + The frequency for downloading updates - can be "always", + "daily" (default), "interval:XXX" (in minutes) or "never" + (only if it doesn't exist locally). + + + + + + 1.0.0+ + + What to do when verification of an artifact checksum fails - + warn, fail, etc. Valid values are "fail" or "warn". + + + + + + + + 1.0.0+ + + + The conditions within the build runtime environment which will trigger + the automatic inclusion of the parent build profile. + + + + + + + 1.0.0+ + + Flag specifying whether this profile is active as a default. + + + + + + 1.0.0+ + + + Specifies that this profile will be activated when a matching JDK is detected. + + + + + + + 1.0.0+ + + + Specifies that this profile will be activated when matching OS attributes are detected. + + + + + + + 1.0.0+ + + + Specifies that this profile will be activated when this System property is specified. + + + + + + + 1.0.0+ + + + Specifies that this profile will be activated based on existence of a file. + + + + + + + + + 1.0.0+ + + + This is an activator which will detect an operating system's attributes in order to activate + its profile. + + + + + + + 1.0.0+ + + The name of the OS to be used to activate a profile. + + + + + + 1.0.0+ + + The general family of the OS to be used to activate a + profile (e.g. 'windows') + + + + + + 1.0.0+ + + The architecture of the OS to be used to activate a profile. + + + + + + 1.0.0+ + + The version of the OS to be used to activate a profile. + + + + + + + + 1.0.0+ + + + This is the property specification used to activate a profile. If the value field is empty, + then the existence of the named property will activate the profile, otherwise it does a case-sensitive + match against the property value as well. + + + + + + + 1.0.0+ + + The name of the property to be used to activate a profile. + + + + + + 1.0.0+ + + The value of the property to be used to activate a profile. + + + + + + + + 1.0.0+ + + + This is the file specification used to activate a profile. The missing value will be a the location + of a file that needs to exist, and if it doesn't the profile must run. On the other hand exists will test + for the existence of the file and if it is there will run the profile. + + + + + + + 1.0.0+ + + The name of the file that should be missing to activate a + profile. + + + + + + 1.0.0+ + + The name of the file that should exist to activate a profile. + + + + + + \ No newline at end of file diff --git a/org.eclipse.m2e.model.edit/xsd/settings-1.2.0.xsd b/org.eclipse.m2e.model.edit/xsd/settings-1.2.0.xsd new file mode 100644 index 0000000000..797779902d --- /dev/null +++ b/org.eclipse.m2e.model.edit/xsd/settings-1.2.0.xsd @@ -0,0 +1,762 @@ + + + + + + + + + + 1.0.0+ + + Root element of the user configuration file. + + + + + + 1.0.0+ + + Root element of the user configuration file. + + + + + + 1.0.0+ + + + The local repository.<br><b>Default value is:</b> <code>${user.home}/.m2/repository</code> + + + + + + + 1.0.0+ + + + Whether Maven should attempt to interact with the user for input. + + + + + + + 1.0.0+ + + + Whether Maven should use the plugin-registry.xml file to manage plugin versions. + + + + + + + 1.0.0+ + + + Indicate whether maven should operate in offline mode full-time. + + + + + + + 1.0.0+ + + + Configuration for different proxy profiles. Multiple proxy profiles + might come in handy for anyone working from a notebook or other + mobile platform, to enable easy switching of entire proxy + configurations by simply specifying the profile id, again either from + the command line or from the defaults section below. + + + + + + + + + + + + 1.0.0+ + + + Configuration of server-specific settings, mainly authentication + method. This allows configuration of authentication on a per-server + basis. + + + + + + + + + + + + 1.0.0+ + + Configuration of download mirrors for repositories. + + + + + + + + + + + 1.0.0+ + + + Configuration of build profiles for adjusting the build + according to environmental parameters. + + + + + + + + + + + + 1.0.0+ + + + List of manually-activated build profiles, specified in the order in which + they should be applied. + + + + + + + + + + + + 1.0.0+ + + List of groupIds to search for a plugin when that plugin + groupId is not explicitly provided. + + + + + + + + + + + + + 1.0.0+ + + + The <code>&lt;proxy&gt;</code> element contains informations required to a proxy settings. + + + + + + 1.0.0+ + + + Whether this proxy configuration is the active one. + + + + + + + 1.0.0+ + + + The proxy protocol. + + + + + + + 1.0.0+ + + + The proxy user. + + + + + + + 1.0.0+ + + + The proxy password. + + + + + + + 1.0.0+ + + + The proxy port. + + + + + + + 1.0.0+ + + + The proxy host. + + + + + + + 1.0.0+ + + + The list of non-proxied hosts (delimited by |). + + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + + The <code>&lt;server&gt;</code> element contains informations required to a server settings. + + + + + + 1.0.0+ + + + The username used to authenticate. + + + + + + + 1.0.0+ + + + The password used in conjunction with the username to authenticate. + + + + + + + 1.0.0+ + + + The private key location used to authenticate. + + + + + + + 1.0.0+ + + + The passphrase used in conjunction with the privateKey to authenticate. + + + + + + + 1.0.0+ + + + The permissions for files when they are created. + + + + + + + 1.0.0+ + + + The permissions for directories when they are created. + + + + + + + 0.0.0+ + + + Extra configuration for the transport layer. + + + + + + + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + A download mirror for a given repository. + + + + + + 1.0.0+ + + The server ID of the repository being mirrored, e.g., + "central". This MUST NOT match the mirror id. + + + + + + 1.0.0+ + + The optional name that describes the mirror. + + + + + + 1.0.0+ + The URL of the mirror repository. + + + + + 1.1.0+ + The layout of the mirror repository. Since Maven 3. + + + + + 1.1.0+ + + The layouts of repositories being mirrored. This value can be used to restrict the usage + of the mirror to repositories with a matching layout (apart from a matching id). Since Maven 3. + + + + + + 1.2.0+ + + Whether this mirror should be blocked from any download request but fail the download process, explaining why. + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + + Modifications to the build process which is keyed on some + sort of environmental parameter. + + + + + + + 1.0.0+ + + + The conditional logic which will automatically + trigger the inclusion of this profile. + + + + + + + 0.0.0+ + + + Extended configuration specific to this profile goes here. + Contents take the form of + <code>&lt;property.name&gt;property.value&lt;/property.name&gt;</code> + + + + + + + + + + + + 1.0.0+ + + + The lists of the remote repositories. + + + + + + + + + + + + 1.0.0+ + + + The lists of the remote repositories for discovering plugins. + + + + + + + + + + + + 1.0.0+ + + + + + + + 1.0.0+ + + Repository contains the information needed for establishing + connections with remote repository + + + + + + 1.0.0+ + + How to handle downloading of releases from this repository + + + + + + 1.0.0+ + + How to handle downloading of snapshots from this repository + + + + + + 1.0.0+ + + + A unique identifier for a repository. + + + + + + + 1.0.0+ + + + Human readable name of the repository. + + + + + + + 1.0.0+ + + + The url of the repository. + + + + + + + 1.0.0+ + + The type of layout this repository uses for locating and + storing artifacts - can be "legacy" or "default". + + + + + + + + 1.0.0+ + Download policy + + + + + 1.0.0+ + + Whether to use this repository for downloading this type of + artifact. + + + + + + 1.0.0+ + + The frequency for downloading updates - can be "always", + "daily" (default), "interval:XXX" (in minutes) or "never" + (only if it doesn't exist locally). + + + + + + 1.0.0+ + + What to do when verification of an artifact checksum fails - + warn, fail, etc. Valid values are "fail" or "warn". + + + + + + + + 1.0.0+ + + + The conditions within the build runtime environment which will trigger + the automatic inclusion of the parent build profile. + + + + + + + 1.0.0+ + + Flag specifying whether this profile is active as a default. + + + + + + 1.0.0+ + + + Specifies that this profile will be activated when a matching JDK is detected. + + + + + + + 1.0.0+ + + + Specifies that this profile will be activated when matching OS attributes are detected. + + + + + + + 1.0.0+ + + + Specifies that this profile will be activated when this System property is specified. + + + + + + + 1.0.0+ + + + Specifies that this profile will be activated based on existence of a file. + + + + + + + + + 1.0.0+ + + + This is an activator which will detect an operating system's attributes in order to activate + its profile. + + + + + + + 1.0.0+ + + The name of the OS to be used to activate a profile. + + + + + + 1.0.0+ + + The general family of the OS to be used to activate a + profile (e.g. 'windows') + + + + + + 1.0.0+ + + The architecture of the OS to be used to activate a profile. + + + + + + 1.0.0+ + + The version of the OS to be used to activate a profile. + + + + + + + + 1.0.0+ + + + This is the property specification used to activate a profile. If the value field is empty, + then the existence of the named property will activate the profile, otherwise it does a case-sensitive + match against the property value as well. + + + + + + + 1.0.0+ + + The name of the property to be used to activate a profile. + + + + + + 1.0.0+ + + The value of the property to be used to activate a profile. + + + + + + + + 1.0.0+ + + + This is the file specification used to activate a profile. The missing value will be a the location + of a file that needs to exist, and if it doesn't the profile must run. On the other hand exists will test + for the existence of the file and if it is there will run the profile. + + + + + + + 1.0.0+ + + The name of the file that should be missing to activate a + profile. + + + + + + 1.0.0+ + + The name of the file that should exist to activate a profile. + + + + + + \ No newline at end of file diff --git a/org.eclipse.m2e.model.edit/xsd/toolchains-1.0.0.xsd b/org.eclipse.m2e.model.edit/xsd/toolchains-1.0.0.xsd new file mode 100644 index 0000000000..7146a3c5ab --- /dev/null +++ b/org.eclipse.m2e.model.edit/xsd/toolchains-1.0.0.xsd @@ -0,0 +1,105 @@ + + + + + + + + + + 1.0.0+ + + The <code>&lt;toolchains&gt;</code> element is the root of the descriptor. + The following table lists all of the possible child elements. + + + + + + 1.0.0+ + + The <code>&lt;toolchains&gt;</code> element is the root of the descriptor. + The following table lists all of the possible child elements. + + + + + + 1.0.0+ + The toolchain instance definition. + + + + + + + 1.0.0+ + Definition of a toolchain instance. + + + + + 1.0.0+ + + Type of toolchain:<ul> + <li><code>jdk</code> for + <a href="http://maven.apache.org/plugins/maven-toolchains-plugin/toolchains/jdk.html">JDK Standard Toolchain</a>,</li> + <li>...</li> + </ul> + + + + + + 1.0.0+ + + + <p>Toolchain identification information, which will be matched against project requirements.</p> + <p>Actual content structure is completely open: each toochain type will define its own format and semantics.</p> + <p>In general, this is a properties format: <code>&lt;name&gt;value&lt;/name&gt;</code> with + predefined properties names.</p> + + + + + + + + + + + 1.0.0+ + + + <p>Toolchain configuration information, like location or any information that is to be retrieved.</p> + <p>Actual content structure is completely open: each toochain type will define its own format and semantics.</p> + <p>In general, this is a properties format: <code>&lt;name&gt;value&lt;/name&gt;</code> wih + predefined properties names.</p> + + + + + + + + + + + \ No newline at end of file diff --git a/org.eclipse.m2e.model.edit/xsd/toolchains-1.1.0.xsd b/org.eclipse.m2e.model.edit/xsd/toolchains-1.1.0.xsd new file mode 100644 index 0000000000..95449af90b --- /dev/null +++ b/org.eclipse.m2e.model.edit/xsd/toolchains-1.1.0.xsd @@ -0,0 +1,107 @@ + + + + + + + + + + 1.0.0+ + + The <code>&lt;toolchains&gt;</code> element is the root of the descriptor. + The following table lists all of the possible child elements. + + + + + + 1.0.0+ + + The <code>&lt;toolchains&gt;</code> element is the root of the descriptor. + The following table lists all of the possible child elements. + + + + + + 1.0.0+ + The toolchain instance definition. + + + + + + + 1.0.0+ + Definition of a toolchain instance. + + + + + 1.0.0+ + + Type of toolchain:<ul> + <li><code>jdk</code> for + <a href="https://maven.apache.org/plugins/maven-toolchains-plugin/toolchains/jdk.html">JDK Standard Toolchain</a>,</li> + <li>other value for + <a href="https://maven.apache.org/plugins/maven-toolchains-plugin/toolchains/custom.html">Custom Toolchain</a></li> + </ul> + + + + + + 1.1.0+ + + + <p>Toolchain identification information, which will be matched against project requirements.</p> + <p>For Maven 2.0.9 to 3.2.3, the actual content structure was completely open: each toolchain type would define its own format and semantics. + In general, this was a properties format.</p> + <p>Since Maven 3.2.4, the type for this field has been changed to Properties to match the de-facto format.</p> + <p>Each toolchain defines its own properties names and semantics.</p> + + + + + + + + + + + 1.0.0+ + + + <p>Toolchain configuration information, like location or any information that is to be retrieved.</p> + <p>Actual content structure is completely open: each toolchain type will define its own format and semantics.</p> + <p>In general, this is a properties format: <code>&lt;name&gt;value&lt;/name&gt;</code> with + per-toolchain defined properties names.</p> + + + + + + + + + + + \ No newline at end of file