com.redhat.ceylon.cmr.resolver.aether.AetherResolverImpl Maven / Gradle / Ivy
/*
* Copyright 2011 Red Hat inc. and third party contributors as noted
* by the author tags.
* Licensed 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 com.redhat.ceylon.cmr.resolver.aether;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.apache.maven.settings.Activation;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Profile;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Repository;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.building.DefaultSettingsBuilder;
import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
import org.apache.maven.settings.building.SettingsBuildingException;
import org.apache.maven.settings.building.SettingsBuildingRequest;
import org.apache.maven.settings.building.SettingsBuildingResult;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.aether.ConfigurationProperties;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.collection.DependencyCollectionContext;
import org.eclipse.aether.collection.DependencySelector;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.graph.DefaultDependencyNode;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import org.eclipse.aether.resolution.VersionRangeResult;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.HttpTransporterFactory;
import org.eclipse.aether.util.artifact.JavaScopes;
import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
import org.eclipse.aether.util.repository.DefaultMirrorSelector;
import org.eclipse.aether.util.repository.DefaultProxySelector;
import org.eclipse.aether.version.Version;
/**
* Aether utils.
*
* @author Ales Justin
*/
public class AetherResolverImpl implements AetherResolver {
private String currentDirectory;
private int timeout;
private boolean offline;
private String settingsXml;
private static RepositorySystem newRepositorySystem() {
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
locator.addService( RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class );
locator.addService( TransporterFactory.class, FileTransporterFactory.class );
locator.addService( TransporterFactory.class, HttpTransporterFactory.class );
return locator.getService( RepositorySystem.class );
}
private DefaultRepositorySystemSession newSession( RepositorySystem system ) {
return MavenRepositorySystemUtils.newSession();
}
private List configureSession(RepositorySystem system, DefaultRepositorySystemSession session){
DefaultSettingsBuilderFactory factory = new DefaultSettingsBuilderFactory();
DefaultSettingsBuilder builder = factory.newInstance();
SettingsBuildingRequest settingsBuilderRequest = new DefaultSettingsBuildingRequest();
settingsBuilderRequest.setSystemProperties(System.getProperties());
// find the settings
String settingsFile = settingsXml;
if(settingsFile == null){
File userSettings = new File(System.getProperty("user.home"), ".m2/settings.xml");
if(userSettings.exists())
settingsFile = userSettings.getAbsolutePath();
}
if(settingsFile != null){
settingsBuilderRequest.setUserSettingsFile(new File(settingsXml));
}
// read it
SettingsBuildingResult settingsBuildingResult;
try {
settingsBuildingResult = builder.build(settingsBuilderRequest);
} catch (SettingsBuildingException e) {
throw new RuntimeException(e);
}
Settings set = settingsBuildingResult.getEffectiveSettings();
// configure the local repo
String localRepository = set.getLocalRepository();
if(localRepository == null)
localRepository = System.getProperty("user.home")+File.separator+".m2"+File.separator+"repository";
else {
if (! new File(localRepository).isAbsolute() && currentDirectory != null) {
localRepository = new File(new File(currentDirectory), localRepository).getAbsolutePath();
}
}
// set up authentication
DefaultAuthenticationSelector authenticationSelector = new DefaultAuthenticationSelector();
for(Server server : set.getServers()){
AuthenticationBuilder auth = new AuthenticationBuilder();
if(server.getUsername() != null)
auth.addUsername(server.getUsername());
if(server.getPassword() != null)
auth.addPassword(server.getPassword());
if(server.getPrivateKey() != null)
auth.addPrivateKey(server.getPrivateKey(), server.getPassphrase());
authenticationSelector.add(server.getId(), auth.build());
}
session.setAuthenticationSelector(authenticationSelector );
// set up mirrors
DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
for(Mirror mirror : set.getMirrors()){
mirrorSelector.add(mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.getMirrorOf(), mirror.getMirrorOfLayouts());
}
session.setMirrorSelector(mirrorSelector);
// set up proxies
DefaultProxySelector proxySelector = new DefaultProxySelector();
for(Proxy proxy : set.getProxies()){
if(proxy.isActive()){
AuthenticationBuilder auth = new AuthenticationBuilder();
if(proxy.getUsername() != null)
auth.addUsername(proxy.getUsername());
if(proxy.getPassword() != null)
auth.addPassword(proxy.getPassword());
org.eclipse.aether.repository.Proxy p = new org.eclipse.aether.repository.Proxy(proxy.getProtocol(), proxy.getHost(),
proxy.getPort(), auth.build() );
proxySelector.add(p , proxy.getNonProxyHosts());
}
}
session.setProxySelector(proxySelector);
// set up remote repos
List repos = new ArrayList<>();
RemoteRepository central = new RemoteRepository.Builder( "central", "default", "http://repo1.maven.org/maven2/" ).build();
repos.add(central);
Set activeProfiles = new HashSet<>();
activeProfiles.addAll(set.getActiveProfiles());
for (Profile profile : set.getProfiles()) {
Activation activation = profile.getActivation();
if(activation != null){
if(activation.isActiveByDefault())
activeProfiles.add(profile.getId());
}
}
for(String profileId : activeProfiles){
Profile profile = set.getProfilesAsMap().get(profileId);
if(profile != null){
addReposFromProfile(repos, profile);
}
}
// connection settings
session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, timeout);
session.setOffline(offline || set.isOffline());
LocalRepository localRepo = new LocalRepository( localRepository );
session.setLocalRepositoryManager( system.newLocalRepositoryManager( session, localRepo ) );
return repos;
}
private void addReposFromProfile(List repos, Profile profile) {
for(Repository repo : profile.getRepositories()){
RemoteRepository.Builder remoteRepo = new RemoteRepository.Builder( repo.getId(), repo.getLayout(), repo.getUrl() );
// policies
org.apache.maven.settings.RepositoryPolicy repoReleasePolicy = repo.getReleases();
if(repoReleasePolicy != null){
String updatePolicy = repoReleasePolicy.getUpdatePolicy();
// This is the default anyway and saves us a message on STDERR
if(updatePolicy == null || updatePolicy.isEmpty())
updatePolicy = RepositoryPolicy.UPDATE_POLICY_NEVER;
RepositoryPolicy releasePolicy = new RepositoryPolicy(repoReleasePolicy.isEnabled(), updatePolicy,
repoReleasePolicy.getChecksumPolicy());
remoteRepo.setReleasePolicy(releasePolicy );
}
org.apache.maven.settings.RepositoryPolicy repoSnapshotPolicy = repo.getSnapshots();
if(repoSnapshotPolicy != null){
String updatePolicy = repoSnapshotPolicy.getUpdatePolicy();
// This is the default anyway and saves us a message on STDERR
if(updatePolicy == null || updatePolicy.isEmpty())
updatePolicy = RepositoryPolicy.UPDATE_POLICY_NEVER;
RepositoryPolicy snapshotPolicy = new RepositoryPolicy(repoSnapshotPolicy.isEnabled(), updatePolicy,
repoSnapshotPolicy.getChecksumPolicy());
remoteRepo.setSnapshotPolicy(snapshotPolicy);
}
// auth, proxy and mirrors are done in the session
repos.add(remoteRepo.build());
}
}
private static final DependencySelector NoChildSelector = new DependencySelector(){
@Override
public DependencySelector deriveChildSelector(DependencyCollectionContext arg0) {
return this;
}
@Override
public boolean selectDependency(Dependency arg0) {
return false;
}
};
public AetherResolverImpl(String currentDirectory, String settingsXml, boolean offline, int timeout) {
this.currentDirectory = currentDirectory;
this.timeout = timeout;
this.offline = offline;
this.settingsXml = settingsXml;
}
@Override
public DependencyDescriptor getDependencies(String groupId, String artifactId, String version, boolean fetchSingleArtifact)
throws AetherException{
// null extension means auto-detect based on pom
return getDependencies(groupId, artifactId, version, null, null, fetchSingleArtifact);
}
public File getLocalRepositoryBaseDir() {
RepositorySystem repoSystem = newRepositorySystem();
DefaultRepositorySystemSession session = newSession( repoSystem );
configureSession(repoSystem, session);
return session.getLocalRepository().getBasedir();
}
@Override
public DependencyDescriptor getDependencies(String groupId, String artifactId, String version,
String classifier, String extension, boolean fetchSingleArtifact)
throws AetherException{
RepositorySystem repoSystem = newRepositorySystem();
DefaultRepositorySystemSession session = newSession( repoSystem );
List repos = configureSession(repoSystem, session);
// TODO figure out how to map this to ArtifactCallback
// session.setTransferListener(new TransferListener(){
//
// @Override
// public void transferCorrupted(TransferEvent arg0) throws TransferCancelledException {
// System.err.println("Transfer corrupted "+arg0.getResource());
// }
//
// @Override
// public void transferFailed(TransferEvent arg0) {
// System.err.println("Transfer failed "+arg0.getResource());
// }
//
// @Override
// public void transferInitiated(TransferEvent arg0) throws TransferCancelledException {
// System.err.println("Transfer initiated "+arg0.getResource());
// }
//
// @Override
// public void transferProgressed(TransferEvent arg0) throws TransferCancelledException {
// System.err.println("Transfer progressed "+arg0.getResource());
// System.err.println("Data length: "+arg0.getDataLength());
// System.err.println("Transferred bytes: "+arg0.getTransferredBytes());
// }
//
// @Override
// public void transferStarted(TransferEvent arg0) throws TransferCancelledException {
// System.err.println("Transfer started "+arg0.getResource());
//
// }
//
// @Override
// public void transferSucceeded(TransferEvent arg0) {
// System.err.println("Transfer succeeded "+arg0.getResource());
//
// }});
Artifact pomResultArtifact = null;
// I don't think POMs with a classifier exist, so let's not set it
DefaultArtifact pomArtifact = new DefaultArtifact( groupId, artifactId, null, "pom", version);
if(extension == null){
try {
pomResultArtifact = resolveSingleArtifact(repoSystem, session, repos, pomArtifact);
} catch (ArtifactResolutionException e) {
throw new AetherException(e);
}
if(pomResultArtifact != null){
extension = findExtension(pomResultArtifact.getFile());
}
if(extension == null
// we only support jar/aar. ear/war/bundle will resolve as jar anyway
|| (!extension.equals("jar") && !extension.equals("aar")))
extension = "jar";
}
DefaultArtifact artifact = new DefaultArtifact( groupId, artifactId, classifier, extension, version);
DependencyNode ret = null;
if(!fetchSingleArtifact){
try {
ret = resolveArtifactWithDependencies(repoSystem, session, repos, artifact);
} catch (DependencyResolutionException e) {
if(!isTimeout(e) && pomResultArtifact == null)
throw new AetherException(e);
// try a jar-less module
}
if(ret == null){
try {
ret = resolveArtifactWithDependencies(repoSystem, session, repos, pomArtifact);
} catch (DependencyResolutionException e) {
throw new AetherException(e);
}
}
}else{
Artifact resultArtifact;
try {
resultArtifact = resolveSingleArtifact(repoSystem, session, repos, artifact);
} catch (ArtifactResolutionException e) {
if(!isTimeout(e) && pomResultArtifact == null)
throw new AetherException(e);
else // go with a jar-less module
resultArtifact = pomResultArtifact;
}
ret = new DefaultDependencyNode(resultArtifact);
}
return ret == null ? null : new DependencyNodeDependencyDescriptor(this, ret);
}
private boolean isTimeout(Throwable e) {
while(e.getCause() != null)
e = e.getCause();
// we can't use its real type since we don't import it
return e.getClass().getSimpleName().endsWith(".ConnectTimeoutException");
}
private DependencyNode resolveArtifactWithDependencies(RepositorySystem repoSystem,
DefaultRepositorySystemSession session,
List repos,
DefaultArtifact artifact)
throws DependencyResolutionException {
final Dependency dependency = new Dependency( artifact, JavaScopes.COMPILE );
CollectRequest collectRequest = new CollectRequest();
collectRequest.setRepositories(repos);
collectRequest.setRoot( dependency );
DependencyRequest dependencyRequest = new DependencyRequest();
dependencyRequest.setCollectRequest(collectRequest);
dependencyRequest.setFilter(new DependencyFilter(){
@Override
public boolean accept(DependencyNode dep, List parents) {
return parents.size() == 0;
}
});
// only get first-level dependencies, of both scopes
session.setDependencySelector(new DependencySelector(){
@Override
public DependencySelector deriveChildSelector(DependencyCollectionContext ctx) {
if(myEquals(ctx.getDependency(), dependency))
return this;
return NoChildSelector;
}
@Override
public boolean selectDependency(Dependency dep) {
// Not System, though we could support it
return JavaScopes.COMPILE.equals(dep.getScope())
|| JavaScopes.RUNTIME.equals(dep.getScope())
|| JavaScopes.PROVIDED.equals(dep.getScope())
// TEST is useless ATM and is nothing but trouble
// || JavaScopes.TEST.equals(dep.getScope())
;
}
});
return repoSystem.resolveDependencies( session, dependencyRequest ).getRoot();
}
private Artifact resolveSingleArtifact(RepositorySystem repoSystem,
DefaultRepositorySystemSession session,
List repos,
DefaultArtifact artifact) throws ArtifactResolutionException {
ArtifactRequest artifactRequest = new ArtifactRequest();
artifactRequest.setArtifact(artifact);
artifactRequest.setRepositories(repos);
return repoSystem.resolveArtifact(session, artifactRequest).getArtifact();
}
private boolean myEquals(Dependency a, Dependency b) {
if(a == null && b == null)
return true;
if(a == null || b == null)
return false;
return myEquals(a.getArtifact(), b.getArtifact())
&& a.isOptional() == b.isOptional()
&& Objects.equals(a.getScope(), b.getScope());
}
private boolean myEquals(Artifact a, Artifact b) {
if(a == null && b == null)
return true;
if(a == null || b == null)
return false;
// Don't use Artifact.equals because it compares Properties which we don't want
return Objects.equals(a.getArtifactId(), b.getArtifactId())
&& Objects.equals(a.getGroupId(), b.getGroupId())
&& Objects.equals(a.getVersion(), b.getVersion())
&& Objects.equals(a.getClassifier(), b.getClassifier())
&& Objects.equals(a.getExtension(), b.getExtension())
&& Objects.equals(a.getFile(), b.getFile())
;
}
private String findExtension(File pomFile) {
if(pomFile != null && pomFile.exists()){
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model;
try(FileReader fileReader = new FileReader(pomFile)){
model = reader.read(fileReader);
return model.getPackaging();
} catch (XmlPullParserException | IOException e) {
return null;
}
};
return null;
}
@Override
public List resolveVersionRange(String groupId, String artifactId, String versionRange) throws AetherException {
RepositorySystem repoSystem = newRepositorySystem();
DefaultRepositorySystemSession session = newSession( repoSystem );
List repos = configureSession(repoSystem, session);
Artifact artifact = new DefaultArtifact( groupId, artifactId, "jar", versionRange );
VersionRangeRequest rangeRequest = new VersionRangeRequest();
rangeRequest.setArtifact( artifact );
rangeRequest.setRepositories(repos);
VersionRangeResult rangeResult;
try {
rangeResult = repoSystem.resolveVersionRange( session, rangeRequest );
} catch (VersionRangeResolutionException e) {
throw new AetherException(e);
}
List ret = new ArrayList<>(rangeResult.getVersions().size());
for(Version version : rangeResult.getVersions())
ret.add(version.toString());
return ret;
}
@Override
public DependencyDescriptor getDependencies(File pomXml, String name, String version) throws IOException {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model;
try(FileReader fileReader = new FileReader(pomXml)){
model = reader.read(fileReader);
} catch (XmlPullParserException e) {
throw new IOException(e);
}
return new ModelDependencyDescriptor(model);
}
@Override
public DependencyDescriptor getDependencies(InputStream pomXml, String name, String version) throws IOException {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model;
try {
model = reader.read(pomXml);
} catch (XmlPullParserException e) {
throw new IOException(e);
}
return new ModelDependencyDescriptor(model);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy