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;
20  
21  import javax.inject.Inject;
22  
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Optional;
30  import java.util.Set;
31  import java.util.stream.Collectors;
32  
33  import org.apache.maven.RepositoryUtils;
34  import org.apache.maven.execution.MavenSession;
35  import org.apache.maven.model.DependencyManagement;
36  import org.apache.maven.plugin.MojoExecutionException;
37  import org.apache.maven.plugins.annotations.Mojo;
38  import org.apache.maven.project.MavenProject;
39  import org.eclipse.aether.RepositorySystem;
40  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
41  import org.eclipse.aether.collection.CollectRequest;
42  import org.eclipse.aether.collection.CollectResult;
43  import org.eclipse.aether.collection.DependencyCollectionException;
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.util.graph.visitor.TreeDependencyVisitor;
48  import org.sonatype.plexus.build.incremental.BuildContext;
49  
50  /**
51   * Goal that collects all project dependencies and then lists the repositories used by the build and by the transitive
52   * dependencies.
53   *
54   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
55   * @since 2.2
56   */
57  @Mojo(name = "list-repositories", threadSafe = true)
58  public class ListRepositoriesMojo extends AbstractDependencyMojo {
59  
60      private final RepositorySystem repositorySystem;
61  
62      @Inject
63      public ListRepositoriesMojo(
64              MavenSession session, BuildContext buildContext, MavenProject project, RepositorySystem repositorySystem) {
65          super(session, buildContext, project);
66          this.repositorySystem = repositorySystem;
67      }
68  
69      /**
70       * Displays a list of the repositories used by this build.
71       *
72       * @throws MojoExecutionException with a message if an error occurs
73       */
74      @Override
75      protected void doExecute() throws MojoExecutionException {
76  
77          CollectRequest request = new CollectRequest();
78          request.setRepositories(getProject().getRemoteProjectRepositories());
79          request.setRootArtifact(RepositoryUtils.toArtifact(getProject().getArtifact()));
80  
81          ArtifactTypeRegistry artifactTypeRegistry =
82                  session.getRepositorySession().getArtifactTypeRegistry();
83  
84          request.setDependencies(getProject().getDependencies().stream()
85                  .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
86                  .collect(Collectors.toList()));
87  
88          request.setManagedDependencies(Optional.ofNullable(getProject().getDependencyManagement())
89                  .map(DependencyManagement::getDependencies)
90                  .orElseGet(Collections::emptyList)
91                  .stream()
92                  .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
93                  .collect(Collectors.toList()));
94  
95          try {
96              CollectResult collectResult = repositorySystem.collectDependencies(session.getRepositorySession(), request);
97              Set<RemoteRepository> repositories = new HashSet<>();
98              collectResult.getRoot().accept(new TreeDependencyVisitor(new DependencyVisitor() {
99                  @Override
100                 public boolean visitEnter(DependencyNode node) {
101                     repositories.addAll(node.getRepositories());
102                     debugLogNodeRepo(node);
103                     return true;
104                 }
105 
106                 @Override
107                 public boolean visitLeave(DependencyNode node) {
108                     return true;
109                 }
110             }));
111 
112             if (repositories.isEmpty()) {
113                 getLog().info("No remote repository is used by this build." + System.lineSeparator());
114                 return;
115             }
116 
117             StringBuilder message = new StringBuilder();
118 
119             Map<Boolean, List<RemoteRepository>> repoGroupByMirrors = repositories.stream()
120                     .collect(Collectors.groupingBy(
121                             repo -> repo.getMirroredRepositories().isEmpty()));
122 
123             prepareRemoteRepositoriesList(
124                     message, repoGroupByMirrors.getOrDefault(Boolean.TRUE, Collections.emptyList()));
125             prepareRemoteMirrorRepositoriesList(
126                     message, repoGroupByMirrors.getOrDefault(Boolean.FALSE, Collections.emptyList()));
127 
128             getLog().info(message);
129 
130         } catch (DependencyCollectionException e) {
131             throw new MojoExecutionException(e.getMessage(), e);
132         }
133     }
134 
135     private void debugLogNodeRepo(DependencyNode node) {
136         if (!getLog().isDebugEnabled()) {
137             return;
138         }
139 
140         getLog().debug("Node: " + node + " resolved from:");
141         node.getRepositories().forEach(repo -> {
142             if (repo.getMirroredRepositories().isEmpty()) {
143                 getLog().debug(" - " + repo);
144             } else {
145                 getLog().debug(" - " + repo + " as mirror for:");
146                 repo.getMirroredRepositories().forEach(mrepo -> getLog().debug("    - " + mrepo));
147             }
148         });
149     }
150 
151     private void prepareRemoteMirrorRepositoriesList(
152             StringBuilder message, Collection<RemoteRepository> remoteProjectRepositories) {
153 
154         Map<RemoteRepository, RemoteRepository> mirrorMap = new HashMap<>();
155         remoteProjectRepositories.forEach(
156                 repo -> repo.getMirroredRepositories().forEach(mrepo -> mirrorMap.put(mrepo, repo)));
157 
158         mirrorMap.forEach((repo, mirror) -> message.append(" * ")
159                 .append(repo)
160                 .append(" mirrored by ")
161                 .append(mirror)
162                 .append(System.lineSeparator()));
163     }
164 
165     private void prepareRemoteRepositoriesList(
166             StringBuilder message, Collection<RemoteRepository> remoteProjectRepositories) {
167 
168         message.append("Project remote repositories used by this build:").append(System.lineSeparator());
169 
170         remoteProjectRepositories.forEach(
171                 repo -> message.append(" * ").append(repo).append(System.lineSeparator()));
172     }
173 }