mirror of https://github.com/apache/maven.git
[MNG-7038] Introduce public properties to point to the root and top directories of (multi-module) project (#1061)
This commit introduces three properties: * project.rootDirectory: the project's directory or parent directory containing a .mvn subdirectory or a pom.xml flagged with the root="true" attribute. If no such directory can be found, accessing the rootDirectory property will throw an IllegalStateException. * session.topDirectory : the directory of the topmost project being built, usually the current directory or the directory pointed at by the -f/--file command line argument. The topDirectory is similar to the executionRootDirectory property available on the session, but renamed to make it coherent with the new rootDirectory and to avoid using root in its name. The topDirectory property is computed by the CLI as the directory pointed at by the -f/--file command line argument, or the current directory if there's no such argument. * session.rootDirectory : the rootDirectory for the topDirectory project. The topDirectory and rootDirectory properties are made available on the MavenSession / Session and deprecate the executionRootDirectory and multiModuleProjectDirectory properties. The rootDirectory should never change for a given project and is thus made available for profile activation and model interpolation (without the project. prefix, similar to basedir). The goal is also to make the rootDirectory property also available during command line arguments interpolation. A root boolean attribute is also added to the model to indicate that the project is the root project. This attribute is only supported if the buildconsumer feature is active and removed before the pom is installed or deployed. It can be used as an alternative mechanism to the .mvn directory.
This commit is contained in:
parent
9e51a8fe95
commit
2db7c85b64
|
@ -86,8 +86,45 @@ default String getId() {
|
|||
return getModel().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #isTopProject()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isExecutionRoot();
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating if the project is the top level project for
|
||||
* this reactor build. The top level project may be different from the
|
||||
* {@code rootDirectory}, especially if a subtree of the project is being
|
||||
* built, either because Maven has been launched in a subdirectory or using
|
||||
* a {@code -f} option.
|
||||
*
|
||||
* @return {@code true} if the project is the top level project for this build
|
||||
*/
|
||||
boolean isTopProject();
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating if the project is a root project,
|
||||
* meaning that the {@link #getRootDirectory()} and {@link #getBasedir()}
|
||||
* points to the same directory, and that either {@link Model#isRoot()}
|
||||
* is {@code true} or that {@code basedir} contains a {@code .mvn} child
|
||||
* directory.
|
||||
*
|
||||
* @return {@code true} if the project is the root project
|
||||
* @see Model#isRoot()
|
||||
*/
|
||||
boolean isRootProject();
|
||||
|
||||
/**
|
||||
* Gets the root directory of the project, which is the parent directory
|
||||
* containing the {@code .mvn} directory or flagged with {@code root="true"}.
|
||||
*
|
||||
* @throws IllegalStateException if the root directory could not be found
|
||||
* @see Session#getRootDirectory()
|
||||
*/
|
||||
@Nonnull
|
||||
Path getRootDirectory();
|
||||
|
||||
@Nonnull
|
||||
Optional<Project> getParent();
|
||||
|
||||
|
|
|
@ -84,9 +84,34 @@ public interface Session {
|
|||
@Nonnull
|
||||
Instant getStartTime();
|
||||
|
||||
/**
|
||||
* Gets the directory of the topmost project being built, usually the current directory or the
|
||||
* directory pointed at by the {@code -f/--file} command line argument.
|
||||
*/
|
||||
@Nonnull
|
||||
Path getTopDirectory();
|
||||
|
||||
/**
|
||||
* Gets the root directory of the session, which is the root directory for the top directory project.
|
||||
*
|
||||
* @throws IllegalStateException if the root directory could not be found
|
||||
* @see #getTopDirectory()
|
||||
* @see Project#getRootDirectory()
|
||||
*/
|
||||
@Nonnull
|
||||
Path getRootDirectory();
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getRootDirectory()} instead
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
Path getMultiModuleProjectDirectory();
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getTopDirectory()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@Nonnull
|
||||
Path getExecutionRootDirectory();
|
||||
|
||||
|
@ -97,8 +122,8 @@ public interface Session {
|
|||
* Returns the plugin context for mojo being executed and the specified
|
||||
* {@link Project}, never returns {@code null} as if context not present, creates it.
|
||||
*
|
||||
* <strong>Implementation note:</strong> while this method return type is {@link Map}, the returned map instance
|
||||
* implements {@link java.util.concurrent.ConcurrentMap} as well.
|
||||
* <strong>Implementation note:</strong> while this method return type is {@link Map}, the
|
||||
* returned map instance implements {@link java.util.concurrent.ConcurrentMap} as well.
|
||||
*
|
||||
* @throws org.apache.maven.api.services.MavenException if not called from the within a mojo execution
|
||||
*/
|
||||
|
|
|
@ -212,6 +212,19 @@
|
|||
</description>
|
||||
<type>String</type>
|
||||
</field>
|
||||
<field xml.attribute="true" xml.tagName="root">
|
||||
<name>root</name>
|
||||
<version>4.0.0+</version>
|
||||
<description>
|
||||
<![CDATA[
|
||||
Indicates that this project is the root project, located in the upper directory of the source tree.
|
||||
This is the directory which may contain the .mvn directory.
|
||||
<br><b>Since</b>: Maven 4.0.0
|
||||
]]>
|
||||
</description>
|
||||
<type>boolean</type>
|
||||
<defaultValue>false</defaultValue>
|
||||
</field>
|
||||
<field>
|
||||
<name>inceptionYear</name>
|
||||
<version>3.0.0+</version>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
import org.apache.maven.bridge.MavenRepositorySystem;
|
||||
import org.apache.maven.model.building.ModelBuilder;
|
||||
import org.apache.maven.model.building.ModelProcessor;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.repository.internal.ModelCacheFactory;
|
||||
import org.eclipse.aether.RepositorySystem;
|
||||
import org.eclipse.aether.impl.RemoteRepositoryManager;
|
||||
|
@ -45,7 +46,8 @@ public TestProjectBuilder(
|
|||
RepositorySystem repoSystem,
|
||||
RemoteRepositoryManager repositoryManager,
|
||||
ProjectDependenciesResolver dependencyResolver,
|
||||
ModelCacheFactory modelCacheFactory) {
|
||||
ModelCacheFactory modelCacheFactory,
|
||||
RootLocator rootLocator) {
|
||||
super(
|
||||
modelBuilder,
|
||||
modelProcessor,
|
||||
|
@ -54,7 +56,8 @@ public TestProjectBuilder(
|
|||
repoSystem,
|
||||
repositoryManager,
|
||||
dependencyResolver,
|
||||
modelCacheFactory);
|
||||
modelCacheFactory,
|
||||
rootLocator);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.maven.execution;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
@ -30,6 +31,7 @@
|
|||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
||||
import org.apache.maven.model.Profile;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.project.DefaultProjectBuildingRequest;
|
||||
import org.apache.maven.project.ProjectBuildingRequest;
|
||||
import org.apache.maven.properties.internal.SystemProperties;
|
||||
|
@ -102,6 +104,10 @@ public class DefaultMavenExecutionRequest implements MavenExecutionRequest {
|
|||
|
||||
private File basedir;
|
||||
|
||||
private Path rootDirectory;
|
||||
|
||||
private Path topDirectory;
|
||||
|
||||
private List<String> goals;
|
||||
|
||||
private boolean useReactor = false;
|
||||
|
@ -1051,16 +1057,43 @@ public MavenExecutionRequest setToolchains(Map<String, List<ToolchainModel>> too
|
|||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setMultiModuleProjectDirectory(File directory) {
|
||||
this.multiModuleProjectDirectory = directory;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public File getMultiModuleProjectDirectory() {
|
||||
return multiModuleProjectDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getRootDirectory() {
|
||||
if (rootDirectory == null) {
|
||||
throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
|
||||
}
|
||||
return rootDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenExecutionRequest setRootDirectory(Path rootDirectory) {
|
||||
this.rootDirectory = rootDirectory;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getTopDirectory() {
|
||||
return topDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenExecutionRequest setTopDirectory(Path topDirectory) {
|
||||
this.topDirectory = topDirectory;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenExecutionRequest setEventSpyDispatcher(EventSpyDispatcher eventSpyDispatcher) {
|
||||
this.eventSpyDispatcher = eventSpyDispatcher;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.maven.execution;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -91,8 +92,17 @@ public interface MavenExecutionRequest {
|
|||
// ----------------------------------------------------------------------
|
||||
|
||||
// Base directory
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #setTopDirectory(Path)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
MavenExecutionRequest setBaseDirectory(File basedir);
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getTopDirectory()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
String getBaseDirectory();
|
||||
|
||||
// Timing (remove this)
|
||||
|
@ -494,14 +504,51 @@ public interface MavenExecutionRequest {
|
|||
|
||||
/**
|
||||
* @since 3.3.0
|
||||
* @deprecated use {@link #setRootDirectory(Path)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
void setMultiModuleProjectDirectory(File file);
|
||||
|
||||
/**
|
||||
* @since 3.3.0
|
||||
* @deprecated use {@link #getRootDirectory()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
File getMultiModuleProjectDirectory();
|
||||
|
||||
/**
|
||||
* Sets the top directory of the project.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
MavenExecutionRequest setTopDirectory(Path topDirectory);
|
||||
|
||||
/**
|
||||
* Gets the directory of the topmost project being built, usually the current directory or the
|
||||
* directory pointed at by the {@code -f/--file} command line argument.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
Path getTopDirectory();
|
||||
|
||||
/**
|
||||
* Sets the root directory of the project.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
MavenExecutionRequest setRootDirectory(Path rootDirectory);
|
||||
|
||||
/**
|
||||
* Gets the root directory of the top project, which is the parent directory containing the {@code .mvn}
|
||||
* directory or a {@code pom.xml} file with the {@code root="true"} attribute.
|
||||
* If there's no such directory, an {@code IllegalStateException} will be thrown.
|
||||
*
|
||||
* @throws IllegalStateException if the root directory could not be found
|
||||
* @see #getTopDirectory()
|
||||
* @since 4.0.0
|
||||
*/
|
||||
Path getRootDirectory();
|
||||
|
||||
/**
|
||||
* @since 3.3.0
|
||||
*/
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.maven.execution;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -141,10 +142,30 @@ public List<MavenProject> getProjects() {
|
|||
return projects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #getTopDirectory()} ()}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getExecutionRootDirectory() {
|
||||
return request.getBaseDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MavenExecutionRequest#getTopDirectory()
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public Path getTopDirectory() {
|
||||
return request.getTopDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MavenExecutionRequest#getRootDirectory()
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public Path getRootDirectory() {
|
||||
return request.getRootDirectory();
|
||||
}
|
||||
|
||||
public MavenExecutionRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,22 @@ public boolean isExecutionRoot() {
|
|||
return project.isExecutionRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTopProject() {
|
||||
return getBasedir().isPresent()
|
||||
&& getBasedir().get().equals(getSession().getTopDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRootProject() {
|
||||
return getBasedir().isPresent() && getBasedir().get().equals(getRootDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getRootDirectory() {
|
||||
return project.getRootDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Project> getParent() {
|
||||
MavenProject parent = project.getParent();
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.apache.maven.internal.impl;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -150,7 +149,17 @@ public Path getMultiModuleProjectDirectory() {
|
|||
@Nonnull
|
||||
@Override
|
||||
public Path getExecutionRootDirectory() {
|
||||
return Paths.get(mavenSession.getRequest().getBaseDirectory());
|
||||
return getTopDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getRootDirectory() {
|
||||
return mavenSession.getRequest().getRootDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getTopDirectory() {
|
||||
return mavenSession.getRequest().getTopDirectory();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
|
|
@ -74,6 +74,9 @@ public void injectTransformedArtifacts(MavenProject project, RepositorySystemSes
|
|||
generatedFile = Files.createTempFile(buildDir, CONSUMER_POM_CLASSIFIER, "pom");
|
||||
}
|
||||
project.addAttachedArtifact(new ConsumerPomArtifact(project, generatedFile, session));
|
||||
} else if (project.getModel().isRoot()) {
|
||||
throw new IllegalStateException(
|
||||
"The use of the root attribute on the model requires the buildconsumer feature to be active");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
import org.apache.maven.model.building.TransformerContext;
|
||||
import org.apache.maven.model.building.TransformerContextBuilder;
|
||||
import org.apache.maven.model.resolution.ModelResolver;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
|
||||
import org.apache.maven.repository.internal.ModelCacheFactory;
|
||||
import org.codehaus.plexus.util.Os;
|
||||
|
@ -101,6 +102,8 @@ public class DefaultProjectBuilder implements ProjectBuilder {
|
|||
private final ProjectDependenciesResolver dependencyResolver;
|
||||
private final ModelCacheFactory modelCacheFactory;
|
||||
|
||||
private final RootLocator rootLocator;
|
||||
|
||||
@SuppressWarnings("checkstyle:ParameterNumber")
|
||||
@Inject
|
||||
public DefaultProjectBuilder(
|
||||
|
@ -111,7 +114,8 @@ public DefaultProjectBuilder(
|
|||
RepositorySystem repoSystem,
|
||||
RemoteRepositoryManager repositoryManager,
|
||||
ProjectDependenciesResolver dependencyResolver,
|
||||
ModelCacheFactory modelCacheFactory) {
|
||||
ModelCacheFactory modelCacheFactory,
|
||||
RootLocator rootLocator) {
|
||||
this.modelBuilder = modelBuilder;
|
||||
this.modelProcessor = modelProcessor;
|
||||
this.projectBuildingHelper = projectBuildingHelper;
|
||||
|
@ -120,6 +124,7 @@ public DefaultProjectBuilder(
|
|||
this.repositoryManager = repositoryManager;
|
||||
this.dependencyResolver = dependencyResolver;
|
||||
this.modelCacheFactory = modelCacheFactory;
|
||||
this.rootLocator = rootLocator;
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
// MavenProjectBuilder Implementation
|
||||
|
@ -162,6 +167,11 @@ private ProjectBuildingResult build(File pomFile, ModelSource modelSource, Inter
|
|||
request.setModelSource(modelSource);
|
||||
request.setLocationTracking(true);
|
||||
|
||||
if (pomFile != null) {
|
||||
project.setRootDirectory(
|
||||
rootLocator.findRoot(pomFile.getParentFile().toPath()));
|
||||
}
|
||||
|
||||
ModelBuildingResult result;
|
||||
try {
|
||||
result = modelBuilder.build(request);
|
||||
|
@ -445,6 +455,8 @@ private boolean build(
|
|||
MavenProject project = new MavenProject();
|
||||
project.setFile(pomFile);
|
||||
|
||||
project.setRootDirectory(rootLocator.findRoot(pomFile.getParentFile().toPath()));
|
||||
|
||||
ModelBuildingRequest request = getModelBuildingRequest(config)
|
||||
.setPomFile(pomFile)
|
||||
.setTwoPhaseBuilding(true)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -64,6 +65,7 @@
|
|||
import org.apache.maven.model.Resource;
|
||||
import org.apache.maven.model.Scm;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
|
||||
import org.apache.maven.project.artifact.MavenMetadataSource;
|
||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||
|
@ -105,6 +107,8 @@ public class MavenProject implements Cloneable {
|
|||
|
||||
private File basedir;
|
||||
|
||||
private Path rootDirectory;
|
||||
|
||||
private Set<Artifact> resolvedArtifacts;
|
||||
|
||||
private ArtifactFilter artifactFilter;
|
||||
|
@ -1679,4 +1683,20 @@ public ProjectBuildingRequest getProjectBuildingRequest() {
|
|||
public void setProjectBuildingRequest(ProjectBuildingRequest projectBuildingRequest) {
|
||||
this.projectBuilderConfiguration = projectBuildingRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.0.0
|
||||
* @return the rootDirectory for this project
|
||||
* @throws IllegalStateException if the rootDirectory cannot be found
|
||||
*/
|
||||
public Path getRootDirectory() {
|
||||
if (rootDirectory == null) {
|
||||
throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
|
||||
}
|
||||
return rootDirectory;
|
||||
}
|
||||
|
||||
public void setRootDirectory(Path rootDirectory) {
|
||||
this.rootDirectory = rootDirectory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.internal.impl;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.maven.execution.DefaultMavenExecutionRequest;
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
|
||||
import org.eclipse.aether.RepositorySystemSession;
|
||||
import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class DefaultSessionTest {
|
||||
|
||||
@Test
|
||||
void testRootDirectoryWithNull() {
|
||||
RepositorySystemSession rss = MavenRepositorySystemUtils.newSession();
|
||||
DefaultMavenExecutionRequest mer = new DefaultMavenExecutionRequest();
|
||||
MavenSession ms = new MavenSession(null, rss, mer, null);
|
||||
DefaultSession session =
|
||||
new DefaultSession(ms, new DefaultRepositorySystem(), Collections.emptyList(), null, null, null);
|
||||
|
||||
assertEquals(
|
||||
RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE,
|
||||
assertThrows(IllegalStateException.class, session::getRootDirectory)
|
||||
.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectory() {
|
||||
RepositorySystemSession rss = MavenRepositorySystemUtils.newSession();
|
||||
DefaultMavenExecutionRequest mer = new DefaultMavenExecutionRequest();
|
||||
MavenSession ms = new MavenSession(null, rss, mer, null);
|
||||
ms.getRequest().setRootDirectory(Paths.get("myRootDirectory"));
|
||||
DefaultSession session =
|
||||
new DefaultSession(ms, new DefaultRepositorySystem(), Collections.emptyList(), null, null, null);
|
||||
|
||||
assertEquals(Paths.get("myRootDirectory"), session.getRootDirectory());
|
||||
}
|
||||
}
|
|
@ -21,6 +21,9 @@
|
|||
import javax.inject.Inject;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -38,6 +41,7 @@
|
|||
import org.apache.maven.model.Build;
|
||||
import org.apache.maven.model.Dependency;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.plugin.descriptor.MojoDescriptor;
|
||||
import org.apache.maven.plugin.descriptor.PluginDescriptor;
|
||||
import org.apache.maven.project.DuplicateProjectException;
|
||||
|
@ -51,8 +55,11 @@
|
|||
|
||||
import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -64,6 +71,8 @@ class PluginParameterExpressionEvaluatorTest extends AbstractCoreMavenComponentT
|
|||
@Inject
|
||||
private RepositorySystem factory;
|
||||
|
||||
private Path rootDirectory;
|
||||
|
||||
@Test
|
||||
void testPluginDescriptorExpressionReference() throws Exception {
|
||||
MojoExecution exec = newMojoExecution();
|
||||
|
@ -357,6 +366,28 @@ void testShouldExtractPluginArtifacts() throws Exception {
|
|||
assertEquals("testGroup", result.getGroupId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectoryNotPrefixed() throws Exception {
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
|
||||
assertNull(ee.evaluate("${rootDirectory}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectoryWithNull() throws Exception {
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
|
||||
Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
|
||||
e = assertInstanceOf(InvocationTargetException.class, e.getCause());
|
||||
e = assertInstanceOf(IllegalStateException.class, e.getCause());
|
||||
assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectory() throws Exception {
|
||||
this.rootDirectory = Paths.get("myRootDirectory");
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
|
||||
assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
|
||||
}
|
||||
|
||||
private MavenProject createDefaultProject() {
|
||||
return new MavenProject(new Model());
|
||||
}
|
||||
|
@ -368,6 +399,7 @@ private ExpressionEvaluator createExpressionEvaluator(
|
|||
MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
|
||||
MavenSession session = createSession(container, repo, executionProperties);
|
||||
session.setCurrentProject(project);
|
||||
session.getRequest().setRootDirectory(rootDirectory);
|
||||
|
||||
MojoDescriptor mojo = new MojoDescriptor();
|
||||
mojo.setPluginDescriptor(pluginDescriptor);
|
||||
|
|
|
@ -0,0 +1,468 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.plugin;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.maven.AbstractCoreMavenComponentTestCase;
|
||||
import org.apache.maven.api.Session;
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.artifact.ArtifactUtils;
|
||||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.execution.DefaultMavenExecutionRequest;
|
||||
import org.apache.maven.execution.DefaultMavenExecutionResult;
|
||||
import org.apache.maven.execution.MavenExecutionRequest;
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.apache.maven.internal.impl.DefaultProject;
|
||||
import org.apache.maven.internal.impl.DefaultSession;
|
||||
import org.apache.maven.model.Build;
|
||||
import org.apache.maven.model.Dependency;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.plugin.descriptor.MojoDescriptor;
|
||||
import org.apache.maven.plugin.descriptor.PluginDescriptor;
|
||||
import org.apache.maven.project.DuplicateProjectException;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.repository.RepositorySystem;
|
||||
import org.codehaus.plexus.MutablePlexusContainer;
|
||||
import org.codehaus.plexus.PlexusContainer;
|
||||
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
|
||||
import org.codehaus.plexus.util.dag.CycleDetectedException;
|
||||
import org.eclipse.aether.DefaultRepositorySystemSession;
|
||||
import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
|
||||
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
|
||||
import org.eclipse.aether.repository.LocalRepository;
|
||||
import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Jason van Zyl
|
||||
*/
|
||||
public class PluginParameterExpressionEvaluatorV4Test extends AbstractCoreMavenComponentTestCase {
|
||||
private static final String FS = File.separator;
|
||||
|
||||
@Inject
|
||||
private RepositorySystem factory;
|
||||
|
||||
private Path rootDirectory;
|
||||
|
||||
@Test
|
||||
public void testPluginDescriptorExpressionReference() throws Exception {
|
||||
MojoExecution exec = newMojoExecution();
|
||||
|
||||
Session session = newSession();
|
||||
|
||||
Object result = new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin}");
|
||||
|
||||
System.out.println("Result: " + result);
|
||||
|
||||
assertSame(
|
||||
exec.getMojoDescriptor().getPluginDescriptor(),
|
||||
result,
|
||||
"${plugin} expression does not return plugin descriptor.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginArtifactsExpressionReference() throws Exception {
|
||||
MojoExecution exec = newMojoExecution();
|
||||
|
||||
Artifact depArtifact = createArtifact("group", "artifact", "1");
|
||||
|
||||
List<Artifact> deps = new ArrayList<>();
|
||||
deps.add(depArtifact);
|
||||
|
||||
exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
|
||||
|
||||
Session session = newSession();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Artifact> depResults = (List<Artifact>)
|
||||
new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin.artifacts}");
|
||||
|
||||
System.out.println("Result: " + depResults);
|
||||
|
||||
assertNotNull(depResults);
|
||||
assertEquals(1, depResults.size());
|
||||
assertSame(depArtifact, depResults.get(0), "dependency artifact is wrong.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginArtifactMapExpressionReference() throws Exception {
|
||||
MojoExecution exec = newMojoExecution();
|
||||
|
||||
Artifact depArtifact = createArtifact("group", "artifact", "1");
|
||||
|
||||
List<Artifact> deps = new ArrayList<>();
|
||||
deps.add(depArtifact);
|
||||
|
||||
exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
|
||||
|
||||
Session session = newSession();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Artifact> depResults = (Map<String, Artifact>)
|
||||
new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin.artifactMap}");
|
||||
|
||||
System.out.println("Result: " + depResults);
|
||||
|
||||
assertNotNull(depResults);
|
||||
assertEquals(1, depResults.size());
|
||||
assertSame(
|
||||
depArtifact,
|
||||
depResults.get(ArtifactUtils.versionlessKey(depArtifact)),
|
||||
"dependency artifact is wrong.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPluginArtifactIdExpressionReference() throws Exception {
|
||||
MojoExecution exec = newMojoExecution();
|
||||
|
||||
Session session = newSession();
|
||||
|
||||
Object result = new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin.artifactId}");
|
||||
|
||||
System.out.println("Result: " + result);
|
||||
|
||||
assertSame(
|
||||
exec.getMojoDescriptor().getPluginDescriptor().getArtifactId(),
|
||||
result,
|
||||
"${plugin.artifactId} expression does not return plugin descriptor's artifactId.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueExtractionWithAPomValueContainingAPath() throws Exception {
|
||||
String expected = getTestFile("target/test-classes/target/classes").getCanonicalPath();
|
||||
|
||||
Build build = new Build();
|
||||
build.setDirectory(expected.substring(0, expected.length() - "/classes".length()));
|
||||
|
||||
Model model = new Model();
|
||||
model.setBuild(build);
|
||||
|
||||
MavenProject project = new MavenProject(model);
|
||||
project.setFile(new File("pom.xml").getCanonicalFile());
|
||||
|
||||
ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(project, null, new Properties());
|
||||
|
||||
Object value = expressionEvaluator.evaluate("${project.build.directory}/classes");
|
||||
String actual = new File(value.toString()).getCanonicalPath();
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscapedVariablePassthrough() throws Exception {
|
||||
String var = "${var}";
|
||||
|
||||
Model model = new Model();
|
||||
model.setVersion("1");
|
||||
|
||||
MavenProject project = new MavenProject(model);
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
|
||||
|
||||
Object value = ee.evaluate("$" + var);
|
||||
|
||||
assertEquals(var, value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscapedVariablePassthroughInLargerExpression() throws Exception {
|
||||
String var = "${var}";
|
||||
String key = var + " with version: ${project.version}";
|
||||
|
||||
Model model = new Model();
|
||||
model.setVersion("1");
|
||||
|
||||
MavenProject project = new MavenProject(model);
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
|
||||
|
||||
Object value = ee.evaluate("$" + key);
|
||||
|
||||
assertEquals("${var} with version: 1", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleSubExpressionsInLargerExpression() throws Exception {
|
||||
String key = "${project.artifactId} with version: ${project.version}";
|
||||
|
||||
Model model = new Model();
|
||||
model.setArtifactId("test");
|
||||
model.setVersion("1");
|
||||
|
||||
MavenProject project = new MavenProject(model);
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
|
||||
|
||||
Object value = ee.evaluate(key);
|
||||
|
||||
assertEquals("test with version: 1", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingPOMPropertyRefInLargerExpression() throws Exception {
|
||||
String expr = "/path/to/someproject-${baseVersion}";
|
||||
|
||||
MavenProject project = new MavenProject(new Model());
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
|
||||
|
||||
Object value = ee.evaluate(expr);
|
||||
|
||||
assertEquals(expr, value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPOMPropertyExtractionWithMissingProject_WithDotNotation() throws Exception {
|
||||
String key = "m2.name";
|
||||
String checkValue = "value";
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(key, checkValue);
|
||||
|
||||
Model model = new Model();
|
||||
model.setProperties(properties);
|
||||
|
||||
MavenProject project = new MavenProject(model);
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
|
||||
|
||||
Object value = ee.evaluate("${" + key + "}");
|
||||
|
||||
assertEquals(checkValue, value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasedirExtractionWithMissingProject() throws Exception {
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(null, null, new Properties());
|
||||
|
||||
Object value = ee.evaluate("${basedir}");
|
||||
|
||||
assertEquals(System.getProperty("user.dir"), value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueExtractionFromSystemPropertiesWithMissingProject() throws Exception {
|
||||
String sysprop = "PPEET_sysprop1";
|
||||
|
||||
Properties executionProperties = new Properties();
|
||||
|
||||
if (executionProperties.getProperty(sysprop) == null) {
|
||||
executionProperties.setProperty(sysprop, "value");
|
||||
}
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(null, null, executionProperties);
|
||||
|
||||
Object value = ee.evaluate("${" + sysprop + "}");
|
||||
|
||||
assertEquals("value", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation() throws Exception {
|
||||
String sysprop = "PPEET.sysprop2";
|
||||
|
||||
Properties executionProperties = new Properties();
|
||||
|
||||
if (executionProperties.getProperty(sysprop) == null) {
|
||||
executionProperties.setProperty(sysprop, "value");
|
||||
}
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(null, null, executionProperties);
|
||||
|
||||
Object value = ee.evaluate("${" + sysprop + "}");
|
||||
|
||||
assertEquals("value", value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static MavenSession createSession(PlexusContainer container, ArtifactRepository repo, Properties properties)
|
||||
throws CycleDetectedException, DuplicateProjectException, NoLocalRepositoryManagerException {
|
||||
MavenExecutionRequest request = new DefaultMavenExecutionRequest()
|
||||
.setSystemProperties(properties)
|
||||
.setGoals(Collections.<String>emptyList())
|
||||
.setBaseDirectory(new File(""))
|
||||
.setLocalRepository(repo);
|
||||
|
||||
DefaultRepositorySystemSession repositorySession = new DefaultRepositorySystemSession();
|
||||
repositorySession.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory()
|
||||
.newInstance(repositorySession, new LocalRepository(repo.getUrl())));
|
||||
MavenSession session =
|
||||
new MavenSession(container, repositorySession, request, new DefaultMavenExecutionResult());
|
||||
session.setProjects(Collections.<MavenProject>emptyList());
|
||||
return session;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRepositoryExtraction() throws Exception {
|
||||
ExpressionEvaluator expressionEvaluator =
|
||||
createExpressionEvaluator(createDefaultProject(), null, new Properties());
|
||||
Object value = expressionEvaluator.evaluate("${localRepository}");
|
||||
|
||||
assertEquals("local", ((org.apache.maven.api.LocalRepository) value).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoExpressions() throws Exception {
|
||||
Build build = new Build();
|
||||
build.setDirectory("expected-directory");
|
||||
build.setFinalName("expected-finalName");
|
||||
|
||||
Model model = new Model();
|
||||
model.setBuild(build);
|
||||
|
||||
ExpressionEvaluator expressionEvaluator =
|
||||
createExpressionEvaluator(new MavenProject(model), null, new Properties());
|
||||
|
||||
Object value = expressionEvaluator.evaluate("${project.build.directory}" + FS + "${project.build.finalName}");
|
||||
|
||||
assertEquals("expected-directory" + File.separatorChar + "expected-finalName", value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldExtractPluginArtifacts() throws Exception {
|
||||
PluginDescriptor pd = new PluginDescriptor();
|
||||
|
||||
Artifact artifact = createArtifact("testGroup", "testArtifact", "1.0");
|
||||
|
||||
pd.setArtifacts(Collections.singletonList(artifact));
|
||||
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), pd, new Properties());
|
||||
|
||||
Object value = ee.evaluate("${plugin.artifacts}");
|
||||
|
||||
assertTrue(value instanceof List);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Artifact> artifacts = (List<Artifact>) value;
|
||||
|
||||
assertEquals(1, artifacts.size());
|
||||
|
||||
Artifact result = artifacts.get(0);
|
||||
|
||||
assertEquals("testGroup", result.getGroupId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectoryNotPrefixed() throws Exception {
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
|
||||
assertNull(ee.evaluate("${rootDirectory}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectoryWithNull() throws Exception {
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
|
||||
Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
|
||||
e = assertInstanceOf(InvocationTargetException.class, e.getCause());
|
||||
e = assertInstanceOf(IllegalStateException.class, e.getCause());
|
||||
assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectory() throws Exception {
|
||||
this.rootDirectory = Paths.get("myRootDirectory");
|
||||
ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
|
||||
assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
|
||||
}
|
||||
|
||||
private MavenProject createDefaultProject() {
|
||||
return new MavenProject(new Model());
|
||||
}
|
||||
|
||||
private ExpressionEvaluator createExpressionEvaluator(
|
||||
MavenProject project, PluginDescriptor pluginDescriptor, Properties executionProperties) throws Exception {
|
||||
ArtifactRepository repo = factory.createDefaultLocalRepository();
|
||||
|
||||
MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
|
||||
MavenSession mavenSession = createSession(container, repo, executionProperties);
|
||||
mavenSession.setCurrentProject(project);
|
||||
mavenSession.getRequest().setRootDirectory(rootDirectory);
|
||||
|
||||
DefaultSession session =
|
||||
new DefaultSession(mavenSession, new DefaultRepositorySystem(), null, null, null, null);
|
||||
|
||||
MojoDescriptor mojo = new MojoDescriptor();
|
||||
mojo.setPluginDescriptor(pluginDescriptor);
|
||||
mojo.setGoal("goal");
|
||||
|
||||
MojoExecution mojoExecution = new MojoExecution(mojo);
|
||||
|
||||
return new PluginParameterExpressionEvaluatorV4(
|
||||
session, project != null ? new DefaultProject(session, project) : null, mojoExecution);
|
||||
}
|
||||
|
||||
protected Artifact createArtifact(String groupId, String artifactId, String version) throws Exception {
|
||||
Dependency dependency = new Dependency();
|
||||
dependency.setGroupId(groupId);
|
||||
dependency.setArtifactId(artifactId);
|
||||
dependency.setVersion(version);
|
||||
dependency.setType("jar");
|
||||
dependency.setScope("compile");
|
||||
|
||||
return factory.createDependencyArtifact(dependency);
|
||||
}
|
||||
|
||||
private MojoExecution newMojoExecution() {
|
||||
PluginDescriptor pd = new PluginDescriptor();
|
||||
pd.setArtifactId("my-plugin");
|
||||
pd.setGroupId("org.myco.plugins");
|
||||
pd.setVersion("1");
|
||||
|
||||
MojoDescriptor md = new MojoDescriptor();
|
||||
md.setPluginDescriptor(pd);
|
||||
|
||||
pd.addComponentDescriptor(md);
|
||||
|
||||
return new MojoExecution(md);
|
||||
}
|
||||
|
||||
private DefaultSession newSession() throws Exception {
|
||||
return new DefaultSession(newMavenSession(), new DefaultRepositorySystem(), null, null, null, null);
|
||||
}
|
||||
|
||||
private MavenSession newMavenSession() throws Exception {
|
||||
return createMavenSession(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProjectsDirectory() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -135,6 +135,13 @@ static Properties getBuildProperties() {
|
|||
}
|
||||
|
||||
public static void showError(Logger logger, String message, Throwable e, boolean showStackTrace) {
|
||||
if (logger == null) {
|
||||
System.err.println(message);
|
||||
if (showStackTrace && e != null) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (showStackTrace) {
|
||||
logger.error(message, e);
|
||||
} else {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.maven.cli;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
|
@ -40,6 +41,10 @@ public class CliRequest {
|
|||
|
||||
File multiModuleProjectDirectory;
|
||||
|
||||
Path rootDirectory;
|
||||
|
||||
Path topDirectory;
|
||||
|
||||
boolean verbose;
|
||||
|
||||
boolean quiet;
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
import java.io.PrintStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -37,6 +39,7 @@
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -87,6 +90,7 @@
|
|||
import org.apache.maven.logwrapper.LogLevelRecorder;
|
||||
import org.apache.maven.logwrapper.MavenSlf4jWrapperFactory;
|
||||
import org.apache.maven.model.building.ModelProcessor;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.properties.internal.EnvironmentUtils;
|
||||
import org.apache.maven.properties.internal.SystemProperties;
|
||||
|
@ -320,6 +324,54 @@ void initialize(CliRequest cliRequest) throws ExitException {
|
|||
}
|
||||
}
|
||||
|
||||
// We need to locate the top level project which may be pointed at using
|
||||
// the -f/--file option. However, the command line isn't parsed yet, so
|
||||
// we need to iterate through the args to find it and act upon it.
|
||||
Path topDirectory = Paths.get(cliRequest.workingDirectory);
|
||||
boolean isAltFile = false;
|
||||
for (String arg : cliRequest.args) {
|
||||
if (isAltFile) {
|
||||
// this is the argument following -f/--file
|
||||
Path path = Paths.get(arg);
|
||||
if (Files.isDirectory(path)) {
|
||||
topDirectory = path;
|
||||
} else if (Files.isRegularFile(topDirectory)) {
|
||||
topDirectory = path.getParent();
|
||||
if (!Files.isDirectory(topDirectory)) {
|
||||
System.err.println("Directory " + topDirectory
|
||||
+ " extracted from the -f/--file command-line argument " + arg + " does not exist");
|
||||
throw new ExitException(1);
|
||||
}
|
||||
} else {
|
||||
System.err.println(
|
||||
"POM file " + arg + " specified with the -f/--file command line argument does not exist");
|
||||
throw new ExitException(1);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// Check if this is the -f/--file option
|
||||
isAltFile = arg.equals(String.valueOf(CLIManager.ALTERNATE_POM_FILE)) || arg.equals("file");
|
||||
}
|
||||
}
|
||||
try {
|
||||
topDirectory = topDirectory.toAbsolutePath().toRealPath();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error computing real path from " + topDirectory);
|
||||
throw new ExitException(1);
|
||||
}
|
||||
cliRequest.topDirectory = topDirectory;
|
||||
// We're very early in the process and we don't have the container set up yet,
|
||||
// so we rely on the JDK services to eventually lookup a custom RootLocator.
|
||||
// This is used to compute {@code session.rootDirectory} but all {@code project.rootDirectory}
|
||||
// properties will be compute through the RootLocator found in the container.
|
||||
RootLocator rootLocator =
|
||||
ServiceLoader.load(RootLocator.class).iterator().next();
|
||||
Path rootDirectory = rootLocator.findRoot(topDirectory);
|
||||
if (rootDirectory == null) {
|
||||
System.err.println(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
|
||||
}
|
||||
cliRequest.rootDirectory = rootDirectory;
|
||||
|
||||
//
|
||||
// Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative
|
||||
// Windows paths.
|
||||
|
@ -1185,6 +1237,8 @@ private MavenExecutionRequest populateRequest(CliRequest cliRequest, MavenExecut
|
|||
request.setSystemProperties(cliRequest.systemProperties);
|
||||
request.setUserProperties(cliRequest.userProperties);
|
||||
request.setMultiModuleProjectDirectory(cliRequest.multiModuleProjectDirectory);
|
||||
request.setRootDirectory(cliRequest.rootDirectory);
|
||||
request.setTopDirectory(cliRequest.topDirectory);
|
||||
request.setPom(determinePom(commandLine, workingDirectory, baseDirectory));
|
||||
request.setTransferListener(determineTransferListener(quiet, verbose, commandLine, request));
|
||||
request.setExecutionListener(determineExecutionListener());
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -36,6 +38,7 @@
|
|||
import org.apache.maven.execution.MavenExecutionRequest;
|
||||
import org.apache.maven.execution.ProfileActivation;
|
||||
import org.apache.maven.execution.ProjectActivation;
|
||||
import org.apache.maven.model.root.DefaultRootLocator;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.shared.utils.logging.MessageUtils;
|
||||
import org.apache.maven.toolchain.building.ToolchainsBuildingRequest;
|
||||
|
@ -543,6 +546,12 @@ void populatePropertiesOverwrite() throws Exception {
|
|||
assertThat(request.getUserProperties().getProperty("x"), is("false"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findRootProjectWithAttribute() {
|
||||
Path test = Paths.get("src/test/projects/root-attribute");
|
||||
assertEquals(test, new DefaultRootLocator().findRoot(test.resolve("child")));
|
||||
}
|
||||
|
||||
private MavenProject createMavenProject(String groupId, String artifactId) {
|
||||
MavenProject project = new MavenProject();
|
||||
project.setGroupId(groupId);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
|
||||
</project>
|
|
@ -0,0 +1,3 @@
|
|||
<project root="true" xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
|
||||
</project>
|
|
@ -64,6 +64,8 @@
|
|||
import org.apache.maven.model.profile.activation.OperatingSystemProfileActivator;
|
||||
import org.apache.maven.model.profile.activation.ProfileActivator;
|
||||
import org.apache.maven.model.profile.activation.PropertyProfileActivator;
|
||||
import org.apache.maven.model.root.DefaultRootLocator;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.model.superpom.DefaultSuperPomProvider;
|
||||
import org.apache.maven.model.superpom.SuperPomProvider;
|
||||
import org.apache.maven.model.validation.DefaultModelValidator;
|
||||
|
@ -100,6 +102,8 @@ public class DefaultModelBuilderFactory {
|
|||
private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
|
||||
private ModelVersionProcessor versionProcessor;
|
||||
|
||||
private RootLocator rootLocator;
|
||||
|
||||
public DefaultModelBuilderFactory setModelProcessor(ModelProcessor modelProcessor) {
|
||||
this.modelProcessor = modelProcessor;
|
||||
return this;
|
||||
|
@ -201,6 +205,11 @@ public DefaultModelBuilderFactory setVersionProcessor(ModelVersionProcessor vers
|
|||
return this;
|
||||
}
|
||||
|
||||
public DefaultModelBuilderFactory setRootLocator(RootLocator rootLocator) {
|
||||
this.rootLocator = rootLocator;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected ModelProcessor newModelProcessor() {
|
||||
return new DefaultModelProcessor(newModelLocator(), newModelReader());
|
||||
}
|
||||
|
@ -227,7 +236,7 @@ protected ProfileActivator[] newProfileActivators() {
|
|||
}
|
||||
|
||||
protected ProfileActivationFilePathInterpolator newProfileActivationFilePathInterpolator() {
|
||||
return new ProfileActivationFilePathInterpolator(newPathTranslator());
|
||||
return new ProfileActivationFilePathInterpolator(newPathTranslator(), newRootLocator());
|
||||
}
|
||||
|
||||
protected UrlNormalizer newUrlNormalizer() {
|
||||
|
@ -238,10 +247,15 @@ protected PathTranslator newPathTranslator() {
|
|||
return new DefaultPathTranslator();
|
||||
}
|
||||
|
||||
protected RootLocator newRootLocator() {
|
||||
return new DefaultRootLocator();
|
||||
}
|
||||
|
||||
protected ModelInterpolator newModelInterpolator() {
|
||||
UrlNormalizer normalizer = newUrlNormalizer();
|
||||
PathTranslator pathTranslator = newPathTranslator();
|
||||
return new StringVisitorModelInterpolator(pathTranslator, normalizer);
|
||||
RootLocator rootLocator = newRootLocator();
|
||||
return new StringVisitorModelInterpolator(pathTranslator, normalizer, rootLocator);
|
||||
}
|
||||
|
||||
protected ModelVersionProcessor newModelVersionPropertiesProcessor() {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
import javax.inject.Inject;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -33,6 +34,7 @@
|
|||
import org.apache.maven.model.building.ModelProblemCollector;
|
||||
import org.apache.maven.model.path.PathTranslator;
|
||||
import org.apache.maven.model.path.UrlNormalizer;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.codehaus.plexus.interpolation.AbstractValueSource;
|
||||
import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
|
||||
import org.codehaus.plexus.interpolation.MapBasedValueSource;
|
||||
|
@ -74,10 +76,14 @@ public abstract class AbstractStringBasedModelInterpolator implements ModelInter
|
|||
private final PathTranslator pathTranslator;
|
||||
private final UrlNormalizer urlNormalizer;
|
||||
|
||||
private final RootLocator rootLocator;
|
||||
|
||||
@Inject
|
||||
public AbstractStringBasedModelInterpolator(PathTranslator pathTranslator, UrlNormalizer urlNormalizer) {
|
||||
public AbstractStringBasedModelInterpolator(
|
||||
PathTranslator pathTranslator, UrlNormalizer urlNormalizer, RootLocator rootLocator) {
|
||||
this.pathTranslator = pathTranslator;
|
||||
this.urlNormalizer = urlNormalizer;
|
||||
this.rootLocator = rootLocator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -133,6 +139,20 @@ public Object getValue(String expression) {
|
|||
valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), modelProperties));
|
||||
}
|
||||
|
||||
valueSources.add(new PrefixedValueSourceWrapper(
|
||||
new AbstractValueSource(false) {
|
||||
@Override
|
||||
public Object getValue(String expression) {
|
||||
if ("rootDirectory".equals(expression)) {
|
||||
Path base = projectDir != null ? projectDir.toPath() : null;
|
||||
Path root = rootLocator.findMandatoryRoot(base);
|
||||
return root.toFile().getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
PROJECT_PREFIXES));
|
||||
|
||||
valueSources.add(projectPrefixValueSource);
|
||||
|
||||
valueSources.add(new MapBasedValueSource(config.getUserProperties()));
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
import org.apache.maven.model.building.ModelProblemCollectorRequest;
|
||||
import org.apache.maven.model.path.PathTranslator;
|
||||
import org.apache.maven.model.path.UrlNormalizer;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.apache.maven.model.v4.MavenTransformer;
|
||||
import org.codehaus.plexus.interpolation.InterpolationException;
|
||||
import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
|
||||
|
@ -51,8 +52,9 @@
|
|||
@Singleton
|
||||
public class StringVisitorModelInterpolator extends AbstractStringBasedModelInterpolator {
|
||||
@Inject
|
||||
public StringVisitorModelInterpolator(PathTranslator pathTranslator, UrlNormalizer urlNormalizer) {
|
||||
super(pathTranslator, urlNormalizer);
|
||||
public StringVisitorModelInterpolator(
|
||||
PathTranslator pathTranslator, UrlNormalizer urlNormalizer, RootLocator rootLocator) {
|
||||
super(pathTranslator, urlNormalizer, rootLocator);
|
||||
}
|
||||
|
||||
interface InnerInterpolator {
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
import javax.inject.Singleton;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.apache.maven.api.model.ActivationFile;
|
||||
import org.apache.maven.model.profile.ProfileActivationContext;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.codehaus.plexus.interpolation.AbstractValueSource;
|
||||
import org.codehaus.plexus.interpolation.InterpolationException;
|
||||
import org.codehaus.plexus.interpolation.MapBasedValueSource;
|
||||
|
@ -42,9 +44,12 @@ public class ProfileActivationFilePathInterpolator {
|
|||
|
||||
private final PathTranslator pathTranslator;
|
||||
|
||||
private final RootLocator rootLocator;
|
||||
|
||||
@Inject
|
||||
public ProfileActivationFilePathInterpolator(PathTranslator pathTranslator) {
|
||||
public ProfileActivationFilePathInterpolator(PathTranslator pathTranslator, RootLocator rootLocator) {
|
||||
this.pathTranslator = pathTranslator;
|
||||
this.rootLocator = rootLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,6 +84,18 @@ public Object getValue(String expression) {
|
|||
return null;
|
||||
}
|
||||
|
||||
interpolator.addValueSource(new AbstractValueSource(false) {
|
||||
@Override
|
||||
public Object getValue(String expression) {
|
||||
if ("rootDirectory".equals(expression)) {
|
||||
Path base = basedir != null ? basedir.toPath() : null;
|
||||
Path root = rootLocator.findMandatoryRoot(base);
|
||||
return root.toFile().getAbsolutePath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
interpolator.addValueSource(new MapBasedValueSource(context.getProjectProperties()));
|
||||
|
||||
interpolator.addValueSource(new MapBasedValueSource(context.getUserProperties()));
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.model.root;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.codehaus.plexus.util.xml.pull.MXParser;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
|
||||
@Named
|
||||
public class DefaultRootLocator implements RootLocator {
|
||||
|
||||
public boolean isRootDirectory(Path dir) {
|
||||
if (Files.isDirectory(dir.resolve(".mvn"))) {
|
||||
return true;
|
||||
}
|
||||
// we're too early to use the modelProcessor ...
|
||||
Path pom = dir.resolve("pom.xml");
|
||||
try (InputStream is = Files.newInputStream(pom)) {
|
||||
MXParser parser = new MXParser();
|
||||
parser.setInput(is, null);
|
||||
if (parser.nextTag() == MXParser.START_TAG && parser.getName().equals("project")) {
|
||||
for (int i = 0; i < parser.getAttributeCount(); i++) {
|
||||
if ("root".equals(parser.getAttributeName(i))) {
|
||||
return Boolean.parseBoolean(parser.getAttributeValue(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException | XmlPullParserException e) {
|
||||
// The root locator can be used very early during the setup of Maven,
|
||||
// even before the arguments from the command line are parsed. Any exception
|
||||
// that would happen here should cause the build to fail at a later stage
|
||||
// (when actually parsing the POM) and will lead to a better exception being
|
||||
// displayed to the user, so just bail out and return false.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.model.root;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.apache.maven.api.annotations.Nonnull;
|
||||
import org.apache.maven.api.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Interface used to locate the root directory for a given project.
|
||||
*
|
||||
* The root locator is usually looked up from the plexus container.
|
||||
* One notable exception is the computation of the early {@code session.rootDirectory}
|
||||
* property which happens very early. The implementation used in this case
|
||||
* will be discovered using the JDK service mechanism.
|
||||
*
|
||||
* The default implementation will look for a {@code .mvn} child directory
|
||||
* or a {@code pom.xml} containing the {@code root="true"} attribute.
|
||||
*
|
||||
* @see DefaultRootLocator
|
||||
*/
|
||||
public interface RootLocator {
|
||||
|
||||
String UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE = "Unable to find the root directory. "
|
||||
+ "Create a .mvn directory in the root directory or add the root=\"true\""
|
||||
+ " attribute on the root project's model to identify it.";
|
||||
|
||||
@Nonnull
|
||||
default Path findMandatoryRoot(Path basedir) {
|
||||
Path rootDirectory = findRoot(basedir);
|
||||
if (rootDirectory == null) {
|
||||
throw new IllegalStateException(getNoRootMessage());
|
||||
}
|
||||
return rootDirectory;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
default Path findRoot(Path basedir) {
|
||||
Path rootDirectory = basedir;
|
||||
while (rootDirectory != null && !isRootDirectory(rootDirectory)) {
|
||||
rootDirectory = rootDirectory.getParent();
|
||||
}
|
||||
return rootDirectory;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
default String getNoRootMessage() {
|
||||
return UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE;
|
||||
}
|
||||
|
||||
boolean isRootDirectory(Path dir);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.apache.maven.model.root.DefaultRootLocator
|
|
@ -41,7 +41,7 @@ Maven Model Builder
|
|||
|
||||
** profile activation: see {{{./apidocs/org/apache/maven/model/profile/activation/package-summary.html}available activators}}.
|
||||
Notice that model interpolation hasn't happened yet, then interpolation for file-based activation is limited to
|
||||
<<<$\{basedir}>>> (since Maven 3), system properties and user properties
|
||||
<<<$\{basedir}>>> (since Maven 3), <<<$\{rootDirectory}>>> (since Maven 4), system properties and user properties
|
||||
|
||||
** file model validation: <<<ModelValidator>>> ({{{./apidocs/org/apache/maven/model/validation/ModelValidator.html}javadoc}}),
|
||||
with its <<<DefaultModelValidator>>> implementation
|
||||
|
@ -51,7 +51,7 @@ Maven Model Builder
|
|||
|
||||
* phase 2, with optional plugin processing
|
||||
|
||||
** Build up a raw model by re-reading the file and enrich it based on information available in the reactor. Some features:
|
||||
** Build up a raw model by re-reading the file and enriching it based on information available in the reactor. Some features:
|
||||
|
||||
*** Resolve version of versionless parents based on relativePath (including ci-friendly versions)
|
||||
|
||||
|
@ -156,13 +156,13 @@ Maven Model Builder
|
|||
|
||||
* Model Interpolation
|
||||
|
||||
Model Interpolation consists in replacing <<<$\{...\}>>> with calculated value. It is done in <<<StringSearchModelInterpolator>>>
|
||||
({{{./apidocs/org/apache/maven/model/interpolation/StringSearchModelInterpolator.html}javadoc}},
|
||||
{{{./xref/org/apache/maven/model/interpolation/StringSearchModelInterpolator.html}source}}).
|
||||
Model Interpolation consists in replacing <<<$\{...\}>>> with calculated value. It is done in <<<StringVisitorModelInterpolator>>>
|
||||
({{{./apidocs/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.html}javadoc}},
|
||||
{{{./xref/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.html}source}}).
|
||||
|
||||
Notice that model interpolation happens <after> profile activation, then profile activation doesn't benefit from every values:
|
||||
Notice that model interpolation happens <after> profile activation, and that profile activation doesn't benefit from every values:
|
||||
interpolation for file-based activation is limited to <<<$\{basedir}>>> (which was introduced in Maven 3 and is not deprecated
|
||||
in this context), system properties and user properties.
|
||||
in this context) and <<<$\{rootDirectory}>>> (introduced in Maven 4), system properties and user properties.
|
||||
|
||||
Values are evaluated in sequence from different syntaxes:
|
||||
|
||||
|
@ -183,6 +183,8 @@ Maven Model Builder
|
|||
| <<<project.baseUri>>>\
|
||||
<<<pom.baseUri>>> (<deprecated>) | the directory containing the <<<pom.xml>>> file as URI | <<<$\{project.baseUri\}>>> |
|
||||
*----+------+------+
|
||||
| <<<project.rootDirectory>>> | the project's root directory (containing a <<<.mvn>>> directory or with the <<<root="true">>> xml attribute) | <<<$\{project.rootDirectory\}>>> |
|
||||
*----+------+------+
|
||||
| <<<build.timestamp>>>\
|
||||
<<<maven.build.timestamp>>> | the UTC timestamp of build start, in <<<yyyy-MM-dd'T'HH:mm:ss'Z'>>> default format, which can be overridden with <<<maven.build.timestamp.format>>> POM property | <<<$\{maven.build.timestamp\}>>> |
|
||||
*----+------+------+
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
package org.apache.maven.model.interpolation;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
|
@ -41,11 +43,13 @@
|
|||
import org.apache.maven.model.building.DefaultModelBuildingRequest;
|
||||
import org.apache.maven.model.building.ModelBuildingRequest;
|
||||
import org.apache.maven.model.building.SimpleProblemCollector;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -306,9 +310,50 @@ public void testBaseUri() throws Exception {
|
|||
assertEquals("myBaseUri/temp-repo", (out.getRepositories().get(0)).getUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectory() throws Exception {
|
||||
Path rootDirectory = Paths.get("myRootDirectory");
|
||||
|
||||
Model model = Model.newBuilder()
|
||||
.version("3.8.1")
|
||||
.artifactId("foo")
|
||||
.repositories(Collections.singletonList(Repository.newBuilder()
|
||||
.url("file:${project.rootDirectory}/temp-repo")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
ModelInterpolator interpolator = createInterpolator();
|
||||
|
||||
final SimpleProblemCollector collector = new SimpleProblemCollector();
|
||||
Model out = interpolator.interpolateModel(
|
||||
model, rootDirectory.toFile(), createModelBuildingRequest(context), collector);
|
||||
assertProblemFree(collector);
|
||||
|
||||
assertEquals("file:myRootDirectory/temp-repo", (out.getRepositories().get(0)).getUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectoryWithNull() throws Exception {
|
||||
Model model = Model.newBuilder()
|
||||
.version("3.8.1")
|
||||
.artifactId("foo")
|
||||
.repositories(Collections.singletonList(Repository.newBuilder()
|
||||
.url("file:///${project.rootDirectory}/temp-repo")
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
ModelInterpolator interpolator = createInterpolator();
|
||||
|
||||
final SimpleProblemCollector collector = new SimpleProblemCollector();
|
||||
IllegalStateException e = assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> interpolator.interpolateModel(model, null, createModelBuildingRequest(context), collector));
|
||||
|
||||
assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnvars() throws Exception {
|
||||
Properties context = new Properties();
|
||||
context.put("env.HOME", "/path/to/home");
|
||||
|
||||
Map<String, String> modelProperties = new HashMap<>();
|
||||
|
|
|
@ -20,6 +20,6 @@
|
|||
|
||||
public class StringVisitorModelInterpolatorTest extends AbstractModelInterpolatorTest {
|
||||
protected ModelInterpolator createInterpolator() {
|
||||
return new StringVisitorModelInterpolator(null, null);
|
||||
return new StringVisitorModelInterpolator(null, null, bd -> true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,11 +28,13 @@
|
|||
import org.apache.maven.model.path.DefaultPathTranslator;
|
||||
import org.apache.maven.model.path.ProfileActivationFilePathInterpolator;
|
||||
import org.apache.maven.model.profile.DefaultProfileActivationContext;
|
||||
import org.apache.maven.model.root.RootLocator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Tests {@link FileProfileActivator}.
|
||||
|
@ -49,9 +51,10 @@ class FileProfileActivatorTest extends AbstractProfileActivatorTest<FileProfileA
|
|||
@BeforeEach
|
||||
@Override
|
||||
void setUp() throws Exception {
|
||||
activator = new FileProfileActivator(new ProfileActivationFilePathInterpolator(new DefaultPathTranslator()));
|
||||
activator = new FileProfileActivator(
|
||||
new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), bd -> true));
|
||||
|
||||
context.setProjectDirectory(new File(tempDir.toString()));
|
||||
context.setProjectDirectory(tempDir.toFile());
|
||||
|
||||
File file = new File(tempDir.resolve("file.txt").toString());
|
||||
if (!file.createNewFile()) {
|
||||
|
@ -59,6 +62,26 @@ void setUp() throws Exception {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectoryWithNull() {
|
||||
context.setProjectDirectory(null);
|
||||
|
||||
IllegalStateException e = assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> assertActivation(false, newExistsProfile("${rootDirectory}"), context));
|
||||
assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRootDirectory() {
|
||||
assertActivation(false, newExistsProfile("${rootDirectory}/someFile.txt"), context);
|
||||
assertActivation(true, newMissingProfile("${rootDirectory}/someFile.txt"), context);
|
||||
assertActivation(true, newExistsProfile("${rootDirectory}"), context);
|
||||
assertActivation(true, newExistsProfile("${rootDirectory}/" + "file.txt"), context);
|
||||
assertActivation(false, newMissingProfile("${rootDirectory}"), context);
|
||||
assertActivation(false, newMissingProfile("${rootDirectory}/" + "file.txt"), context);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsActiveNoFile() {
|
||||
assertActivation(false, newExistsProfile(null), context);
|
||||
|
|
|
@ -40,6 +40,8 @@ public final XmlPullParser get(XmlPullParser orgParser, Path projectPath) {
|
|||
|
||||
parser = buildPomXMLFilterFactory.get(parser, projectPath);
|
||||
|
||||
// Remove root model attribute
|
||||
parser = new RootXMLFilter(parser);
|
||||
// Strip modules
|
||||
parser = new ModulesXMLFilter(parser);
|
||||
// Adjust relativePath
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.model.transform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.maven.model.transform.pull.BufferingParser;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
|
||||
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
|
||||
|
||||
/**
|
||||
* Remove the root attribute on the model
|
||||
*
|
||||
* @author Guillaume Nodet
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class RootXMLFilter extends BufferingParser {
|
||||
RootXMLFilter(XmlPullParser xmlPullParser) {
|
||||
super(xmlPullParser);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean accept() throws XmlPullParserException, IOException {
|
||||
if (xmlPullParser.getEventType() == XmlPullParser.START_TAG) {
|
||||
if (xmlPullParser.getDepth() == 1 && "project".equals(xmlPullParser.getName())) {
|
||||
Event event = bufferEvent();
|
||||
event.attributes = Stream.of(event.attributes)
|
||||
.filter(a -> !"root".equals(a.name))
|
||||
.toArray(Attribute[]::new);
|
||||
pushEvent(event);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -395,6 +395,16 @@ protected Event bufferEvent() throws XmlPullParserException {
|
|||
event.prefix = pp.getPrefix();
|
||||
event.empty = pp.isEmptyElementTag();
|
||||
event.text = pp.getText();
|
||||
event.attributes = new Attribute[pp.getAttributeCount()];
|
||||
for (int i = 0; i < pp.getAttributeCount(); i++) {
|
||||
Attribute attr = new Attribute();
|
||||
attr.name = pp.getAttributeName(i);
|
||||
attr.namespace = pp.getAttributeNamespace(i);
|
||||
attr.value = pp.getAttributeValue(i);
|
||||
attr.type = pp.getAttributeType(i);
|
||||
attr.isDefault = pp.isAttributeDefault(i);
|
||||
event.attributes[i] = attr;
|
||||
}
|
||||
break;
|
||||
case END_TAG:
|
||||
event.name = pp.getName();
|
||||
|
|
|
@ -207,7 +207,7 @@ public class ${className}
|
|||
#if ( $field.type == "String" )
|
||||
${classLcapName}.${field.name}( interpolatedTrimmed( value, "$fieldTagName" ) );
|
||||
#elseif ( $field.type == "boolean" || $field.type == "Boolean" )
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( value, "$fieldTagName" ), "$fieldTagName", parser, strict, "${field.defaultValue}" ) );
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( value, "$fieldTagName" ), "$fieldTagName", parser, ${field.defaultValue} ) );
|
||||
#else
|
||||
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
|
||||
#end
|
||||
|
|
|
@ -236,7 +236,7 @@ public class ${className}
|
|||
#if ( $field.type == "String" )
|
||||
${classLcapName}.${field.name}( interpolatedTrimmed( value, "$fieldTagName" ) );
|
||||
#elseif ( $field.type == "boolean" || $field.type == "Boolean" )
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( value, "$fieldTagName" ), "$fieldTagName", parser, "${field.defaultValue}" ) );
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( value, "$fieldTagName" ), "$fieldTagName", parser, ${field.defaultValue} ) );
|
||||
#else
|
||||
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
|
||||
#end
|
||||
|
|
|
@ -175,7 +175,7 @@ public class ${className}
|
|||
private boolean getBooleanValue( String s, String attribute, XmlPullParser parser )
|
||||
throws XmlPullParserException
|
||||
{
|
||||
return getBooleanValue( s, attribute, parser, null );
|
||||
return getBooleanValue( s, attribute, parser, false );
|
||||
} //-- boolean getBooleanValue( String, String, XmlPullParser )
|
||||
|
||||
/**
|
||||
|
@ -189,18 +189,14 @@ public class ${className}
|
|||
* any.
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean getBooleanValue( String s, String attribute, XmlPullParser parser, String defaultValue )
|
||||
private boolean getBooleanValue( String s, String attribute, XmlPullParser parser, boolean defaultValue )
|
||||
throws XmlPullParserException
|
||||
{
|
||||
if ( s != null && s.length() != 0 )
|
||||
{
|
||||
return Boolean.valueOf( s ).booleanValue();
|
||||
}
|
||||
if ( defaultValue != null )
|
||||
{
|
||||
return Boolean.valueOf( defaultValue ).booleanValue();
|
||||
}
|
||||
return false;
|
||||
return defaultValue;
|
||||
} //-- boolean getBooleanValue( String, String, XmlPullParser, String )
|
||||
|
||||
/**
|
||||
|
@ -709,7 +705,7 @@ public class ${className}
|
|||
#if ( $field.type == "String" )
|
||||
${classLcapName}.${field.name}( interpolatedTrimmed( value, "$fieldTagName" ) );
|
||||
#elseif ( $field.type == "boolean" || $field.type == "Boolean" )
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( value, "$fieldTagName" ), "$fieldTagName", parser, "${field.defaultValue}" ) );
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( value, "$fieldTagName" ), "$fieldTagName", parser, ${field.defaultValue} ) );
|
||||
#else
|
||||
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
|
||||
#end
|
||||
|
@ -749,7 +745,7 @@ public class ${className}
|
|||
${classLcapName}.${field.name}( interpolatedTrimmed( parser.nextText(), "${fieldTagName}" ) );
|
||||
break;
|
||||
#elseif ( $field.type == "boolean" || $field.type == "Boolean" )
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( parser.nextText(), "${fieldTagName}" ), "${fieldTagName}", parser, "${field.defaultValue}" ) );
|
||||
${classLcapName}.${field.name}( getBooleanValue( interpolatedTrimmed( parser.nextText(), "${fieldTagName}" ), "${fieldTagName}", parser, ${field.defaultValue} ) );
|
||||
break;
|
||||
#elseif ( $field.type == "int" )
|
||||
${classLcapName}.${field.name}( getIntegerValue( interpolatedTrimmed( parser.nextText(), "${fieldTagName}" ), "${fieldTagName}", parser, strict, ${field.defaultValue} ) );
|
||||
|
|
|
@ -210,8 +210,15 @@ public class ${className}
|
|||
#set ( $fieldCapName = $Helper.capitalise( $field.name ) )
|
||||
#if ( $field.type == "String" )
|
||||
writeAttr( "$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer );
|
||||
#elseif ( $field.type == "boolean" )
|
||||
#set ( $def = ${field.defaultValue} )
|
||||
#if ( ${def} == "true" )
|
||||
writeAttr( "$fieldTagName", ${classLcapName}.is${fieldCapName}() ? null : "false", serializer );
|
||||
#else
|
||||
writeAttr( "$fieldTagName", ${classLcapName}.is${fieldCapName}() ? "true" : null, serializer );
|
||||
#end
|
||||
#else
|
||||
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
|
||||
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
|
|
|
@ -192,8 +192,15 @@ public class ${className}
|
|||
#set ( $fieldCapName = $Helper.capitalise( $field.name ) )
|
||||
#if ( $field.type == "String" )
|
||||
writeAttr( "$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer );
|
||||
#elseif ( $field.type == "boolean" )
|
||||
#set ( $def = ${field.defaultValue} )
|
||||
#if ( ${def} == "true" )
|
||||
writeAttr( "$fieldTagName", ${classLcapName}.is${fieldCapName}() ? null : "false", serializer );
|
||||
#else
|
||||
writeAttr( "$fieldTagName", ${classLcapName}.is${fieldCapName}() ? "true" : null, serializer );
|
||||
#end
|
||||
#else
|
||||
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
|
||||
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
|
|
Loading…
Reference in New Issue