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.LinkedHashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.maven.RepositoryUtils;
27  import org.apache.maven.model.Dependency;
28  import org.apache.maven.model.Plugin;
29  import org.apache.maven.plugin.PluginResolutionException;
30  import org.codehaus.plexus.component.annotations.Component;
31  import org.codehaus.plexus.component.annotations.Requirement;
32  import org.codehaus.plexus.logging.Logger;
33  import org.eclipse.aether.DefaultRepositorySystemSession;
34  import org.eclipse.aether.RepositorySystem;
35  import org.eclipse.aether.RepositorySystemSession;
36  import org.eclipse.aether.RequestTrace;
37  import org.eclipse.aether.artifact.Artifact;
38  import org.eclipse.aether.artifact.DefaultArtifact;
39  import org.eclipse.aether.collection.CollectRequest;
40  import org.eclipse.aether.collection.DependencyCollectionException;
41  import org.eclipse.aether.collection.DependencyGraphTransformer;
42  import org.eclipse.aether.collection.DependencySelector;
43  import org.eclipse.aether.graph.DependencyFilter;
44  import org.eclipse.aether.graph.DependencyNode;
45  import org.eclipse.aether.graph.DependencyVisitor;
46  import org.eclipse.aether.repository.RemoteRepository;
47  import org.eclipse.aether.resolution.ArtifactDescriptorException;
48  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
49  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
50  import org.eclipse.aether.resolution.ArtifactRequest;
51  import org.eclipse.aether.resolution.ArtifactResolutionException;
52  import org.eclipse.aether.resolution.DependencyRequest;
53  import org.eclipse.aether.resolution.DependencyResolutionException;
54  import org.eclipse.aether.util.artifact.JavaScopes;
55  import org.eclipse.aether.util.filter.AndDependencyFilter;
56  import org.eclipse.aether.util.filter.ScopeDependencyFilter;
57  import org.eclipse.aether.util.graph.selector.AndDependencySelector;
58  import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
59  import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
60  
61  /**
62   * Assists in resolving the dependencies of a plugin. <strong>Warning:</strong> This is an internal utility class that
63   * is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or
64   * deleted without prior notice.
65   *
66   * @since 3.0
67   * @author Benjamin Bentmann
68   */
69  @Component( role = PluginDependenciesResolver.class )
70  public class DefaultPluginDependenciesResolver
71      implements PluginDependenciesResolver
72  {
73  
74      private static final String REPOSITORY_CONTEXT = "plugin";
75  
76      @Requirement
77      private Logger logger;
78  
79      @Requirement
80      private RepositorySystem repoSystem;
81  
82      private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
83      {
84          return new DefaultArtifact( plugin.getGroupId(), plugin.getArtifactId(), null, "jar", plugin.getVersion(),
85                                      session.getArtifactTypeRegistry().get( "maven-plugin" ) );
86      }
87  
88      public Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
89          throws PluginResolutionException
90      {
91          RequestTrace trace = RequestTrace.newChild( null, plugin );
92  
93          Artifact pluginArtifact = toArtifact( plugin, session );
94  
95          try
96          {
97              DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
98              pluginSession.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, false ) );
99  
100             ArtifactDescriptorRequest request =
101                 new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
102             request.setTrace( trace );
103             ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor( pluginSession, request );
104 
105             pluginArtifact = result.getArtifact();
106 
107             String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" );
108             if ( requiredMavenVersion != null )
109             {
110                 Map<String, String> props = new LinkedHashMap<>( pluginArtifact.getProperties() );
111                 props.put( "requiredMavenVersion", requiredMavenVersion );
112                 pluginArtifact = pluginArtifact.setProperties( props );
113             }
114         }
115         catch ( ArtifactDescriptorException e )
116         {
117             throw new PluginResolutionException( plugin, e );
118         }
119 
120         try
121         {
122             ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
123             request.setTrace( trace );
124             pluginArtifact = repoSystem.resolveArtifact( session, request ).getArtifact();
125         }
126         catch ( ArtifactResolutionException e )
127         {
128             throw new PluginResolutionException( plugin, e );
129         }
130 
131         return pluginArtifact;
132     }
133 
134     /**
135      * @since 3.3.0
136      */
137     public DependencyNode resolveCoreExtension( Plugin plugin, DependencyFilter dependencyFilter,
138                                                 List<RemoteRepository> repositories, RepositorySystemSession session )
139         throws PluginResolutionException
140     {
141         return resolveInternal( plugin, null /* pluginArtifact */, dependencyFilter, null /* transformer */,
142                                 repositories, session );
143     }
144 
145     public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
146                                    List<RemoteRepository> repositories, RepositorySystemSession session )
147         throws PluginResolutionException
148     {
149         return resolveInternal( plugin, pluginArtifact, dependencyFilter, new PlexusUtilsInjector(), repositories,
150                                 session );
151     }
152 
153     private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
154                                             DependencyGraphTransformer transformer,
155                                             List<RemoteRepository> repositories, RepositorySystemSession session )
156         throws PluginResolutionException
157     {
158         RequestTrace trace = RequestTrace.newChild( null, plugin );
159 
160         if ( pluginArtifact == null )
161         {
162             pluginArtifact = toArtifact( plugin, session );
163         }
164 
165         DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" );
166         DependencyFilter resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, dependencyFilter );
167 
168         DependencyNode node;
169 
170         try
171         {
172             DependencySelector selector =
173                 AndDependencySelector.newInstance( session.getDependencySelector(), new WagonExcluder() );
174 
175             transformer =
176                 ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(), transformer );
177 
178             DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
179             pluginSession.setDependencySelector( selector );
180             pluginSession.setDependencyGraphTransformer( transformer );
181 
182             CollectRequest request = new CollectRequest();
183             request.setRequestContext( REPOSITORY_CONTEXT );
184             request.setRepositories( repositories );
185             request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ) );
186             for ( Dependency dependency : plugin.getDependencies() )
187             {
188                 org.eclipse.aether.graph.Dependency pluginDep =
189                     RepositoryUtils.toDependency( dependency, session.getArtifactTypeRegistry() );
190                 if ( !JavaScopes.SYSTEM.equals( pluginDep.getScope() ) )
191                 {
192                     pluginDep = pluginDep.setScope( JavaScopes.RUNTIME );
193                 }
194                 request.addDependency( pluginDep );
195             }
196 
197             DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter );
198             depRequest.setTrace( trace );
199 
200             request.setTrace( RequestTrace.newChild( trace, depRequest ) );
201 
202             node = repoSystem.collectDependencies( pluginSession, request ).getRoot();
203 
204             if ( logger.isDebugEnabled() )
205             {
206                 node.accept( new GraphLogger() );
207             }
208 
209             depRequest.setRoot( node );
210             repoSystem.resolveDependencies( session, depRequest );
211         }
212         catch ( DependencyCollectionException e )
213         {
214             throw new PluginResolutionException( plugin, e );
215         }
216         catch ( DependencyResolutionException e )
217         {
218             throw new PluginResolutionException( plugin, e.getCause() );
219         }
220 
221         return node;
222     }
223 
224     class GraphLogger
225         implements DependencyVisitor
226     {
227 
228         private String indent = "";
229 
230         public boolean visitEnter( DependencyNode node )
231         {
232             StringBuilder buffer = new StringBuilder( 128 );
233             buffer.append( indent );
234             org.eclipse.aether.graph.Dependency dep = node.getDependency();
235             if ( dep != null )
236             {
237                 Artifact art = dep.getArtifact();
238 
239                 buffer.append( art );
240                 buffer.append( ':' ).append( dep.getScope() );
241             }
242 
243             logger.debug( buffer.toString() );
244             indent += "   ";
245             return true;
246         }
247 
248         public boolean visitLeave( DependencyNode node )
249         {
250             indent = indent.substring( 0, indent.length() - 3 );
251             return true;
252         }
253 
254     }
255 
256 }