Skip to content

Commit

Permalink
[MNG-7959] User controlled relocations (#1339)
Browse files Browse the repository at this point in the history
With some improvements. It accepts user property with CSV entries for relocations.

To toy with it, use `-Dmaven.relocations.entries` user property, for example create `.mvn/maven.config` file with contents:
```
-Dmaven.relocations.entries=entry1,entry2,...
```
It accepts CSV (comma delimited) of entries, while entry form is as:
```
GAV>GAV
```
Where left GAV can contain `*` for any elem (so `*:*:*` would mean ALL, something you don't want). Right GAV is either fully specified, or also can contain `*`, then it behaves as "ordinary relocation": the coordinate is preserved from relocated artifact. Finally, if right hand GAV is absent (line looks like "GAV>"). the left hand matching GAV is banned fully (from resolving).

Note: the ">" means project level, while ">>" means global (whole session level, so even plugins will get relocated artifacts) relocation.

Examples:
```
-Dmaven.relocations.entries=org.foo:*:*>,org.here:*:*>org.there:*:*,javax.inject:javax.inject:1>>jakarta.inject:jakarta.inject:1.0.5
```

Meaning: 3 entries, ban `org.foo` group (exactly, so `org.foo.bar` is allowed), relocate `org.here` to `org.there` and finally **globally relocate** (see ">>") `javax.inject:javax.inject:1` to `jakarta.inject:jakarta.inject:1.0.5`

---

https://issues.apache.org/jira/browse/MNG-7959
  • Loading branch information
cstamas authored Dec 18, 2023
1 parent 6e192fb commit e34afc8
Show file tree
Hide file tree
Showing 6 changed files with 393 additions and 56 deletions.
30 changes: 15 additions & 15 deletions maven-resolver-provider/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ under the License.
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>provided</scope>
</dependency>

<!-- Testing -->
<dependency>
Expand Down Expand Up @@ -110,21 +125,6 @@ under the License.
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.inject</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
import java.util.Properties;
import java.util.Set;

import org.apache.maven.model.DistributionManagement;
import org.apache.maven.model.Model;
import org.apache.maven.model.Relocation;
import org.apache.maven.model.building.ArtifactModelSource;
import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.ModelBuilder;
Expand Down Expand Up @@ -64,23 +62,22 @@
import org.eclipse.aether.resolution.VersionResolutionException;
import org.eclipse.aether.resolution.VersionResult;
import org.eclipse.aether.transfer.ArtifactNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Default artifact descriptor reader.
*/
@Named
@Singleton
public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultArtifactDescriptorReader.class);

private final RemoteRepositoryManager remoteRepositoryManager;
private final VersionResolver versionResolver;
private final VersionRangeResolver versionRangeResolver;
private final ArtifactResolver artifactResolver;
private final RepositoryEventDispatcher repositoryEventDispatcher;
private final ModelBuilder modelBuilder;
private final ModelCacheFactory modelCacheFactory;
private final Map<String, MavenArtifactRelocationSource> artifactRelocationSources;
private final ArtifactDescriptorReaderDelegate delegate;

@Inject
public DefaultArtifactDescriptorReader(
Expand All @@ -90,7 +87,8 @@ public DefaultArtifactDescriptorReader(
ArtifactResolver artifactResolver,
ModelBuilder modelBuilder,
RepositoryEventDispatcher repositoryEventDispatcher,
ModelCacheFactory modelCacheFactory) {
ModelCacheFactory modelCacheFactory,
Map<String, MavenArtifactRelocationSource> artifactRelocationSources) {
this.remoteRepositoryManager =
Objects.requireNonNull(remoteRepositoryManager, "remoteRepositoryManager cannot be null");
this.versionResolver = Objects.requireNonNull(versionResolver, "versionResolver cannot be null");
Expand All @@ -100,6 +98,9 @@ public DefaultArtifactDescriptorReader(
this.repositoryEventDispatcher =
Objects.requireNonNull(repositoryEventDispatcher, "repositoryEventDispatcher cannot be null");
this.modelCacheFactory = Objects.requireNonNull(modelCacheFactory, "modelCacheFactory cannot be null");
this.artifactRelocationSources =
Objects.requireNonNull(artifactRelocationSources, "artifactRelocationSources cannot be null");
this.delegate = new ArtifactDescriptorReaderDelegate();
}

@Override
Expand All @@ -114,7 +115,7 @@ public ArtifactDescriptorResult readArtifactDescriptor(
(ArtifactDescriptorReaderDelegate) config.get(ArtifactDescriptorReaderDelegate.class.getName());

if (delegate == null) {
delegate = new ArtifactDescriptorReaderDelegate();
delegate = this.delegate;
}

delegate.populateResult(session, result, model);
Expand Down Expand Up @@ -236,16 +237,10 @@ private Model loadPom(
throw new ArtifactDescriptorException(result);
}

Relocation relocation = getRelocation(model);

if (relocation != null) {
Artifact relocatedArtifact = getRelocation(session, request, model);
if (relocatedArtifact != null) {
result.addRelocation(a);
a = new RelocatedArtifact(
a,
relocation.getGroupId(),
relocation.getArtifactId(),
relocation.getVersion(),
relocation.getMessage());
a = relocatedArtifact;
result.setArtifact(a);
} else {
return model;
Expand All @@ -264,13 +259,15 @@ private Properties toProperties(Map<String, String> dominant, Map<String, String
return props;
}

private Relocation getRelocation(Model model) {
Relocation relocation = null;
DistributionManagement distMgmt = model.getDistributionManagement();
if (distMgmt != null) {
relocation = distMgmt.getRelocation();
private Artifact getRelocation(RepositorySystemSession session, ArtifactDescriptorRequest request, Model model) {
Artifact result = null;
for (MavenArtifactRelocationSource source : artifactRelocationSources.values()) {
result = source.relocatedTarget(session, request, model);
if (result != null) {
break;
}
}
return relocation;
return result;
}

private void missingDescriptor(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.repository.internal;

import org.apache.maven.model.Model;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.resolution.ArtifactDescriptorRequest;

/**
* Maven relocation source.
*
* @since 4.0.0
*/
public interface MavenArtifactRelocationSource {
/**
* Returns {@link Artifact} instance where to relocate to, or {@code null}.
*
* @param session The session, never {@code null}.
* @param request The artifact descriptor request, never {@code null}.
* @param model The artifact model, never {@code null}.
* @return The {@link Artifact} to relocate to, or {@code null} if no relocation wanted.
*/
Artifact relocatedTarget(RepositorySystemSession session, ArtifactDescriptorRequest request, Model model);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,29 @@ public final class RelocatedArtifact extends AbstractArtifact {

private final String artifactId;

private final String classifier;

private final String extension;

private final String version;

private final String message;

RelocatedArtifact(Artifact artifact, String groupId, String artifactId, String version, String message) {
public RelocatedArtifact(
Artifact artifact,
String groupId,
String artifactId,
String classifier,
String extension,
String version,
String message) {
this.artifact = Objects.requireNonNull(artifact, "artifact cannot be null");
this.groupId = (groupId != null && groupId.length() > 0) ? groupId : null;
this.artifactId = (artifactId != null && artifactId.length() > 0) ? artifactId : null;
this.version = (version != null && version.length() > 0) ? version : null;
this.message = (message != null && message.length() > 0) ? message : null;
this.groupId = (groupId != null && !groupId.isEmpty()) ? groupId : null;
this.artifactId = (artifactId != null && !artifactId.isEmpty()) ? artifactId : null;
this.classifier = (classifier != null && !classifier.isEmpty()) ? classifier : null;
this.extension = (extension != null && !extension.isEmpty()) ? extension : null;
this.version = (version != null && !version.isEmpty()) ? version : null;
this.message = (message != null && !message.isEmpty()) ? message : null;
}

@Override
Expand All @@ -65,6 +78,24 @@ public String getArtifactId() {
}
}

@Override
public String getClassifier() {
if (classifier != null) {
return classifier;
} else {
return artifact.getClassifier();
}
}

@Override
public String getExtension() {
if (extension != null) {
return extension;
} else {
return artifact.getExtension();
}
}

@Override
public String getVersion() {
if (version != null) {
Expand All @@ -81,7 +112,7 @@ public Artifact setVersion(String version) {
if (current.equals(version) || (version == null && current.length() <= 0)) {
return this;
}
return new RelocatedArtifact(artifact, groupId, artifactId, version, message);
return new RelocatedArtifact(artifact, groupId, artifactId, classifier, extension, version, message);
}

@Override
Expand All @@ -90,7 +121,8 @@ public Artifact setFile(File file) {
if (Objects.equals(current, file)) {
return this;
}
return new RelocatedArtifact(artifact.setFile(file), groupId, artifactId, version, message);
return new RelocatedArtifact(
artifact.setFile(file), groupId, artifactId, classifier, extension, version, message);
}

@Override
Expand All @@ -99,17 +131,8 @@ public Artifact setProperties(Map<String, String> properties) {
if (current.equals(properties) || (properties == null && current.isEmpty())) {
return this;
}
return new RelocatedArtifact(artifact.setProperties(properties), groupId, artifactId, version, message);
}

@Override
public String getClassifier() {
return artifact.getClassifier();
}

@Override
public String getExtension() {
return artifact.getExtension();
return new RelocatedArtifact(
artifact.setProperties(properties), groupId, artifactId, classifier, extension, version, message);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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.repository.internal.relocation;

import javax.inject.Named;
import javax.inject.Singleton;

import org.apache.maven.model.DistributionManagement;
import org.apache.maven.model.Model;
import org.apache.maven.model.Relocation;
import org.apache.maven.repository.internal.MavenArtifactRelocationSource;
import org.apache.maven.repository.internal.RelocatedArtifact;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
import org.eclipse.sisu.Priority;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Relocation source from standard distribution management. This is the "one and only" relocation implementation that
* existed in Maven 3 land, uses POM distributionManagement/relocation.
* <p>
* Note: this component should kick-in last regarding relocations.
*
* @since 4.0.0
*/
@Singleton
@Named
@Priority(5)
@SuppressWarnings("checkstyle:MagicNumber")
public final class DistributionManagementArtifactRelocationSource implements MavenArtifactRelocationSource {
private static final Logger LOGGER = LoggerFactory.getLogger(DistributionManagementArtifactRelocationSource.class);

@Override
public Artifact relocatedTarget(RepositorySystemSession session, ArtifactDescriptorRequest request, Model model) {
DistributionManagement distMgmt = model.getDistributionManagement();
if (distMgmt != null) {
Relocation relocation = distMgmt.getRelocation();
if (relocation != null) {
Artifact result = new RelocatedArtifact(
request.getArtifact(),
relocation.getGroupId(),
relocation.getArtifactId(),
null,
null,
relocation.getVersion(),
relocation.getMessage());
LOGGER.debug(
"The artifact {} has been relocated to {}: {}",
request.getArtifact(),
result,
relocation.getMessage());
return result;
}
}
return null;
}
}
Loading

0 comments on commit e34afc8

Please sign in to comment.