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      public GoOfflineMojo(
85              MavenSession session,
86              BuildContext buildContext,
87              MavenProject project,
88              ResolverUtil resolverUtil,
89              ProjectBuilder projectBuilder,
90              ArtifactHandlerManager artifactHandlerManager) {
91          super(session, buildContext, project, resolverUtil, projectBuilder, artifactHandlerManager);
92      }
93  
94      /**
95       * Main entry into mojo. Gets the list of dependencies, resolves all that are not in the Reactor, and iterates
96       * through displaying the resolved versions.
97       *
98       * @throws MojoExecutionException with a message if an error occurs
99       */
100     @Override
101     protected void doExecute() throws MojoExecutionException {
102 
103         try {
104             final Set<Plugin> plugins = getProjectPlugins();
105 
106             for (Plugin plugin : plugins) {
107                 org.eclipse.aether.artifact.Artifact artifact =
108                         getResolverUtil().resolvePlugin(plugin);
109 
110                 logMessage("Resolved plugin: "
111                         + DependencyUtil.getFormattedFileName(RepositoryUtils.toArtifact(artifact), false));
112                 if (!excludeTransitive) {
113                     logMessage("Resolved plugin dependency:");
114                     List<org.eclipse.aether.artifact.Artifact> artifacts =
115                             getResolverUtil().resolveDependencies(plugin, getDependencyFilter());
116                     for (org.eclipse.aether.artifact.Artifact a : artifacts) {
117                         logMessage(
118                                 "      " + DependencyUtil.getFormattedFileName(RepositoryUtils.toArtifact(a), false));
119                     }
120                 }
121             }
122 
123             final List<org.eclipse.aether.artifact.Artifact> dependencies = resolveDependencyArtifacts();
124 
125             for (org.eclipse.aether.artifact.Artifact artifact : dependencies) {
126                 logMessage("Resolved dependency: "
127                         + DependencyUtil.getFormattedFileName(RepositoryUtils.toArtifact(artifact), false));
128             }
129 
130         } catch (ArtifactFilterException | ArtifactResolutionException | DependencyResolutionException e) {
131             throw new MojoExecutionException(e.getMessage(), e);
132         }
133     }
134 
135     private Predicate<Dependency> getDependencyFilter() {
136         if (excludeReactor) {
137             return new ExcludeReactorProjectsDependencyFilter(session.getProjects());
138         } else {
139             return __ -> true;
140         }
141     }
142 
143     private void logMessage(String message) {
144         if (isSilent()) {
145             getLog().debug(message);
146         } else {
147             getLog().info(message);
148         }
149     }
150 
151     /**
152      * This method resolves the dependency artifacts from the project.
153      *
154      * @return lis of resolved dependency artifacts
155      * @throws ArtifactFilterException in case of an error while filtering the artifacts
156      * @throws DependencyResolutionException in case of an error while resolving the artifacts
157      */
158     protected List<org.eclipse.aether.artifact.Artifact> resolveDependencyArtifacts()
159             throws ArtifactFilterException, DependencyResolutionException {
160         Collection<Dependency> dependencies = getProject().getDependencies();
161 
162         dependencies = filterDependencies(dependencies);
163 
164         Predicate<Dependency> excludeReactorProjectsDependencyFilter = d -> true;
165         if (this.excludeReactor) {
166             excludeReactorProjectsDependencyFilter = new ExcludeReactorProjectsDependencyFilter(session.getProjects());
167         }
168 
169         ArtifactTypeRegistry artifactTypeRegistry =
170                 session.getRepositorySession().getArtifactTypeRegistry();
171 
172         List<org.eclipse.aether.graph.Dependency> dependableCoordinates = dependencies.stream()
173                 .filter(excludeReactorProjectsDependencyFilter)
174                 .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
175                 .collect(Collectors.toList());
176 
177         List<org.eclipse.aether.graph.Dependency> managedDependencies = ofNullable(
178                         getProject().getDependencyManagement())
179                 .map(DependencyManagement::getDependencies)
180                 .map(list -> list.stream()
181                         .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
182                         .collect(Collectors.toList()))
183                 .orElse(null);
184 
185         return getResolverUtil()
186                 .resolveDependenciesForArtifact(
187                         RepositoryUtils.toArtifact(getProject().getArtifact()),
188                         dependableCoordinates,
189                         managedDependencies,
190                         getProject().getRemoteProjectRepositories());
191     }
192 
193     /**
194      * This method retrieve plugins list from the project.
195      *
196      * @return set of plugin used in project
197      */
198     private Set<Plugin> getProjectPlugins() {
199         Predicate<Plugin> pluginsFilter = new PluginsIncludeExcludeFilter(
200                 toList(includeGroupIds),
201                 toList(excludeGroupIds),
202                 toList(includeArtifactIds),
203                 toList(excludeArtifactIds));
204 
205         Predicate<Plugin> reactorExclusionFilter = plugin -> true;
206         if (excludeReactor) {
207             reactorExclusionFilter = new PluginsReactorExcludeFilter(session.getProjects());
208         }
209 
210         return getResolverUtil().getProjectPlugins(getProject()).stream()
211                 .filter(reactorExclusionFilter)
212                 .filter(pluginsFilter)
213                 .collect(Collectors.toSet());
214     }
215 
216     private List<String> toList(String list) {
217         if (list == null || list.isEmpty()) {
218             return Collections.emptyList();
219         }
220         return Arrays.asList(DependencyUtil.cleanToBeTokenizedString(list).split(","));
221     }
222 
223     private Collection<Dependency> filterDependencies(Collection<Dependency> deps) throws ArtifactFilterException {
224 
225         Set<Artifact> artifacts = createArtifactSetFromDependencies(deps);
226 
227         final FilterArtifacts filter = getArtifactsFilter();
228         artifacts = filter.filter(artifacts);
229 
230         return createDependencySetFromArtifacts(artifacts);
231     }
232 
233     private Set<Artifact> createArtifactSetFromDependencies(Collection<Dependency> deps) {
234         Set<Artifact> artifacts = new HashSet<>();
235         for (Dependency dep : deps) {
236             DefaultArtifactHandler handler = new DefaultArtifactHandler(dep.getType());
237             artifacts.add(new DefaultArtifact(
238                     dep.getGroupId(),
239                     dep.getArtifactId(),
240                     dep.getVersion(),
241                     dep.getScope(),
242                     dep.getType(),
243                     dep.getClassifier(),
244                     handler));
245         }
246         return artifacts;
247     }
248 
249     private Collection<Dependency> createDependencySetFromArtifacts(Set<Artifact> artifacts) {
250         Set<Dependency> dependencies = new HashSet<>();
251 
252         for (Artifact artifact : artifacts) {
253             Dependency d = new Dependency();
254             d.setGroupId(artifact.getGroupId());
255             d.setArtifactId(artifact.getArtifactId());
256             d.setVersion(artifact.getVersion());
257             d.setType(artifact.getType());
258             d.setClassifier(artifact.getClassifier());
259             d.setScope(artifact.getScope());
260             dependencies.add(d);
261         }
262 
263         return dependencies;
264     }
265 
266     /**
267      * @return {@link FilterArtifacts}
268      */
269     // TODO: refactor this to use Resolver API filters
270     protected FilterArtifacts getArtifactsFilter() {
271         final FilterArtifacts filter = new FilterArtifacts();
272 
273         if (excludeReactor) {
274             filter.addFilter(new ExcludeReactorProjectsArtifactFilter(session.getProjects(), getLog()));
275         }
276 
277         filter.addFilter(new ScopeFilter(
278                 DependencyUtil.cleanToBeTokenizedString(this.includeScope),
279                 DependencyUtil.cleanToBeTokenizedString(this.excludeScope)));
280 
281         filter.addFilter(new TypeFilter(
282                 DependencyUtil.cleanToBeTokenizedString(this.includeTypes),
283                 DependencyUtil.cleanToBeTokenizedString(this.excludeTypes)));
284 
285         filter.addFilter(new ClassifierFilter(
286                 DependencyUtil.cleanToBeTokenizedString(this.includeClassifiers),
287                 DependencyUtil.cleanToBeTokenizedString(this.excludeClassifiers)));
288 
289         filter.addFilter(new GroupIdFilter(
290                 DependencyUtil.cleanToBeTokenizedString(this.includeGroupIds),
291                 DependencyUtil.cleanToBeTokenizedString(this.excludeGroupIds)));
292 
293         filter.addFilter(new ArtifactIdFilter(
294                 DependencyUtil.cleanToBeTokenizedString(this.includeArtifactIds),
295                 DependencyUtil.cleanToBeTokenizedString(this.excludeArtifactIds)));
296 
297         return filter;
298     }
299 
300     @Override
301     protected ArtifactsFilter getMarkedArtifactFilter() {
302         return null;
303     }
304 }