Version resolver API (#1335)

This commit is contained in:
Guillaume Nodet 2023-12-08 10:10:49 +01:00 committed by GitHub
parent bd849b54ad
commit 2f91c7e9c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 799 additions and 48 deletions

View File

@ -169,185 +169,226 @@ public interface Session {
Collection<Listener> getListeners();
/**
* Shortcut for <code>getService(RepositoryFactory.class).createLocal(...)</code>
* Shortcut for {@code getService(RepositoryFactory.class).createLocal(...)}.
*
* @see org.apache.maven.api.services.RepositoryFactory#createLocal(Path)
*/
LocalRepository createLocalRepository(Path path);
/**
* Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
* Shortcut for {@code getService(RepositoryFactory.class).createRemote(...)}.
*
* @see org.apache.maven.api.services.RepositoryFactory#createRemote(String, String)
*/
@Nonnull
RemoteRepository createRemoteRepository(@Nonnull String id, @Nonnull String url);
/**
* Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
* Shortcut for {@code getService(RepositoryFactory.class).createRemote(...)}.
*
* @see org.apache.maven.api.services.RepositoryFactory#createRemote(Repository)
*/
@Nonnull
RemoteRepository createRemoteRepository(@Nonnull Repository repository);
/**
* Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
* Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
*
* @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String)
*/
ArtifactCoordinate createArtifactCoordinate(String groupId, String artifactId, String version, String extension);
/**
* Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
* Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
*
* @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
*/
ArtifactCoordinate createArtifactCoordinate(
String groupId, String artifactId, String version, String classifier, String extension, String type);
/**
* Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
* Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
*
* @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
*/
ArtifactCoordinate createArtifactCoordinate(Artifact artifact);
/**
* Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
* Shortcut for {@code getService(DependencyFactory.class).create(...)}.
*
* @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate)
*/
@Nonnull
DependencyCoordinate createDependencyCoordinate(@Nonnull ArtifactCoordinate coordinate);
/**
* Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
* Shortcut for {@code getService(DependencyFactory.class).create(...)}.
*
* @see DependencyCoordinateFactory#create(Session, Dependency)
*/
@Nonnull
DependencyCoordinate createDependencyCoordinate(@Nonnull Dependency dependency);
/**
* Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
* Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
*
* @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String)
*/
Artifact createArtifact(String groupId, String artifactId, String version, String extension);
/**
* Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
* Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
*
* @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
*/
Artifact createArtifact(
String groupId, String artifactId, String version, String classifier, String extension, String type);
/**
* Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}.
*
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
*/
Map.Entry<Artifact, Path> resolveArtifact(ArtifactCoordinate coordinate);
/**
* Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}.
*
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
*/
Map<Artifact, Path> resolveArtifacts(ArtifactCoordinate... coordinates);
/**
* Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}.
*
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
*/
Map<Artifact, Path> resolveArtifacts(Collection<? extends ArtifactCoordinate> coordinates);
/**
* Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}.
*
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
*/
Map.Entry<Artifact, Path> resolveArtifact(Artifact artifact);
/**
* Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}.
*
* @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
* @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
*/
Map<Artifact, Path> resolveArtifacts(Artifact... artifacts);
/**
* Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
* @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
* Shortcut for {@code getService(ArtifactInstaller.class).install(...)}.
*
* @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
* @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed
*/
void installArtifacts(Artifact... artifacts);
/**
* Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
* @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
* Shortcut for {@code getService(ArtifactInstaller.class).install(...)}.
*
* @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
* @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed
*/
void installArtifacts(Collection<Artifact> artifacts);
/**
* Shortcut for <code>getService(ArtifactDeployer.class).deploy(...)</code>
* @see org.apache.maven.api.services.ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
* Shortcut for {@code getService(ArtifactDeployer.class).deploy(...)}.
*
* @see org.apache.maven.api.services.ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
* @throws org.apache.maven.api.services.ArtifactDeployerException if the artifacts deployment failed
*/
void deployArtifact(RemoteRepository repository, Artifact... artifacts);
/**
* Shortcut for <code>getService(ArtifactManager.class).setPath(...)</code>
* Shortcut for {@code getService(ArtifactManager.class).setPath(...)}.
*
* @see org.apache.maven.api.services.ArtifactManager#setPath(Artifact, Path)
*/
void setArtifactPath(@Nonnull Artifact artifact, @Nonnull Path path);
/**
* Shortcut for <code>getService(ArtifactManager.class).getPath(...)</code>
* Shortcut for {@code getService(ArtifactManager.class).getPath(...)}.
*
* @see org.apache.maven.api.services.ArtifactManager#getPath(Artifact)
*/
@Nonnull
Optional<Path> getArtifactPath(@Nonnull Artifact artifact);
/**
* Shortcut for <code>getService(ArtifactManager.class).isSnapshot(...)</code>
* Gets the relative path for a locally installed artifact. Note that the artifact need not actually exist yet at
* the returned location, the path merely indicates where the artifact would eventually be stored.
* <p>
* Shortcut for {@code getService(LocalArtifactManager.class).getPathForLocalArtitact(...)}.
*
* @see org.apache.maven.api.services.LocalRepositoryManager#getPathForLocalArtifact(Session, LocalRepository, Artifact)
*/
Path getPathForLocalArtifact(@Nonnull Artifact artifact);
/**
* Gets the relative path for an artifact cached from a remote repository.
* Note that the artifact need not actually exist yet at the returned location,
* the path merely indicates where the artifact would eventually be stored.
* <p>
* Shortcut for {@code getService(LocalArtifactManager.class).getPathForRemoteArtifact(...)}.
*
* @see org.apache.maven.api.services.LocalRepositoryManager#getPathForRemoteArtifact(Session, LocalRepository, RemoteRepository, Artifact)
*/
@Nonnull
Path getPathForRemoteArtifact(@Nonnull RemoteRepository remote, @Nonnull Artifact artifact);
/**
* Checks whether a given artifact version is considered a {@code SNAPSHOT} or not.
* <p>
* Shortcut for {@code getService(ArtifactManager.class).isSnapshot(...)}.
*
* @see org.apache.maven.api.services.VersionParser#isSnapshot(String)
*/
boolean isVersionSnapshot(@Nonnull String version);
/**
* Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
* @see org.apache.maven.api.services.DependencyCollector#collect(Session, Artifact)
* Shortcut for {@code getService(DependencyCollector.class).collect(...)}
*
* @see org.apache.maven.api.services.DependencyCollector#collect(Session, Artifact)
* @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
*/
@Nonnull
Node collectDependencies(@Nonnull Artifact artifact);
/**
* Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
* @see org.apache.maven.api.services.DependencyCollector#collect(Session, Project)
* Shortcut for {@code getService(DependencyCollector.class).collect(...)}
*
* @see org.apache.maven.api.services.DependencyCollector#collect(Session, Project)
* @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
*/
@Nonnull
Node collectDependencies(@Nonnull Project project);
/**
* Shortcut for <code>getService(DependencyCollector.class).resolve(...)</code>
* @see org.apache.maven.api.services.DependencyCollector#collect(Session, DependencyCoordinate)
* Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
* only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
* artifact files.
* <p>
* Shortcut for {@code getService(DependencyCollector.class).resolve(...)}
*
* @see org.apache.maven.api.services.DependencyCollector#collect(Session, DependencyCoordinate)
* @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
*/
@Nonnull
Node collectDependencies(@Nonnull DependencyCoordinate dependency);
/**
* Shortcut for <code>getService(DependencyResolver.class).flatten(...)</code>
* @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, ResolutionScope)
* Shortcut for {@code getService(DependencyResolver.class).flatten(...)}.
*
* @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, ResolutionScope)
* @throws org.apache.maven.api.services.DependencyResolverException if the dependency flattening failed
*/
@Nonnull
@ -360,25 +401,52 @@ Artifact createArtifact(
List<Path> resolveDependencies(@Nonnull List<DependencyCoordinate> dependencyCoordinates);
@Nonnull
List<Path> resolveDependencies(@Nonnull Project project, ResolutionScope scope);
Path getPathForLocalArtifact(@Nonnull Artifact artifact);
Path getPathForRemoteArtifact(RemoteRepository remote, Artifact artifact);
List<Path> resolveDependencies(@Nonnull Project project, @Nonnull ResolutionScope scope);
/**
* Shortcut for <code>getService(VersionParser.class).parseVersion(...)</code>
* @see org.apache.maven.api.services.VersionParser#parseVersion(String)
* Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT"
* to "1.0-20090208.132618-23" or "RELEASE"/"LATEST" to "2.0".
* <p>
* Shortcut for {@code getService(VersionResolver.class).resolve(...)}
*
* @see org.apache.maven.api.services.VersionResolver#resolve(Session, ArtifactCoordinate) (String)
* @throws org.apache.maven.api.services.VersionResolverException if the resolution failed
*/
@Nonnull
Version resolveVersion(@Nonnull ArtifactCoordinate artifact);
/**
* Expands a version range to a list of matching versions, in ascending order.
* For example, resolves "[3.8,4.0)" to "3.8", "3.8.1", "3.8.2".
* The returned list of versions is only dependent on the configured repositories and their contents.
* The supplied request may also refer to a single concrete version rather than a version range.
* In this case though, the result contains simply the (parsed) input version, regardless of the
* repositories and their contents.
*
* @return a list of resolved {@code Version}s.
* @see org.apache.maven.api.services.VersionRangeResolver#resolve(Session, ArtifactCoordinate) (String)
* @throws org.apache.maven.api.services.VersionRangeResolverException if the resolution failed
*/
@Nonnull
List<Version> resolveVersionRange(@Nonnull ArtifactCoordinate artifact);
/**
* Parses the specified version string, for example "1.0".
* <p>
* Shortcut for {@code getService(VersionParser.class).parseVersion(...)}.
*
* @see org.apache.maven.api.services.VersionParser#parseVersion(String)
* @throws org.apache.maven.api.services.VersionParserException if the parsing failed
*/
@Nonnull
Version parseVersion(@Nonnull String version);
/**
* Shortcut for <code>getService(VersionParser.class).parseVersionRange(...)</code>
* @see org.apache.maven.api.services.VersionParser#parseVersionRange(String)
* Parses the specified version range specification, for example "[1.0,2.0)".
* <p>
* Shortcut for {@code getService(VersionParser.class).parseVersionRange(...)}.
*
* @see org.apache.maven.api.services.VersionParser#parseVersionRange(String)
* @throws org.apache.maven.api.services.VersionParserException if the parsing failed
*/
@Nonnull

View File

@ -26,6 +26,7 @@
import org.apache.maven.api.Service;
import org.apache.maven.api.Session;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
/**
*
@ -34,7 +35,34 @@
@Experimental
public interface LocalRepositoryManager extends Service {
Path getPathForLocalArtifact(Session session, LocalRepository local, Artifact artifact);
/**
* Gets the relative path for a locally installed artifact.
* Note that the artifact need not actually exist yet at
* the returned location, the path merely indicates where
* the artifact would eventually be stored.
*
* @param session The session to use, must not be {@code null}.
* @param artifact The artifact for which to determine the path, must not be {@code null}.
* @return The path, resolved against the local repository's base directory.
*/
@Nonnull
Path getPathForLocalArtifact(@Nonnull Session session, @Nonnull LocalRepository local, @Nonnull Artifact artifact);
Path getPathForRemoteArtifact(Session session, LocalRepository local, RemoteRepository remote, Artifact artifact);
/**
* Gets the relative path for an artifact cached from a remote repository.
* Note that the artifact need not actually exist yet at the returned location,
* the path merely indicates where the artifact would eventually be stored.
*
* @param session The session to use, must not be {@code null}.
* @param local The local repository, must not be {@code null}.
* @param artifact The artifact for which to determine the path, must not be {@code null}.
* @param remote The source repository of the artifact, must not be {@code null}.
* @return The path, relative to the local repository's base directory.
*/
@Nonnull
Path getPathForRemoteArtifact(
@Nonnull Session session,
@Nonnull LocalRepository local,
@Nonnull RemoteRepository remote,
@Nonnull Artifact artifact);
}

View File

@ -31,6 +31,7 @@
*/
@Experimental
public interface VersionParser extends Service {
/**
* Parses the specified version string, for example "1.0".
*

View File

@ -0,0 +1,57 @@
/*
* 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.api.services;
import org.apache.maven.api.ArtifactCoordinate;
import org.apache.maven.api.Service;
import org.apache.maven.api.Session;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
/**
* Parses and evaluates version ranges encountered in dependency declarations.
*/
@Experimental
@Consumer
public interface VersionRangeResolver extends Service {
/**
* Expands a version range to a list of matching versions, in ascending order.
* For example, resolves "[3.8,4.0)" to "3.8", "3.8.1", "3.8.2".
* The returned list of versions is only dependent on the configured repositories and their contents.
* The supplied request may also refer to a single concrete version rather than a version range.
* In this case though, the result contains simply the (parsed) input version, regardless of the
* repositories and their contents.
*
* @param session the session to use
* @param artifactCoordinate t
* @return the version range resolution result
* @throws VersionResolverException if an errors occurs
*/
@Nonnull
default VersionRangeResolverResult resolve(@Nonnull Session session, @Nonnull ArtifactCoordinate artifactCoordinate)
throws VersionResolverException {
return resolve(VersionRangeResolverRequest.build(session, artifactCoordinate));
}
@Nonnull
VersionRangeResolverResult resolve(@Nonnull VersionRangeResolverRequest request)
throws VersionRangeResolverException;
}

View File

@ -0,0 +1,33 @@
/*
* 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.api.services;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
/**
* @since 4.0.0
*/
@Experimental
@Consumer
public class VersionRangeResolverException extends MavenException {
public VersionRangeResolverException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,86 @@
/*
* 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.api.services;
import org.apache.maven.api.ArtifactCoordinate;
import org.apache.maven.api.Session;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.NotThreadSafe;
import static org.apache.maven.api.services.BaseRequest.nonNull;
@Experimental
public interface VersionRangeResolverRequest {
@Nonnull
Session getSession();
@Nonnull
ArtifactCoordinate getArtifactCoordinate();
@Nonnull
static VersionRangeResolverRequest build(@Nonnull Session session, @Nonnull ArtifactCoordinate artifactCoordinate) {
return builder()
.session(nonNull(session, "session cannot be null"))
.artifactCoordinate(nonNull(artifactCoordinate, "artifactCoordinate cannot be null"))
.build();
}
@Nonnull
static VersionResolverRequestBuilder builder() {
return new VersionResolverRequestBuilder();
}
@NotThreadSafe
class VersionResolverRequestBuilder {
Session session;
ArtifactCoordinate artifactCoordinate;
public VersionResolverRequestBuilder session(Session session) {
this.session = session;
return this;
}
public VersionResolverRequestBuilder artifactCoordinate(ArtifactCoordinate artifactCoordinate) {
this.artifactCoordinate = artifactCoordinate;
return this;
}
public VersionRangeResolverRequest build() {
return new DefaultVersionResolverRequest(session, artifactCoordinate);
}
private static class DefaultVersionResolverRequest extends BaseRequest implements VersionRangeResolverRequest {
private final ArtifactCoordinate artifactCoordinate;
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultVersionResolverRequest(@Nonnull Session session, @Nonnull ArtifactCoordinate artifactCoordinate) {
super(session);
this.artifactCoordinate = artifactCoordinate;
}
@Nonnull
@Override
public ArtifactCoordinate getArtifactCoordinate() {
return artifactCoordinate;
}
}
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.api.services;
import java.util.List;
import java.util.Optional;
import org.apache.maven.api.Repository;
import org.apache.maven.api.Version;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
@Experimental
public interface VersionRangeResolverResult {
@Nonnull
List<Exception> getExceptions();
@Nonnull
List<Version> getVersions();
@Nonnull
default Optional<Version> getLowerVersion() {
return getVersions().isEmpty()
? Optional.empty()
: Optional.of(getVersions().get(0));
}
@Nonnull
default Optional<Version> getHigherVersion() {
return getVersions().isEmpty()
? Optional.empty()
: Optional.of(getVersions().get(getVersions().size() - 1));
}
@Nonnull
Optional<Repository> getRepository(Version version);
}

View File

@ -0,0 +1,60 @@
/*
* 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.api.services;
import org.apache.maven.api.ArtifactCoordinate;
import org.apache.maven.api.Service;
import org.apache.maven.api.Session;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
/**
* Resolves artifact meta/pseudo versions.
*/
@Experimental
@Consumer
public interface VersionResolver extends Service {
/**
* Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT"
* to "1.0-20090208.132618-23" or "RELEASE"/"LATEST" to "2.0".
*
* @param session The repository session, must not be {@code null}.
* @param artifactCoordinate The artifact coordinate for which the version needs to be resolved, must not be {@code null}
* @return The version result, never {@code null}.
* @throws VersionResolverException If the metaversion could not be resolved.
*/
@Nonnull
default VersionResolverResult resolve(@Nonnull Session session, @Nonnull ArtifactCoordinate artifactCoordinate)
throws VersionResolverException {
return resolve(VersionResolverRequest.build(session, artifactCoordinate));
}
/**
* Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT"
* to "1.0-20090208.132618-23" or "RELEASE"/"LATEST" to "2.0".
*
* @param request The version request, must not be {@code null}.
* @return The version result, never {@code null}.
* @throws VersionResolverException If the metaversion could not be resolved.
*/
@Nonnull
VersionResolverResult resolve(@Nonnull VersionResolverRequest request) throws VersionResolverException;
}

View File

@ -0,0 +1,33 @@
/*
* 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.api.services;
import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
/**
* @since 4.0.0
*/
@Experimental
@Consumer
public class VersionResolverException extends MavenException {
public VersionResolverException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,86 @@
/*
* 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.api.services;
import org.apache.maven.api.ArtifactCoordinate;
import org.apache.maven.api.Session;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.NotThreadSafe;
import static org.apache.maven.api.services.BaseRequest.nonNull;
@Experimental
public interface VersionResolverRequest {
@Nonnull
Session getSession();
@Nonnull
ArtifactCoordinate getArtifactCoordinate();
@Nonnull
static VersionResolverRequest build(@Nonnull Session session, @Nonnull ArtifactCoordinate artifactCoordinate) {
return builder()
.session(nonNull(session, "session cannot be null"))
.artifactCoordinate(nonNull(artifactCoordinate, "artifactCoordinate cannot be null"))
.build();
}
@Nonnull
static VersionResolverRequestBuilder builder() {
return new VersionResolverRequestBuilder();
}
@NotThreadSafe
class VersionResolverRequestBuilder {
Session session;
ArtifactCoordinate artifactCoordinate;
public VersionResolverRequestBuilder session(Session session) {
this.session = session;
return this;
}
public VersionResolverRequestBuilder artifactCoordinate(ArtifactCoordinate artifactCoordinate) {
this.artifactCoordinate = artifactCoordinate;
return this;
}
public VersionResolverRequest build() {
return new DefaultVersionResolverRequest(session, artifactCoordinate);
}
private static class DefaultVersionResolverRequest extends BaseRequest implements VersionResolverRequest {
private final ArtifactCoordinate artifactCoordinate;
@SuppressWarnings("checkstyle:ParameterNumber")
DefaultVersionResolverRequest(@Nonnull Session session, @Nonnull ArtifactCoordinate artifactCoordinate) {
super(session);
this.artifactCoordinate = artifactCoordinate;
}
@Nonnull
@Override
public ArtifactCoordinate getArtifactCoordinate() {
return artifactCoordinate;
}
}
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.api.services;
import java.util.List;
import java.util.Optional;
import org.apache.maven.api.Repository;
import org.apache.maven.api.Version;
import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Nonnull;
@Experimental
public interface VersionResolverResult {
@Nonnull
List<Exception> getExceptions();
@Nonnull
Version getVersion();
@Nonnull
Optional<Repository> getRepository();
}

View File

@ -493,4 +493,14 @@ public Version parseVersion(String version) {
public VersionRange parseVersionRange(String versionRange) {
return getService(VersionParser.class).parseVersionRange(versionRange);
}
@Override
public Version resolveVersion(ArtifactCoordinate artifact) {
return getService(VersionResolver.class).resolve(this, artifact).getVersion();
}
@Override
public List<Version> resolveVersionRange(ArtifactCoordinate artifact) {
return getService(VersionRangeResolver.class).resolve(this, artifact).getVersions();
}
}

View File

@ -0,0 +1,102 @@
/*
* 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 javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.maven.api.Repository;
import org.apache.maven.api.Version;
import org.apache.maven.api.services.VersionRangeResolver;
import org.apache.maven.api.services.VersionRangeResolverException;
import org.apache.maven.api.services.VersionRangeResolverRequest;
import org.apache.maven.api.services.VersionRangeResolverResult;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.repository.ArtifactRepository;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import org.eclipse.aether.resolution.VersionRangeResult;
import static org.apache.maven.internal.impl.Utils.map;
import static org.apache.maven.internal.impl.Utils.nonNull;
@Named
@Singleton
public class DefaultVersionRangeResolver implements VersionRangeResolver {
private final RepositorySystem repositorySystem;
@Inject
public DefaultVersionRangeResolver(RepositorySystem repositorySystem) {
this.repositorySystem = repositorySystem;
}
@Override
public VersionRangeResolverResult resolve(VersionRangeResolverRequest request)
throws VersionRangeResolverException {
nonNull(request, "request");
InternalSession session = InternalSession.from(request.getSession());
try {
VersionRangeResult res = repositorySystem.resolveVersionRange(
session.getSession(),
new VersionRangeRequest(
session.toArtifact(request.getArtifactCoordinate()),
session.toRepositories(session.getRemoteRepositories()),
null));
Map<String, ArtifactRepository> repos =
res.getVersions().stream().collect(Collectors.toMap(v -> v.toString(), res::getRepository));
return new VersionRangeResolverResult() {
@Override
public List<Exception> getExceptions() {
return res.getExceptions();
}
@Override
public List<Version> getVersions() {
return map(res.getVersions(), v -> session.parseVersion(v.toString()));
}
@Override
public Optional<Repository> getRepository(Version version) {
ArtifactRepository repo = repos.get(version.toString());
if (repo instanceof org.eclipse.aether.repository.LocalRepository) {
return Optional.of(
new DefaultLocalRepository((org.eclipse.aether.repository.LocalRepository) repo));
} else if (repo instanceof org.eclipse.aether.repository.RemoteRepository) {
return Optional.of(
new DefaultRemoteRepository((org.eclipse.aether.repository.RemoteRepository) repo));
} else {
return Optional.empty();
}
}
};
} catch (VersionRangeResolutionException e) {
throw new VersionRangeResolverException("Unable to resolve version range", e);
}
}
}

View File

@ -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.internal.impl;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.List;
import java.util.Optional;
import org.apache.maven.api.Repository;
import org.apache.maven.api.Version;
import org.apache.maven.api.services.VersionResolver;
import org.apache.maven.api.services.VersionResolverException;
import org.apache.maven.api.services.VersionResolverRequest;
import org.apache.maven.api.services.VersionResolverResult;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.resolution.VersionRequest;
import org.eclipse.aether.resolution.VersionResolutionException;
import org.eclipse.aether.resolution.VersionResult;
import static org.apache.maven.internal.impl.Utils.nonNull;
@Named
@Singleton
public class DefaultVersionResolver implements VersionResolver {
private final RepositorySystem repositorySystem;
@Inject
public DefaultVersionResolver(RepositorySystem repositorySystem) {
this.repositorySystem = repositorySystem;
}
@Override
public VersionResolverResult resolve(VersionResolverRequest request) throws VersionResolverException {
nonNull(request, "request");
InternalSession session = InternalSession.from(request.getSession());
try {
VersionResult res = repositorySystem.resolveVersion(
session.getSession(),
new VersionRequest(
session.toArtifact(request.getArtifactCoordinate()),
session.toRepositories(session.getRemoteRepositories()),
null));
return new VersionResolverResult() {
@Override
public List<Exception> getExceptions() {
return res.getExceptions();
}
@Override
public Version getVersion() {
return session.parseVersion(res.getVersion());
}
@Override
public Optional<Repository> getRepository() {
if (res.getRepository() instanceof org.eclipse.aether.repository.LocalRepository) {
return Optional.of(new DefaultLocalRepository(
(org.eclipse.aether.repository.LocalRepository) res.getRepository()));
} else if (res.getRepository() instanceof org.eclipse.aether.repository.RemoteRepository) {
return Optional.of(new DefaultRemoteRepository(
(org.eclipse.aether.repository.RemoteRepository) res.getRepository()));
} else {
return Optional.empty();
}
}
};
} catch (VersionResolutionException e) {
throw new VersionResolverException("Unable to resolve version", e);
}
}
}