View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.dependency.resolvers;
20  
21  import javax.inject.Inject;
22  
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  import java.util.function.Predicate;
30  import java.util.stream.Collectors;
31  
32  import org.apache.maven.RepositoryUtils;
33  import org.apache.maven.artifact.Artifact;
34  import org.apache.maven.artifact.DefaultArtifact;
35  import org.apache.maven.artifact.handler.DefaultArtifactHandler;
36  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
37  import org.apache.maven.execution.MavenSession;
38  import org.apache.maven.model.Dependency;
39  import org.apache.maven.model.DependencyManagement;
40  import org.apache.maven.model.Plugin;
41  import org.apache.maven.plugin.MojoExecutionException;
42  import org.apache.maven.plugins.annotations.Mojo;
43  import org.apache.maven.plugins.annotations.Parameter;
44  import org.apache.maven.plugins.dependency.fromDependencies.AbstractDependencyFilterMojo;
45  import org.apache.maven.plugins.dependency.utils.DependencyUtil;
46  import org.apache.maven.plugins.dependency.utils.ResolverUtil;
47  import org.apache.maven.project.MavenProject;
48  import org.apache.maven.project.ProjectBuilder;
49  import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
50  import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter;
51  import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
52  import org.apache.maven.shared.artifact.filter.collection.ClassifierFilter;
53  import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
54  import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter;
55  import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
56  import org.apache.maven.shared.artifact.filter.collection.TypeFilter;
57  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
58  import org.eclipse.aether.resolution.ArtifactResolutionException;
59  import org.eclipse.aether.resolution.DependencyResolutionException;
60  import org.sonatype.plexus.build.incremental.BuildContext;
61  
62  import static java.util.Optional.ofNullable;
63  
64  /**
65   * Goal that resolves all project dependencies, including plugins and reports and their dependencies.
66   *
67   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
68   * @author Maarten Mulders
69   * @author Lisa Hardy
70   * @since 2.0
71   */
72  @Mojo(name = "go-offline", threadSafe = true)
73  public class GoOfflineMojo extends AbstractDependencyFilterMojo {
74  
75      /**
76       * Don't resolve plugins and artifacts that are in the current reactor.
77       *
78       * @since 2.7
79       */
80      @Parameter(property = "excludeReactor", defaultValue = "true")
81      protected boolean excludeReactor;
82  
83      @Inject
84      // CHECKSTYLE_OFF: ParameterNumber
85      public GoOfflineMojo(
86              MavenSession session,
87              BuildContext buildContext,
88              MavenProject project,
89              ResolverUtil resolverUtil,
90              ProjectBuilder projectBuilder,
91              ArtifactHandlerManager artifactHandlerManager) {
92          super(session, buildContext, project, resolverUtil, projectBuilder, artifactHandlerManager);
93      }
94      // CHECKSTYLE_ON: ParameterNumber
95  
96      /**
97       * Main entry into mojo. Gets the list of dependencies, resolves all that are not in the Reactor, and iterates
98       * through displaying the resolved versions.
99       *
100      * @throws MojoExecutionException with a message if an error occurs
101      */
102     @Override
103     protected void doExecute() throws MojoExecutionException {
104 
105         try {
106             final Set<Plugin> plugins = getProjectPlugins();
107 
108             for (Plugin plugin : plugins) {
109                 org.eclipse.aether.artifact.Artifact artifact =
110                         getResolverUtil().resolvePlugin(plugin);
111 
112                 logMessage("Resolved plugin: "
113                         + DependencyUtil.getFormattedFileName(RepositoryUtils.toArtifact(artifact), false));
114                 if (!excludeTransitive) {
115                     logMessage("Resolved plugin dependency:");
116                     List<org.eclipse.aether.artifact.Artifact> artifacts =
117                             getResolverUtil().resolveDependencies(plugin);
118                     for (org.eclipse.aether.artifact.Artifact a : artifacts) {
119                         logMessage(
120                                 "      " + DependencyUtil.getFormattedFileName(RepositoryUtils.toArtifact(a), false));
121                     }
122                 }
123             }
124 
125             final List<org.eclipse.aether.artifact.Artifact> dependencies = resolveDependencyArtifacts();
126 
127             for (org.eclipse.aether.artifact.Artifact artifact : dependencies) {
128                 logMessage("Resolved dependency: "
129                         + DependencyUtil.getFormattedFileName(RepositoryUtils.toArtifact(artifact), false));
130             }
131 
132         } catch (ArtifactFilterException | ArtifactResolutionException | DependencyResolutionException e) {
133             throw new MojoExecutionException(e.getMessage(), e);
134         }
135     }
136 
137     private void logMessage(String message) {
138         if (isSilent()) {
139             getLog().debug(message);
140         } else {
141             getLog().info(message);
142         }
143     }
144 
145     /**
146      * This method resolves the dependency artifacts from the project.
147      *
148      * @return lis of resolved dependency artifacts
149      * @throws ArtifactFilterException in case of an error while filtering the artifacts
150      * @throws DependencyResolutionException in case of an error while resolving the artifacts
151      */
152     protected List<org.eclipse.aether.artifact.Artifact> resolveDependencyArtifacts()
153             throws ArtifactFilterException, DependencyResolutionException {
154         Collection<Dependency> dependencies = getProject().getDependencies();
155 
156         dependencies = filterDependencies(dependencies);
157 
158         Predicate<Dependency> excludeReactorProjectsDependencyFilter = d -> true;
159         if (this.excludeReactor) {
160             excludeReactorProjectsDependencyFilter = new ExcludeReactorProjectsDependencyFilter(this.reactorProjects);
161         }
162 
163         ArtifactTypeRegistry artifactTypeRegistry =
164                 session.getRepositorySession().getArtifactTypeRegistry();
165 
166         List<org.eclipse.aether.graph.Dependency> dependableCoordinates = dependencies.stream()
167                 .filter(excludeReactorProjectsDependencyFilter)
168                 .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
169                 .collect(Collectors.toList());
170 
171         List<org.eclipse.aether.graph.Dependency> managedDependencies = ofNullable(
172                         getProject().getDependencyManagement())
173                 .map(DependencyManagement::getDependencies)
174                 .map(list -> list.stream()
175                         .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
176                         .collect(Collectors.toList()))
177                 .orElse(null);
178 
179         return getResolverUtil()
180                 .resolveDependenciesForArtifact(
181                         RepositoryUtils.toArtifact(getProject().getArtifact()),
182                         dependableCoordinates,
183                         managedDependencies,
184                         getProject().getRemoteProjectRepositories());
185     }
186 
187     /**
188      * This method retrieve plugins list from the project.
189      *
190      * @return set of plugin used in project
191      */
192     private Set<Plugin> getProjectPlugins() {
193         Predicate<Plugin> pluginsFilter = new PluginsIncludeExcludeFilter(
194                 toList(includeGroupIds),
195                 toList(excludeGroupIds),
196                 toList(includeArtifactIds),
197                 toList(excludeArtifactIds));
198 
199         Predicate<Plugin> reactorExclusionFilter = plugin -> true;
200         if (excludeReactor) {
201             reactorExclusionFilter = new PluginsReactorExcludeFilter(session.getProjects());
202         }
203 
204         return getResolverUtil().getProjectPlugins(getProject()).stream()
205                 .filter(reactorExclusionFilter)
206                 .filter(pluginsFilter)
207                 .collect(Collectors.toSet());
208     }
209 
210     private List<String> toList(String list) {
211         if (list == null || list.isEmpty()) {
212             return Collections.emptyList();
213         }
214         return Arrays.asList(DependencyUtil.cleanToBeTokenizedString(list).split(","));
215     }
216 
217     private Collection<Dependency> filterDependencies(Collection<Dependency> deps) throws ArtifactFilterException {
218 
219         Set<Artifact> artifacts = createArtifactSetFromDependencies(deps);
220 
221         final FilterArtifacts filter = getArtifactsFilter();
222         artifacts = filter.filter(artifacts);
223 
224         return createDependencySetFromArtifacts(artifacts);
225     }
226 
227     private Set<Artifact> createArtifactSetFromDependencies(Collection<Dependency> deps) {
228         Set<Artifact> artifacts = new HashSet<>();
229         for (Dependency dep : deps) {
230             DefaultArtifactHandler handler = new DefaultArtifactHandler(dep.getType());
231             artifacts.add(new DefaultArtifact(
232                     dep.getGroupId(),
233                     dep.getArtifactId(),
234                     dep.getVersion(),
235                     dep.getScope(),
236                     dep.getType(),
237                     dep.getClassifier(),
238                     handler));
239         }
240         return artifacts;
241     }
242 
243     private Collection<Dependency> createDependencySetFromArtifacts(Set<Artifact> artifacts) {
244         Set<Dependency> dependencies = new HashSet<>();
245 
246         for (Artifact artifact : artifacts) {
247             Dependency d = new Dependency();
248             d.setGroupId(artifact.getGroupId());
249             d.setArtifactId(artifact.getArtifactId());
250             d.setVersion(artifact.getVersion());
251             d.setType(artifact.getType());
252             d.setClassifier(artifact.getClassifier());
253             d.setScope(artifact.getScope());
254             dependencies.add(d);
255         }
256 
257         return dependencies;
258     }
259 
260     /**
261      * @return {@link FilterArtifacts}
262      */
263     // TODO: refactor this to use Resolver API filters
264     protected FilterArtifacts getArtifactsFilter() {
265         final FilterArtifacts filter = new FilterArtifacts();
266 
267         if (excludeReactor) {
268             filter.addFilter(new ExcludeReactorProjectsArtifactFilter(reactorProjects, getLog()));
269         }
270 
271         filter.addFilter(new ScopeFilter(
272                 DependencyUtil.cleanToBeTokenizedString(this.includeScope),
273                 DependencyUtil.cleanToBeTokenizedString(this.excludeScope)));
274 
275         filter.addFilter(new TypeFilter(
276                 DependencyUtil.cleanToBeTokenizedString(this.includeTypes),
277                 DependencyUtil.cleanToBeTokenizedString(this.excludeTypes)));
278 
279         filter.addFilter(new ClassifierFilter(
280                 DependencyUtil.cleanToBeTokenizedString(this.includeClassifiers),
281                 DependencyUtil.cleanToBeTokenizedString(this.excludeClassifiers)));
282 
283         filter.addFilter(new GroupIdFilter(
284                 DependencyUtil.cleanToBeTokenizedString(this.includeGroupIds),
285                 DependencyUtil.cleanToBeTokenizedString(this.excludeGroupIds)));
286 
287         filter.addFilter(new ArtifactIdFilter(
288                 DependencyUtil.cleanToBeTokenizedString(this.includeArtifactIds),
289                 DependencyUtil.cleanToBeTokenizedString(this.excludeArtifactIds)));
290 
291         return filter;
292     }
293 
294     @Override
295     protected ArtifactsFilter getMarkedArtifactFilter() {
296         return null;
297     }
298 }