001 package org.apache.maven.plugin.internal;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.util.LinkedHashMap;
023 import java.util.List;
024 import java.util.Map;
025
026 import org.apache.maven.ArtifactFilterManager;
027 import org.apache.maven.RepositoryUtils;
028 import org.apache.maven.model.Dependency;
029 import org.apache.maven.model.Plugin;
030 import org.apache.maven.plugin.PluginResolutionException;
031 import org.codehaus.plexus.component.annotations.Component;
032 import org.codehaus.plexus.component.annotations.Requirement;
033 import org.codehaus.plexus.logging.Logger;
034 import org.sonatype.aether.RepositorySystem;
035 import org.sonatype.aether.RepositorySystemSession;
036 import org.sonatype.aether.RequestTrace;
037 import org.sonatype.aether.artifact.Artifact;
038 import org.sonatype.aether.collection.CollectRequest;
039 import org.sonatype.aether.collection.DependencyCollectionException;
040 import org.sonatype.aether.collection.DependencyGraphTransformer;
041 import org.sonatype.aether.collection.DependencySelector;
042 import org.sonatype.aether.graph.DependencyFilter;
043 import org.sonatype.aether.graph.DependencyNode;
044 import org.sonatype.aether.graph.DependencyVisitor;
045 import org.sonatype.aether.repository.RemoteRepository;
046 import org.sonatype.aether.resolution.ArtifactDescriptorException;
047 import org.sonatype.aether.resolution.ArtifactDescriptorRequest;
048 import org.sonatype.aether.resolution.ArtifactDescriptorResult;
049 import org.sonatype.aether.resolution.ArtifactRequest;
050 import org.sonatype.aether.resolution.ArtifactResolutionException;
051 import org.sonatype.aether.resolution.DependencyRequest;
052 import org.sonatype.aether.resolution.DependencyResolutionException;
053 import org.sonatype.aether.util.DefaultRepositorySystemSession;
054 import org.sonatype.aether.util.DefaultRequestTrace;
055 import org.sonatype.aether.util.FilterRepositorySystemSession;
056 import org.sonatype.aether.util.artifact.DefaultArtifact;
057 import org.sonatype.aether.util.artifact.JavaScopes;
058 import org.sonatype.aether.util.filter.AndDependencyFilter;
059 import org.sonatype.aether.util.filter.ExclusionsDependencyFilter;
060 import org.sonatype.aether.util.filter.ScopeDependencyFilter;
061 import org.sonatype.aether.util.graph.selector.AndDependencySelector;
062 import org.sonatype.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
063
064 /**
065 * Assists in resolving the dependencies of a plugin. <strong>Warning:</strong> This is an internal utility class that
066 * is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or
067 * deleted without prior notice.
068 *
069 * @since 3.0
070 * @author Benjamin Bentmann
071 */
072 @Component( role = PluginDependenciesResolver.class )
073 public class DefaultPluginDependenciesResolver
074 implements PluginDependenciesResolver
075 {
076
077 private static final String REPOSITORY_CONTEXT = "plugin";
078
079 @Requirement
080 private Logger logger;
081
082 @Requirement
083 private ArtifactFilterManager artifactFilterManager;
084
085 @Requirement
086 private RepositorySystem repoSystem;
087
088 private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
089 {
090 return new DefaultArtifact( plugin.getGroupId(), plugin.getArtifactId(), null, "jar", plugin.getVersion(),
091 session.getArtifactTypeRegistry().get( "maven-plugin" ) );
092 }
093
094 public Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
095 throws PluginResolutionException
096 {
097 RequestTrace trace = DefaultRequestTrace.newChild( null, plugin );
098
099 Artifact pluginArtifact = toArtifact( plugin, session );
100
101 try
102 {
103 RepositorySystemSession pluginSession = new FilterRepositorySystemSession( session )
104 {
105 @Override
106 public boolean isIgnoreMissingArtifactDescriptor()
107 {
108 return false;
109 }
110 };
111
112 ArtifactDescriptorRequest request =
113 new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
114 request.setTrace( trace );
115 ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor( pluginSession, request );
116
117 pluginArtifact = result.getArtifact();
118
119 String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" );
120 if ( requiredMavenVersion != null )
121 {
122 Map<String, String> props = new LinkedHashMap<String, String>( pluginArtifact.getProperties() );
123 props.put( "requiredMavenVersion", requiredMavenVersion );
124 pluginArtifact = pluginArtifact.setProperties( props );
125 }
126 }
127 catch ( ArtifactDescriptorException e )
128 {
129 throw new PluginResolutionException( plugin, e );
130 }
131
132 try
133 {
134 ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
135 request.setTrace( trace );
136 pluginArtifact = repoSystem.resolveArtifact( session, request ).getArtifact();
137 }
138 catch ( ArtifactResolutionException e )
139 {
140 throw new PluginResolutionException( plugin, e );
141 }
142
143 return pluginArtifact;
144 }
145
146 public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
147 List<RemoteRepository> repositories, RepositorySystemSession session )
148 throws PluginResolutionException
149 {
150 RequestTrace trace = DefaultRequestTrace.newChild( null, plugin );
151
152 if ( pluginArtifact == null )
153 {
154 pluginArtifact = toArtifact( plugin, session );
155 }
156
157 DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" );
158
159 DependencyFilter resolutionFilter =
160 new ExclusionsDependencyFilter( artifactFilterManager.getCoreArtifactExcludes() );
161 resolutionFilter = AndDependencyFilter.newInstance( resolutionFilter, dependencyFilter );
162 resolutionFilter = new AndDependencyFilter( collectionFilter, resolutionFilter );
163
164 DependencyNode node;
165
166 try
167 {
168 DependencySelector selector =
169 AndDependencySelector.newInstance( session.getDependencySelector(), new WagonExcluder() );
170
171 DependencyGraphTransformer transformer =
172 ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(),
173 new PlexusUtilsInjector() );
174
175 DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
176 pluginSession.setDependencySelector( selector );
177 pluginSession.setDependencyGraphTransformer( transformer );
178
179 CollectRequest request = new CollectRequest();
180 request.setRequestContext( REPOSITORY_CONTEXT );
181 request.setRepositories( repositories );
182 request.setRoot( new org.sonatype.aether.graph.Dependency( pluginArtifact, null ) );
183 for ( Dependency dependency : plugin.getDependencies() )
184 {
185 org.sonatype.aether.graph.Dependency pluginDep =
186 RepositoryUtils.toDependency( dependency, session.getArtifactTypeRegistry() );
187 if ( !JavaScopes.SYSTEM.equals( pluginDep.getScope() ) )
188 {
189 pluginDep = pluginDep.setScope( JavaScopes.RUNTIME );
190 }
191 request.addDependency( pluginDep );
192 }
193
194 DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter );
195 depRequest.setTrace( trace );
196
197 request.setTrace( DefaultRequestTrace.newChild( trace, depRequest ) );
198
199 node = repoSystem.collectDependencies( pluginSession, request ).getRoot();
200
201 if ( logger.isDebugEnabled() )
202 {
203 node.accept( new GraphLogger() );
204 }
205
206 depRequest.setRoot( node );
207 repoSystem.resolveDependencies( session, depRequest );
208 }
209 catch ( DependencyCollectionException e )
210 {
211 throw new PluginResolutionException( plugin, e );
212 }
213 catch ( DependencyResolutionException e )
214 {
215 throw new PluginResolutionException( plugin, e.getCause() );
216 }
217
218 return node;
219 }
220
221 class GraphLogger
222 implements DependencyVisitor
223 {
224
225 private String indent = "";
226
227 public boolean visitEnter( DependencyNode node )
228 {
229 StringBuilder buffer = new StringBuilder( 128 );
230 buffer.append( indent );
231 org.sonatype.aether.graph.Dependency dep = node.getDependency();
232 if ( dep != null )
233 {
234 org.sonatype.aether.artifact.Artifact art = dep.getArtifact();
235
236 buffer.append( art );
237 buffer.append( ':' ).append( dep.getScope() );
238
239 if ( node.getPremanagedScope() != null && !node.getPremanagedScope().equals( dep.getScope() ) )
240 {
241 buffer.append( " (scope managed from " ).append( node.getPremanagedScope() ).append( ")" );
242 }
243
244 if ( node.getPremanagedVersion() != null && !node.getPremanagedVersion().equals( art.getVersion() ) )
245 {
246 buffer.append( " (version managed from " ).append( node.getPremanagedVersion() ).append( ")" );
247 }
248 }
249
250 logger.debug( buffer.toString() );
251 indent += " ";
252 return true;
253 }
254
255 public boolean visitLeave( DependencyNode node )
256 {
257 indent = indent.substring( 0, indent.length() - 3 );
258 return true;
259 }
260
261 }
262
263 }