mirror of https://github.com/apache/maven.git
[MNG-7960] Artifact collection filtering (#1353)
Make Maven more friendly (and tunable) when ranges are being used. There new options are merely affecting range processing, allowing different narrowing strategies. Relies on latest Resolver alpha-6 features. https://issues.apache.org/jira/browse/MNG-7960
This commit is contained in:
parent
63a207a0f6
commit
a952c9ee10
|
@ -30,6 +30,7 @@ import java.util.HashSet;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.maven.RepositoryUtils;
|
||||
|
@ -59,6 +60,9 @@ import org.eclipse.aether.RepositoryListener;
|
|||
import org.eclipse.aether.RepositorySystem;
|
||||
import org.eclipse.aether.RepositorySystemSession;
|
||||
import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
|
||||
import org.eclipse.aether.artifact.Artifact;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.collection.VersionFilter;
|
||||
import org.eclipse.aether.repository.AuthenticationContext;
|
||||
import org.eclipse.aether.repository.AuthenticationSelector;
|
||||
import org.eclipse.aether.repository.ProxySelector;
|
||||
|
@ -67,6 +71,7 @@ import org.eclipse.aether.repository.RepositoryPolicy;
|
|||
import org.eclipse.aether.repository.WorkspaceReader;
|
||||
import org.eclipse.aether.resolution.ResolutionErrorPolicy;
|
||||
import org.eclipse.aether.util.graph.manager.ClassicDependencyManager;
|
||||
import org.eclipse.aether.util.graph.version.*;
|
||||
import org.eclipse.aether.util.listener.ChainedRepositoryListener;
|
||||
import org.eclipse.aether.util.repository.AuthenticationBuilder;
|
||||
import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
|
||||
|
@ -75,6 +80,10 @@ import org.eclipse.aether.util.repository.DefaultMirrorSelector;
|
|||
import org.eclipse.aether.util.repository.DefaultProxySelector;
|
||||
import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
|
||||
import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
|
||||
import org.eclipse.aether.version.InvalidVersionSpecificationException;
|
||||
import org.eclipse.aether.version.Version;
|
||||
import org.eclipse.aether.version.VersionRange;
|
||||
import org.eclipse.aether.version.VersionScheme;
|
||||
import org.eclipse.sisu.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -84,6 +93,25 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
@Named
|
||||
public class DefaultRepositorySystemSessionFactory {
|
||||
/**
|
||||
* User property for version filters expression, a semicolon separated list of filters to apply. By default, no version
|
||||
* filter is applied (like in Maven 3).
|
||||
* <p>
|
||||
* Supported filters:
|
||||
* <ul>
|
||||
* <li>"h" or "h(num)" - highest version or top list of highest ones filter</li>
|
||||
* <li>"l" or "l(num)" - lowest version or bottom list of lowest ones filter</li>
|
||||
* <li>"s" - contextual snapshot filter</li>
|
||||
* <li>"e(G:A:V)" - predicate filter (leaves out G:A:V from range, if hit, V can be range)</li>
|
||||
* </ul>
|
||||
* Example filter expression: {@code "h(5);s;e(org.foo:bar:1)} will cause: ranges are filtered for "top 5" (instead
|
||||
* full range), snapshots are banned if root project is not a snapshot, and if range for {@code org.foo:bar} is
|
||||
* being processed, version 1 is omitted.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private static final String MAVEN_VERSION_FILTERS = "maven.versionFilters";
|
||||
|
||||
/**
|
||||
* User property for chained LRM: list of "tail" local repository paths (separated by comma), to be used with
|
||||
* {@link ChainedLocalRepositoryManager}.
|
||||
|
@ -162,6 +190,8 @@ public class DefaultRepositorySystemSessionFactory {
|
|||
|
||||
private final TypeRegistry typeRegistry;
|
||||
|
||||
private final VersionScheme versionScheme;
|
||||
|
||||
@SuppressWarnings("checkstyle:ParameterNumber")
|
||||
@Inject
|
||||
public DefaultRepositorySystemSessionFactory(
|
||||
|
@ -171,7 +201,8 @@ public class DefaultRepositorySystemSessionFactory {
|
|||
SettingsDecrypter settingsDecrypter,
|
||||
EventSpyDispatcher eventSpyDispatcher,
|
||||
RuntimeInformation runtimeInformation,
|
||||
TypeRegistry typeRegistry) {
|
||||
TypeRegistry typeRegistry,
|
||||
VersionScheme versionScheme) {
|
||||
this.artifactHandlerManager = artifactHandlerManager;
|
||||
this.repoSystem = repoSystem;
|
||||
this.workspaceRepository = workspaceRepository;
|
||||
|
@ -179,6 +210,7 @@ public class DefaultRepositorySystemSessionFactory {
|
|||
this.eventSpyDispatcher = eventSpyDispatcher;
|
||||
this.runtimeInformation = runtimeInformation;
|
||||
this.typeRegistry = typeRegistry;
|
||||
this.versionScheme = versionScheme;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@ -222,6 +254,11 @@ public class DefaultRepositorySystemSessionFactory {
|
|||
session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(
|
||||
request.isIgnoreMissingArtifactDescriptor(), request.isIgnoreInvalidArtifactDescriptor()));
|
||||
|
||||
VersionFilter versionFilter = buildVersionFilter((String) configProps.get(MAVEN_VERSION_FILTERS));
|
||||
if (versionFilter != null) {
|
||||
session.setVersionFilter(versionFilter);
|
||||
}
|
||||
|
||||
session.setArtifactTypeRegistry(RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager));
|
||||
|
||||
session.setWorkspaceReader(
|
||||
|
@ -426,6 +463,72 @@ public class DefaultRepositorySystemSessionFactory {
|
|||
return session;
|
||||
}
|
||||
|
||||
private VersionFilter buildVersionFilter(String filterExpression) {
|
||||
ArrayList<VersionFilter> filters = new ArrayList<>();
|
||||
if (filterExpression != null) {
|
||||
List<String> expressions = Arrays.stream(filterExpression.split(";"))
|
||||
.filter(s -> s != null && !s.trim().isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
for (String expression : expressions) {
|
||||
if ("h".equals(expression)) {
|
||||
filters.add(new HighestVersionFilter());
|
||||
} else if (expression.startsWith("h(") && expression.endsWith(")")) {
|
||||
int num = Integer.parseInt(expression.substring(2, expression.length() - 1));
|
||||
filters.add(new HighestVersionFilter(num));
|
||||
} else if ("l".equals(expression)) {
|
||||
filters.add(new LowestVersionFilter());
|
||||
} else if (expression.startsWith("l(") && expression.endsWith(")")) {
|
||||
int num = Integer.parseInt(expression.substring(2, expression.length() - 1));
|
||||
filters.add(new LowestVersionFilter(num));
|
||||
} else if ("s".equals(expression)) {
|
||||
filters.add(new ContextualSnapshotVersionFilter());
|
||||
} else if (expression.startsWith("e(") && expression.endsWith(")")) {
|
||||
Artifact artifact = new DefaultArtifact(expression.substring(2, expression.length() - 1));
|
||||
VersionRange versionRange =
|
||||
artifact.getVersion().contains(",") ? parseVersionRange(artifact.getVersion()) : null;
|
||||
Predicate<Artifact> predicate = a -> {
|
||||
if (artifact.getGroupId().equals(a.getGroupId())
|
||||
&& artifact.getArtifactId().equals(a.getArtifactId())) {
|
||||
if (versionRange != null) {
|
||||
Version v = parseVersion(a.getVersion());
|
||||
return !versionRange.containsVersion(v);
|
||||
} else {
|
||||
return !artifact.getVersion().equals(a.getVersion());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
filters.add(new PredicateVersionFilter(predicate));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported filter expression: " + expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filters.isEmpty()) {
|
||||
return null;
|
||||
} else if (filters.size() == 1) {
|
||||
return filters.get(0);
|
||||
} else {
|
||||
return ChainedVersionFilter.newInstance(filters);
|
||||
}
|
||||
}
|
||||
|
||||
private Version parseVersion(String spec) {
|
||||
try {
|
||||
return versionScheme.parseVersion(spec);
|
||||
} catch (InvalidVersionSpecificationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private VersionRange parseVersionRange(String spec) {
|
||||
try {
|
||||
return versionScheme.parseVersionRange(spec);
|
||||
} catch (InvalidVersionSpecificationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<?, ?> getPropertiesFromRequestedProfiles(MavenExecutionRequest request) {
|
||||
HashSet<String> activeProfileId =
|
||||
new HashSet<>(request.getProfileActivation().getRequiredActiveProfileIds());
|
||||
|
@ -508,7 +611,7 @@ public class DefaultRepositorySystemSessionFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void injectAuthentication(AuthenticationSelector selector, List<ArtifactRepository> repositories) {
|
||||
private void injectAuthentication(AuthenticationSelector selector, List<ArtifactRepository> repositories) {
|
||||
if (repositories != null && selector != null) {
|
||||
for (ArtifactRepository repository : repositories) {
|
||||
repository.setAuthentication(getAuthentication(selector, repository));
|
||||
|
|
|
@ -41,14 +41,14 @@ import org.codehaus.plexus.configuration.PlexusConfiguration;
|
|||
import org.codehaus.plexus.testing.PlexusTest;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
import org.eclipse.aether.ConfigurationProperties;
|
||||
import org.eclipse.aether.collection.VersionFilter;
|
||||
import org.eclipse.aether.repository.RepositoryPolicy;
|
||||
import org.eclipse.aether.util.graph.version.*;
|
||||
import org.eclipse.aether.version.VersionScheme;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* UT for {@link DefaultRepositorySystemSessionFactory}.
|
||||
|
@ -76,6 +76,9 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
@Inject
|
||||
protected DefaultTypeRegistry defaultTypeRegistry;
|
||||
|
||||
@Inject
|
||||
protected VersionScheme versionScheme;
|
||||
|
||||
@Test
|
||||
void isNoSnapshotUpdatesTest() throws InvalidRepositoryException {
|
||||
DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
|
||||
|
@ -85,7 +88,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
|
||||
request.setLocalRepository(getLocalRepository());
|
||||
|
@ -108,7 +112,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
|
||||
request.setLocalRepository(getLocalRepository());
|
||||
|
@ -143,7 +148,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
PlexusConfiguration plexusConfiguration = (PlexusConfiguration) systemSessionFactory
|
||||
.newRepositorySession(request)
|
||||
|
@ -186,7 +192,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
Map<String, String> headers = (Map<String, String>) systemSessionFactory
|
||||
.newRepositorySession(request)
|
||||
|
@ -223,7 +230,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
int connectionTimeout = (Integer) systemSessionFactory
|
||||
.newRepositorySession(request)
|
||||
|
@ -264,7 +272,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
int connectionTimeout = (Integer) systemSessionFactory
|
||||
.newRepositorySession(request)
|
||||
|
@ -299,7 +308,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
int requestTimeout = (Integer) systemSessionFactory
|
||||
.newRepositorySession(request)
|
||||
|
@ -340,7 +350,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
int requestTimeout = (Integer) systemSessionFactory
|
||||
.newRepositorySession(request)
|
||||
|
@ -358,7 +369,8 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry);
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
|
||||
request.setLocalRepository(getLocalRepository());
|
||||
|
@ -395,6 +407,66 @@ public class DefaultRepositorySystemSessionFactoryTest {
|
|||
properties.remove("maven.resolver.transport");
|
||||
}
|
||||
|
||||
@Test
|
||||
void versionFilteringTest() throws InvalidRepositoryException {
|
||||
DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
|
||||
artifactHandlerManager,
|
||||
aetherRepositorySystem,
|
||||
null,
|
||||
settingsDecrypter,
|
||||
eventSpyDispatcher,
|
||||
information,
|
||||
defaultTypeRegistry,
|
||||
versionScheme);
|
||||
|
||||
MavenExecutionRequest request = new DefaultMavenExecutionRequest();
|
||||
request.setLocalRepository(getLocalRepository());
|
||||
|
||||
VersionFilter versionFilter;
|
||||
|
||||
// single one
|
||||
request.getUserProperties().put("maven.versionFilters", "s");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof ContextualSnapshotVersionFilter);
|
||||
|
||||
request.getUserProperties().put("maven.versionFilters", "h");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof HighestVersionFilter);
|
||||
|
||||
request.getUserProperties().put("maven.versionFilters", "h(5)");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof HighestVersionFilter);
|
||||
|
||||
request.getUserProperties().put("maven.versionFilters", "l");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof LowestVersionFilter);
|
||||
|
||||
request.getUserProperties().put("maven.versionFilters", "l(5)");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof LowestVersionFilter);
|
||||
|
||||
request.getUserProperties().put("maven.versionFilters", "e(g:a:v)");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof PredicateVersionFilter);
|
||||
|
||||
request.getUserProperties().put("maven.versionFilters", "e(g:a:[1,2])");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof PredicateVersionFilter);
|
||||
|
||||
// chained
|
||||
request.getUserProperties().put("maven.versionFilters", "h(5);s;e(org.foo:bar:1)");
|
||||
versionFilter = systemSessionFactory.newRepositorySession(request).getVersionFilter();
|
||||
assertNotNull(versionFilter);
|
||||
assertTrue(versionFilter instanceof ChainedVersionFilter);
|
||||
}
|
||||
|
||||
protected ArtifactRepository getLocalRepository() throws InvalidRepositoryException {
|
||||
File repoDir = new File(getBasedir(), "target/local-repo").getAbsoluteFile();
|
||||
|
||||
|
|
Loading…
Reference in New Issue