diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/validator/MavenValidator.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/validator/MavenValidator.java new file mode 100644 index 000000000000..3726a7719f37 --- /dev/null +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/validator/MavenValidator.java @@ -0,0 +1,93 @@ +/* + * 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.impl.resolver.validator; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.validator.Validator; + +/** + * Simplest Maven specific validator that is meant to prevent un-interpolated + * elements enter resolver; if it does, is most likely some bug. + */ +public class MavenValidator implements Validator { + protected boolean containsPlaceholder(String value) { + return value != null && value.contains("${"); + } + + @Override + public void validateArtifact(Artifact artifact) throws IllegalArgumentException { + if (containsPlaceholder(artifact.getGroupId()) + || containsPlaceholder(artifact.getArtifactId()) + || containsPlaceholder(artifact.getVersion()) + || containsPlaceholder(artifact.getClassifier()) + || containsPlaceholder(artifact.getExtension())) { + throw new IllegalArgumentException("Not fully interpolated artifact " + artifact); + } + } + + @Override + public void validateMetadata(Metadata metadata) throws IllegalArgumentException { + if (containsPlaceholder(metadata.getGroupId()) + || containsPlaceholder(metadata.getArtifactId()) + || containsPlaceholder(metadata.getVersion()) + || containsPlaceholder(metadata.getType())) { + throw new IllegalArgumentException("Not fully interpolated metadata " + metadata); + } + } + + @Override + public void validateDependency(Dependency dependency) throws IllegalArgumentException { + Artifact artifact = dependency.getArtifact(); + if (containsPlaceholder(artifact.getGroupId()) + || containsPlaceholder(artifact.getArtifactId()) + || containsPlaceholder(artifact.getVersion()) + || containsPlaceholder(artifact.getClassifier()) + || containsPlaceholder(artifact.getExtension()) + || containsPlaceholder(dependency.getScope()) + || dependency.getExclusions().stream() + .anyMatch(e -> containsPlaceholder(e.getGroupId()) + || containsPlaceholder(e.getArtifactId()) + || containsPlaceholder(e.getClassifier()) + || containsPlaceholder(e.getExtension()))) { + throw new IllegalArgumentException("Not fully interpolated dependency " + dependency); + } + } + + @Override + public void validateLocalRepository(LocalRepository localRepository) throws IllegalArgumentException { + if (containsPlaceholder(localRepository.getBasePath().toString()) + || containsPlaceholder(localRepository.getContentType()) + || containsPlaceholder(localRepository.getId())) { + throw new IllegalArgumentException("Not fully interpolated local repository " + localRepository); + } + } + + @Override + public void validateRemoteRepository(RemoteRepository remoteRepository) throws IllegalArgumentException { + if (containsPlaceholder(remoteRepository.getUrl()) + || containsPlaceholder(remoteRepository.getContentType()) + || containsPlaceholder(remoteRepository.getId())) { + throw new IllegalArgumentException("Not fully interpolated remote repository " + remoteRepository); + } + } +} diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/validator/MavenValidatorFactory.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/validator/MavenValidatorFactory.java new file mode 100644 index 000000000000..57039f9b23a7 --- /dev/null +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/validator/MavenValidatorFactory.java @@ -0,0 +1,36 @@ +/* + * 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.impl.resolver.validator; + +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.spi.validator.Validator; +import org.eclipse.aether.spi.validator.ValidatorFactory; + +@Named +@Singleton +public class MavenValidatorFactory implements ValidatorFactory { + private final MavenValidator instance = new MavenValidator(); + + @Override + public Validator newInstance(RepositorySystemSession repositorySystemSession) { + return instance; + } +} diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/standalone/RepositorySystemSupplier.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/standalone/RepositorySystemSupplier.java index 50832df1d65d..7089b9fb6690 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/standalone/RepositorySystemSupplier.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/standalone/RepositorySystemSupplier.java @@ -18,11 +18,13 @@ */ package org.apache.maven.impl.standalone; +import java.util.List; import java.util.Map; import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.di.Named; import org.apache.maven.api.di.Provides; +import org.apache.maven.impl.resolver.validator.MavenValidatorFactory; import org.eclipse.aether.RepositoryListener; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; @@ -40,6 +42,7 @@ import org.eclipse.aether.impl.RepositoryConnectorProvider; import org.eclipse.aether.impl.RepositoryEventDispatcher; import org.eclipse.aether.impl.RepositorySystemLifecycle; +import org.eclipse.aether.impl.RepositorySystemValidator; import org.eclipse.aether.impl.UpdateCheckManager; import org.eclipse.aether.impl.UpdatePolicyAnalyzer; import org.eclipse.aether.impl.VersionRangeResolver; @@ -62,6 +65,7 @@ import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; import org.eclipse.aether.internal.impl.DefaultRepositorySystem; import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemValidator; import org.eclipse.aether.internal.impl.DefaultTrackingFileManager; import org.eclipse.aether.internal.impl.DefaultTransporterProvider; import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; @@ -85,8 +89,10 @@ import org.eclipse.aether.internal.impl.collect.bf.BfDependencyCollector; import org.eclipse.aether.internal.impl.collect.df.DfDependencyCollector; import org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager; +import org.eclipse.aether.internal.impl.filter.FilteringPipelineRepositoryConnectorFactory; import org.eclipse.aether.internal.impl.filter.GroupIdRemoteRepositoryFilterSource; import org.eclipse.aether.internal.impl.filter.PrefixesRemoteRepositoryFilterSource; +import org.eclipse.aether.internal.impl.offline.OfflinePipelineRepositoryConnectorFactory; import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory; import org.eclipse.aether.internal.impl.synccontext.named.NameMapper; import org.eclipse.aether.internal.impl.synccontext.named.NameMappers; @@ -105,6 +111,7 @@ import org.eclipse.aether.spi.artifact.generator.ArtifactGeneratorFactory; import org.eclipse.aether.spi.checksums.ProvidedChecksumsSource; import org.eclipse.aether.spi.checksums.TrustedChecksumsSource; +import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory; import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; @@ -121,6 +128,7 @@ import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; import org.eclipse.aether.spi.resolution.ArtifactResolverPostProcessor; import org.eclipse.aether.spi.synccontext.SyncContextFactory; +import org.eclipse.aether.spi.validator.ValidatorFactory; /** * DI Bridge for Maven Resolver @@ -177,8 +185,8 @@ static UpdatePolicyAnalyzer newUpdatePolicyAnalyzer() { @Provides static RepositoryConnectorProvider newRepositoryConnectorProvider( Map connectorFactories, - RemoteRepositoryFilterManager remoteRepositoryFilterManager) { - return new DefaultRepositoryConnectorProvider(connectorFactories, remoteRepositoryFilterManager); + Map pipelineConnectorFactories) { + return new DefaultRepositoryConnectorProvider(connectorFactories, pipelineConnectorFactories); } @Named("basic") @@ -197,6 +205,20 @@ static BasicRepositoryConnectorFactory newBasicRepositoryConnectorFactory( providedChecksumsSources); } + @Named(OfflinePipelineRepositoryConnectorFactory.NAME) + @Provides + static OfflinePipelineRepositoryConnectorFactory newOfflinePipelineConnectorFactory( + OfflineController offlineController) { + return new OfflinePipelineRepositoryConnectorFactory(offlineController); + } + + @Named(FilteringPipelineRepositoryConnectorFactory.NAME) + @Provides + static FilteringPipelineRepositoryConnectorFactory newFilteringPipelineConnectorFactory( + RemoteRepositoryFilterManager remoteRepositoryFilterManager) { + return new FilteringPipelineRepositoryConnectorFactory(remoteRepositoryFilterManager); + } + @Provides static RepositoryLayoutProvider newRepositoryLayoutProvider(Map layoutFactories) { return new DefaultRepositoryLayoutProvider(layoutFactories); @@ -245,6 +267,16 @@ static PathProcessor newPathProcessor() { return new DefaultPathProcessor(); } + @Provides + static List newValidatorFactories() { + return List.of(new MavenValidatorFactory()); + } + + @Provides + static RepositorySystemValidator newRepositorySystemValidator(List validatorFactories) { + return new DefaultRepositorySystemValidator(validatorFactories); + } + @Provides static RepositorySystem newRepositorySystem( VersionResolver versionResolver, @@ -259,7 +291,8 @@ static RepositorySystem newRepositorySystem( SyncContextFactory syncContextFactory, RemoteRepositoryManager remoteRepositoryManager, RepositorySystemLifecycle repositorySystemLifecycle, - @Nullable Map artifactDecoratorFactories) { + @Nullable Map artifactDecoratorFactories, + RepositorySystemValidator repositorySystemValidator) { return new DefaultRepositorySystem( versionResolver, versionRangeResolver, @@ -273,7 +306,8 @@ static RepositorySystem newRepositorySystem( syncContextFactory, remoteRepositoryManager, repositorySystemLifecycle, - artifactDecoratorFactories != null ? artifactDecoratorFactories : Map.of()); + artifactDecoratorFactories != null ? artifactDecoratorFactories : Map.of(), + repositorySystemValidator); } @Provides diff --git a/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/stubs/RepositorySystemSupplier.java b/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/stubs/RepositorySystemSupplier.java index 5f7246db79ec..18a48a4b4710 100644 --- a/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/stubs/RepositorySystemSupplier.java +++ b/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/stubs/RepositorySystemSupplier.java @@ -18,6 +18,7 @@ */ package org.apache.maven.api.plugin.testing.stubs; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -57,6 +58,7 @@ import org.apache.maven.impl.resolver.VersionsMetadataGeneratorFactory; import org.apache.maven.impl.resolver.relocation.DistributionManagementArtifactRelocationSource; import org.apache.maven.impl.resolver.relocation.UserPropertiesArtifactRelocationSource; +import org.apache.maven.impl.resolver.validator.MavenValidatorFactory; import org.eclipse.aether.RepositoryListener; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; @@ -74,6 +76,7 @@ import org.eclipse.aether.impl.RepositoryConnectorProvider; import org.eclipse.aether.impl.RepositoryEventDispatcher; import org.eclipse.aether.impl.RepositorySystemLifecycle; +import org.eclipse.aether.impl.RepositorySystemValidator; import org.eclipse.aether.impl.UpdateCheckManager; import org.eclipse.aether.impl.UpdatePolicyAnalyzer; import org.eclipse.aether.impl.VersionRangeResolver; @@ -96,6 +99,7 @@ import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; import org.eclipse.aether.internal.impl.DefaultRepositorySystem; import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemValidator; import org.eclipse.aether.internal.impl.DefaultTrackingFileManager; import org.eclipse.aether.internal.impl.DefaultTransporterProvider; import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; @@ -119,8 +123,10 @@ import org.eclipse.aether.internal.impl.collect.bf.BfDependencyCollector; import org.eclipse.aether.internal.impl.collect.df.DfDependencyCollector; import org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager; +import org.eclipse.aether.internal.impl.filter.FilteringPipelineRepositoryConnectorFactory; import org.eclipse.aether.internal.impl.filter.GroupIdRemoteRepositoryFilterSource; import org.eclipse.aether.internal.impl.filter.PrefixesRemoteRepositoryFilterSource; +import org.eclipse.aether.internal.impl.offline.OfflinePipelineRepositoryConnectorFactory; import org.eclipse.aether.internal.impl.resolution.TrustedChecksumsArtifactResolverPostProcessor; import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory; import org.eclipse.aether.internal.impl.synccontext.named.NameMapper; @@ -141,6 +147,7 @@ import org.eclipse.aether.spi.artifact.transformer.ArtifactTransformer; import org.eclipse.aether.spi.checksums.ProvidedChecksumsSource; import org.eclipse.aether.spi.checksums.TrustedChecksumsSource; +import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory; import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; @@ -157,6 +164,7 @@ import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; import org.eclipse.aether.spi.resolution.ArtifactResolverPostProcessor; import org.eclipse.aether.spi.synccontext.SyncContextFactory; +import org.eclipse.aether.spi.validator.ValidatorFactory; import org.eclipse.aether.transport.apache.ApacheTransporterFactory; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.util.version.GenericVersionScheme; @@ -720,6 +728,27 @@ protected Map createRepositoryConnectorFacto return result; } + private Map pipelineRepositoryConnectorFactories; + + public final Map getPipelineRepositoryConnectorFactories() { + checkClosed(); + if (pipelineRepositoryConnectorFactories == null) { + pipelineRepositoryConnectorFactories = createPipelineRepositoryConnectorFactories(); + } + return pipelineRepositoryConnectorFactories; + } + + protected Map createPipelineRepositoryConnectorFactories() { + HashMap result = new HashMap<>(); + result.put( + OfflinePipelineRepositoryConnectorFactory.NAME, + new OfflinePipelineRepositoryConnectorFactory(getOfflineController())); + result.put( + FilteringPipelineRepositoryConnectorFactory.NAME, + new FilteringPipelineRepositoryConnectorFactory(getRemoteRepositoryFilterManager())); + return result; + } + private RepositoryConnectorProvider repositoryConnectorProvider; public final RepositoryConnectorProvider getRepositoryConnectorProvider() { @@ -732,7 +761,7 @@ public final RepositoryConnectorProvider getRepositoryConnectorProvider() { protected RepositoryConnectorProvider createRepositoryConnectorProvider() { return new DefaultRepositoryConnectorProvider( - getRepositoryConnectorFactories(), getRemoteRepositoryFilterManager()); + getRepositoryConnectorFactories(), getPipelineRepositoryConnectorFactories()); } private Installer installer; @@ -1081,6 +1110,36 @@ protected ModelBuilder createModelBuilder() { new DefaultRootLocator()); } + private RepositorySystemValidator repositorySystemValidator; + + public RepositorySystemValidator getRepositorySystemValidator() { + checkClosed(); + if (repositorySystemValidator == null) { + repositorySystemValidator = createRepositorySystemValidator(); + } + return repositorySystemValidator; + } + + protected RepositorySystemValidator createRepositorySystemValidator() { + return new DefaultRepositorySystemValidator(getValidatorFactories()); + } + + private List validatorFactories; + + public final List getValidatorFactories() { + checkClosed(); + if (validatorFactories == null) { + validatorFactories = createValidatorFactories(); + } + return validatorFactories; + } + + protected List createValidatorFactories() { + List result = new ArrayList<>(); + result.add(new MavenValidatorFactory()); + return result; + } + private RepositorySystem repositorySystem; public final RepositorySystem getRepositorySystem() { @@ -1105,7 +1164,8 @@ protected RepositorySystem createRepositorySystem() { getSyncContextFactory(), getRemoteRepositoryManager(), getRepositorySystemLifecycle(), - getArtifactDecoratorFactories()); + getArtifactDecoratorFactories(), + getRepositorySystemValidator()); } @Override diff --git a/its/core-it-suite/src/test/resources/mng-5639-import-scope-pom-resolution/.mvn/maven.properties b/its/core-it-suite/src/test/resources/mng-5639-import-scope-pom-resolution/.mvn/maven.properties new file mode 100644 index 000000000000..0344983373a6 --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-5639-import-scope-pom-resolution/.mvn/maven.properties @@ -0,0 +1,2 @@ +# Value corresponds to the folder name in this directory +repository.url.suffix.property = repo-set-by-property diff --git a/its/core-it-suite/src/test/resources/mng-5639-import-scope-pom-resolution/pom.xml b/its/core-it-suite/src/test/resources/mng-5639-import-scope-pom-resolution/pom.xml index ee0ca564cd41..c119576f3342 100644 --- a/its/core-it-suite/src/test/resources/mng-5639-import-scope-pom-resolution/pom.xml +++ b/its/core-it-suite/src/test/resources/mng-5639-import-scope-pom-resolution/pom.xml @@ -29,11 +29,6 @@ under the License. Checks that an import POM in the dependencyManagement section can be successfully resolved from a repository defining a URL that contains a property. - - - repo-set-by-property - - diff --git a/pom.xml b/pom.xml index cdaed2b86e23..5978a366efe4 100644 --- a/pom.xml +++ b/pom.xml @@ -162,7 +162,7 @@ under the License. 1.28 1.5.0 4.1.0 - 2.0.7 + 2.0.8 4.1.0 0.9.0.M3 2.0.17