From 5d3e12f0a0f7c2677e1d8ed1a35823743678d483 Mon Sep 17 00:00:00 2001 From: Mickael Istria Date: Mon, 16 May 2022 16:20:50 +0200 Subject: [PATCH] Allow basedir in MavenExecutionContext and project-specific MavenImpl This allows to read and set project-specific properties that can be passed to the Maven request and used for further executions. Covers parts of https://github.com/eclipse-m2e/m2e-core/issues/666 and progress towards https://github.com/eclipse-m2e/m2e-core/issues/546 --- .../resources/projects/dotMvn/.mvn/.keep | 0 .../resources/projects/dotMvn/child/pom.xml | 6 +++++ .../org/eclipse/m2e/core/MavenBugsTest.java | 26 +++++++++++++++++++ .../embedder/MavenExecutionContext.java | 8 +++++- .../m2e/core/internal/embedder/MavenImpl.java | 25 +++++++++++++++--- .../project/registry/MavenProjectFacade.java | 10 +++++-- 6 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 org.eclipse.m2e.core.tests/resources/projects/dotMvn/.mvn/.keep create mode 100644 org.eclipse.m2e.core.tests/resources/projects/dotMvn/child/pom.xml diff --git a/org.eclipse.m2e.core.tests/resources/projects/dotMvn/.mvn/.keep b/org.eclipse.m2e.core.tests/resources/projects/dotMvn/.mvn/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/org.eclipse.m2e.core.tests/resources/projects/dotMvn/child/pom.xml b/org.eclipse.m2e.core.tests/resources/projects/dotMvn/child/pom.xml new file mode 100644 index 0000000000..bee4952ad5 --- /dev/null +++ b/org.eclipse.m2e.core.tests/resources/projects/dotMvn/child/pom.xml @@ -0,0 +1,6 @@ + + 4.0.0 + org.eclipse.m2e.tests.projects + simplePomOK + 1 + \ No newline at end of file diff --git a/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/core/MavenBugsTest.java b/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/core/MavenBugsTest.java index 98956ca543..d48bad2f0c 100644 --- a/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/core/MavenBugsTest.java +++ b/org.eclipse.m2e.core.tests/src/org/eclipse/m2e/core/MavenBugsTest.java @@ -26,11 +26,13 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.m2e.core.internal.MavenPluginActivator; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.MavenProjectInfo; import org.eclipse.m2e.core.project.ProjectImportConfiguration; import org.eclipse.m2e.tests.common.AbstractMavenProjectTestCase; import org.junit.After; +import org.junit.Assert; import org.junit.Test; @@ -78,5 +80,29 @@ public void testMNG6530() throws Exception { } finally { FileUtils.deleteDirectory(tempDirectory); } + } + + @Test + public void testMultiModuleProjectDirectoryChild() throws Exception { + IProject project = createExisting("simple", "resources/projects/dotMvn/", false); + waitForJobsToComplete(monitor); + IMavenProjectFacade facade = MavenPluginActivator.getDefault().getMavenProjectManagerImpl().create(project.getFile("child/pom.xml"), + true, monitor); + Assert.assertNotNull(facade); + File[] multiModuleDirectory = new File[] { null }; + facade.getMaven().execute((context, monitor) -> multiModuleDirectory[0] = context.getExecutionRequest().getMultiModuleProjectDirectory(), null); + assertEquals(project.getLocation().toFile(), multiModuleDirectory[0]); + } + + @Test + public void testMultiModuleProjectDirectorySimple() throws Exception { + IProject project = createExisting("hierarchyWithDotMVN", "resources/projects/simplePomOK", true); + waitForJobsToComplete(monitor); + IMavenProjectFacade facade = MavenPluginActivator.getDefault().getMavenProjectManagerImpl().create(project, + monitor); + Assert.assertNotNull(facade); + File[] multiModuleDirectory = new File[] { null }; + facade.getMaven().execute((context, monitor) -> multiModuleDirectory[0] = context.getExecutionRequest().getMultiModuleProjectDirectory(), null); + assertEquals(project.getLocation().toFile(), multiModuleDirectory[0]); } } 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 8ad9f00c68..4a9ae947c6 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 @@ -15,6 +15,7 @@ import static org.eclipse.m2e.core.internal.M2EUtils.copyProperties; +import java.io.File; import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; @@ -66,13 +67,17 @@ public class MavenExecutionContext implements IMavenExecutionContext { // TODO maybe delegate to parent context private Map context; - public MavenExecutionContext(MavenImpl maven) { + private final File basedir; + + public MavenExecutionContext(MavenImpl maven, File basedir) { this.maven = maven; + this.basedir = basedir == null ? null : (basedir.isDirectory() ? basedir : basedir.getParentFile()); } MavenExecutionContext(MavenImpl maven, MavenExecutionRequest request) { this.maven = maven; this.request = request; + this.basedir = request.getBaseDirectory() != null ? new File(request.getBaseDirectory()) : null; } @Override @@ -99,6 +104,7 @@ protected MavenExecutionRequest newExecutionRequest() throws CoreException { if(request == null) { request = maven.createExecutionRequest(); } + request.setMultiModuleProjectDirectory(MavenImpl.computeMultiModuleProjectDirectory(basedir)); return request; } 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 c54c73ef96..51bc429e2e 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 @@ -174,7 +174,7 @@ @Component(service = {IMaven.class, IMavenConfigurationChangeListener.class}) -public class MavenImpl implements IMaven, IMavenConfigurationChangeListener { +public class MavenImpl implements IMaven, IMavenConfigurationChangeListener, Cloneable { private static final Logger log = LoggerFactory.getLogger(MavenImpl.class); /** @@ -204,6 +204,8 @@ public class MavenImpl implements IMaven, IMavenConfigurationChangeListener { /** Last modified timestamp of cached user settings */ private long settingsTimestamp; + private File basedir; + MavenExecutionRequest createExecutionRequest() throws CoreException { MavenExecutionRequest request = new DefaultMavenExecutionRequest(); @@ -242,6 +244,10 @@ MavenExecutionRequest createExecutionRequest() throws CoreException { request.setGlobalChecksumPolicy(mavenConfiguration.getGlobalChecksumPolicy()); // the right way to disable snapshot update // request.setUpdateSnapshots(false); + if(basedir != null) { + request.setBaseDirectory(basedir); + request.setMultiModuleProjectDirectory(computeMultiModuleProjectDirectory(basedir)); + } return request; } @@ -665,7 +671,7 @@ public Artifact resolve(String groupId, String artifactId, String version, Strin private IMavenExecutionContext context() { MavenExecutionContext context = MavenExecutionContext.getThreadContext(); if(context == null) { - context = new MavenExecutionContext(this); + context = createExecutionContext(); } return context; } @@ -1250,7 +1256,7 @@ public void execute(MavenProject project, MojoExecution execution, IProgressMoni @Override public MavenExecutionContext createExecutionContext() { - return new MavenExecutionContext(this); + return new MavenExecutionContext(this, basedir); } @Override @@ -1308,4 +1314,17 @@ public static File computeMultiModuleProjectDirectory(File file) { return basedir; } + public MavenImpl cloneForBasedir(File basedir) { + try { + MavenImpl res = (MavenImpl) clone(); + res.basedir = basedir; + // TODO: more customization may be needed, more fields cleared, maybe in the end no + // need to start from a clone at all... + // TODO? What about getExecutionContext() that's tied to the thread and not to this? + return res; + } catch(CloneNotSupportedException ex) { + // unexpected, let's just crash + throw new RuntimeException(ex); + } + } } diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java index be6a5a682a..b25046a862 100644 --- a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java +++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/project/registry/MavenProjectFacade.java @@ -41,6 +41,7 @@ import org.eclipse.m2e.core.embedder.ArtifactRef; import org.eclipse.m2e.core.embedder.ArtifactRepositoryRef; import org.eclipse.m2e.core.embedder.IMaven; +import org.eclipse.m2e.core.internal.embedder.MavenImpl; import org.eclipse.m2e.core.lifecyclemapping.model.IPluginExecutionMetadata; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.MavenProjectUtils; @@ -108,6 +109,8 @@ public class MavenProjectFacade implements IMavenProjectFacade, Serializable { private transient Map sessionProperties; + private IMaven maven; + public MavenProjectFacade(ProjectRegistryManager manager, IFile pom, MavenProject mavenProject, ResolverConfiguration resolverConfiguration) { this.manager = manager; @@ -532,7 +535,10 @@ public List getExecutionPlan(String lifecycle, IProgressMonitor m @Override public IMaven getMaven() { - // TODO: if project has Maven customization (such as a .mvn, MAVEN_OPTS...) - return MavenPlugin.getMaven(); + if(maven == null) { + File basedir = pomFile != null ? (pomFile.isDirectory() ? pomFile : pomFile.getParentFile()) : null; + maven = ((MavenImpl) MavenPlugin.getMaven()).cloneForBasedir(basedir); + } + return maven; } }