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