View Javadoc
1   package org.apache.maven.plugin.internal;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Collection;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.maven.RepositoryUtils;
28  import org.apache.maven.model.Dependency;
29  import org.apache.maven.model.Plugin;
30  import org.apache.maven.plugin.PluginResolutionException;
31  import org.codehaus.plexus.component.annotations.Component;
32  import org.codehaus.plexus.component.annotations.Requirement;
33  import org.codehaus.plexus.logging.Logger;
34  import org.codehaus.plexus.util.StringUtils;
35  import org.eclipse.aether.DefaultRepositorySystemSession;
36  import org.eclipse.aether.RepositorySystem;
37  import org.eclipse.aether.RepositorySystemSession;
38  import org.eclipse.aether.RequestTrace;
39  import org.eclipse.aether.artifact.Artifact;
40  import org.eclipse.aether.artifact.DefaultArtifact;
41  import org.eclipse.aether.collection.CollectRequest;
42  import org.eclipse.aether.collection.DependencyCollectionException;
43  import org.eclipse.aether.collection.DependencyGraphTransformer;
44  import org.eclipse.aether.collection.DependencySelector;
45  import org.eclipse.aether.graph.DependencyFilter;
46  import org.eclipse.aether.graph.DependencyNode;
47  import org.eclipse.aether.graph.DependencyVisitor;
48  import org.eclipse.aether.repository.RemoteRepository;
49  import org.eclipse.aether.resolution.ArtifactDescriptorException;
50  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
51  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
52  import org.eclipse.aether.resolution.ArtifactRequest;
53  import org.eclipse.aether.resolution.ArtifactResolutionException;
54  import org.eclipse.aether.resolution.DependencyRequest;
55  import org.eclipse.aether.resolution.DependencyResolutionException;
56  import org.eclipse.aether.util.artifact.JavaScopes;
57  import org.eclipse.aether.util.filter.AndDependencyFilter;
58  import org.eclipse.aether.util.filter.ScopeDependencyFilter;
59  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
60  import org.eclipse.aether.util.graph.selector.AndDependencySelector;
61  import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
62  import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
63  
64  /**
65   * Assists in resolving the dependencies of a plugin. <strong>Warning:</strong> This is an internal utility class that
66   * is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or
67   * deleted without prior notice.
68   *
69   * @since 3.0
70   * @author Benjamin Bentmann
71   */
72  @Component( role = PluginDependenciesResolver.class )
73  public class DefaultPluginDependenciesResolver
74      implements PluginDependenciesResolver
75  {
76  
77      private static final String REPOSITORY_CONTEXT = "plugin";
78  
79      @Requirement
80      private Logger logger;
81  
82      @Requirement
83      private RepositorySystem repoSystem;
84  
85      private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
86      {
87          return new DefaultArtifact( plugin.getGroupId(), plugin.getArtifactId(), null, "jar", plugin.getVersion(),
88                                      session.getArtifactTypeRegistry().get( "maven-plugin" ) );
89      }
90  
91      public Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
92          throws PluginResolutionException
93      {
94          RequestTrace trace = RequestTrace.newChild( null, plugin );
95  
96          Artifact pluginArtifact = toArtifact( plugin, session );
97  
98          try
99          {
100             DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
101             pluginSession.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, false ) );
102 
103             ArtifactDescriptorRequest request =
104                 new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
105             request.setTrace( trace );
106             ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor( pluginSession, request );
107 
108             pluginArtifact = result.getArtifact();
109 
110             String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" );
111             if ( requiredMavenVersion != null )
112             {
113                 Map<String, String> props = new LinkedHashMap<>( pluginArtifact.getProperties() );
114                 props.put( "requiredMavenVersion", requiredMavenVersion );
115                 pluginArtifact = pluginArtifact.setProperties( props );
116             }
117         }
118         catch ( ArtifactDescriptorException e )
119         {
120             throw new PluginResolutionException( plugin, e );
121         }
122 
123         try
124         {
125             ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
126             request.setTrace( trace );
127             pluginArtifact = repoSystem.resolveArtifact( session, request ).getArtifact();
128         }
129         catch ( ArtifactResolutionException e )
130         {
131             throw new PluginResolutionException( plugin, e );
132         }
133 
134         return pluginArtifact;
135     }
136 
137     /**
138      * @since 3.3.0
139      */
140     public DependencyNode resolveCoreExtension( Plugin plugin, DependencyFilter dependencyFilter,
141                                                 List<RemoteRepository> repositories, RepositorySystemSession session )
142         throws PluginResolutionException
143     {
144         return resolveInternal( plugin, null /* pluginArtifact */, dependencyFilter, null /* transformer */,
145                                 repositories, session );
146     }
147 
148     public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
149                                    List<RemoteRepository> repositories, RepositorySystemSession session )
150         throws PluginResolutionException
151     {
152         return resolveInternal( plugin, pluginArtifact, dependencyFilter, new PlexusUtilsInjector(), repositories,
153                                 session );
154     }
155 
156     private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
157                                             DependencyGraphTransformer transformer,
158                                             List<RemoteRepository> repositories, RepositorySystemSession session )
159         throws PluginResolutionException
160     {
161         RequestTrace trace = RequestTrace.newChild( null, plugin );
162 
163         if ( pluginArtifact == null )
164         {
165             pluginArtifact = toArtifact( plugin, session );
166         }
167 
168         DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" );
169         DependencyFilter resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, dependencyFilter );
170 
171         DependencyNode node;
172 
173         try
174         {
175             DependencySelector selector =
176                 AndDependencySelector.newInstance( session.getDependencySelector(), new WagonExcluder() );
177 
178             transformer =
179                 ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(), transformer );
180 
181             DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
182             pluginSession.setDependencySelector( selector );
183             pluginSession.setDependencyGraphTransformer( transformer );
184 
185             CollectRequest request = new CollectRequest();
186             request.setRequestContext( REPOSITORY_CONTEXT );
187             request.setRepositories( repositories );
188             request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ) );
189             for ( Dependency dependency : plugin.getDependencies() )
190             {
191                 org.eclipse.aether.graph.Dependency pluginDep =
192                     RepositoryUtils.toDependency( dependency, session.getArtifactTypeRegistry() );
193                 if ( !JavaScopes.SYSTEM.equals( pluginDep.getScope() ) )
194                 {
195                     pluginDep = pluginDep.setScope( JavaScopes.RUNTIME );
196                 }
197                 request.addDependency( pluginDep );
198             }
199 
200             DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter );
201             depRequest.setTrace( trace );
202 
203             request.setTrace( RequestTrace.newChild( trace, depRequest ) );
204 
205             node = repoSystem.collectDependencies( pluginSession, request ).getRoot();
206 
207             if ( logger.isDebugEnabled() )
208             {
209                 node.accept( new GraphLogger() );
210             }
211 
212             depRequest.setRoot( node );
213             repoSystem.resolveDependencies( session, depRequest );
214         }
215         catch ( DependencyCollectionException e )
216         {
217             throw new PluginResolutionException( plugin, e );
218         }
219         catch ( DependencyResolutionException e )
220         {
221             throw new PluginResolutionException( plugin, e.getCause() );
222         }
223 
224         return node;
225     }
226 
227     // Keep this class in sync with org.apache.maven.project.DefaultProjectDependenciesResolver.GraphLogger
228     class GraphLogger
229         implements DependencyVisitor
230     {
231 
232         private String indent = "";
233 
234         public boolean visitEnter( DependencyNode node )
235         {
236             StringBuilder buffer = new StringBuilder( 128 );
237             buffer.append( indent );
238             org.eclipse.aether.graph.Dependency dep = node.getDependency();
239             if ( dep != null )
240             {
241                 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
242 
243                 buffer.append( art );
244                 if ( StringUtils.isNotEmpty( dep.getScope() ) )
245                 {
246                     buffer.append( ':' ).append( dep.getScope() );
247                 }
248 
249                 if ( dep.isOptional() )
250                 {
251                     buffer.append( " (optional)" );
252                 }
253 
254                 // TODO We currently cannot tell which <dependencyManagement> section contained the management
255                 //      information. When the resolver provides this information, these log messages should be updated
256                 //      to contain it.
257                 if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) == DependencyNode.MANAGED_SCOPE )
258                 {
259                     final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node );
260                     buffer.append( " (scope managed from " );
261                     buffer.append( StringUtils.defaultString( premanagedScope, "default" ) );
262                     buffer.append( ')' );
263                 }
264 
265                 if ( ( node.getManagedBits() & DependencyNode.MANAGED_VERSION ) == DependencyNode.MANAGED_VERSION )
266                 {
267                     final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node );
268                     buffer.append( " (version managed from " );
269                     buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) );
270                     buffer.append( ')' );
271                 }
272 
273                 if ( ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) == DependencyNode.MANAGED_OPTIONAL )
274                 {
275                     final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node );
276                     buffer.append( " (optionality managed from " );
277                     buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) );
278                     buffer.append( ')' );
279                 }
280 
281                 if ( ( node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS )
282                          == DependencyNode.MANAGED_EXCLUSIONS )
283                 {
284                     final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
285                         DependencyManagerUtils.getPremanagedExclusions( node );
286 
287                     buffer.append( " (exclusions managed from " );
288                     buffer.append( StringUtils.defaultString( premanagedExclusions, "default" ) );
289                     buffer.append( ')' );
290                 }
291 
292                 if ( ( node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES )
293                          == DependencyNode.MANAGED_PROPERTIES )
294                 {
295                     final Map<String, String> premanagedProperties =
296                         DependencyManagerUtils.getPremanagedProperties( node );
297 
298                     buffer.append( " (properties managed from " );
299                     buffer.append( StringUtils.defaultString( premanagedProperties, "default" ) );
300                     buffer.append( ')' );
301                 }
302             }
303 
304             logger.debug( buffer.toString() );
305             indent += "   ";
306             return true;
307         }
308 
309         public boolean visitLeave( DependencyNode node )
310         {
311             indent = indent.substring( 0, indent.length() - 3 );
312             return true;
313         }
314 
315     }
316 
317 }