1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.assembly.artifact;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.ArrayDeque;
26 import java.util.ArrayList;
27 import java.util.Deque;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.LinkedHashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Optional;
34 import java.util.Set;
35 import java.util.stream.Collectors;
36
37 import org.apache.maven.RepositoryUtils;
38 import org.apache.maven.artifact.Artifact;
39 import org.apache.maven.artifact.DefaultArtifact;
40 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
41 import org.apache.maven.artifact.versioning.VersionRange;
42 import org.apache.maven.model.DependencyManagement;
43 import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
44 import org.apache.maven.plugins.assembly.archive.ArchiveCreationException;
45 import org.apache.maven.plugins.assembly.archive.phase.ModuleSetAssemblyPhase;
46 import org.apache.maven.plugins.assembly.model.Assembly;
47 import org.apache.maven.plugins.assembly.model.DependencySet;
48 import org.apache.maven.plugins.assembly.model.ModuleBinaries;
49 import org.apache.maven.plugins.assembly.model.ModuleSet;
50 import org.apache.maven.project.MavenProject;
51 import org.codehaus.plexus.util.StringUtils;
52 import org.eclipse.aether.RepositorySystem;
53 import org.eclipse.aether.RepositorySystemSession;
54 import org.eclipse.aether.collection.CollectRequest;
55 import org.eclipse.aether.graph.DefaultDependencyNode;
56 import org.eclipse.aether.graph.Dependency;
57 import org.eclipse.aether.graph.DependencyFilter;
58 import org.eclipse.aether.graph.DependencyNode;
59 import org.eclipse.aether.graph.DependencyVisitor;
60 import org.eclipse.aether.resolution.DependencyRequest;
61 import org.eclipse.aether.resolution.DependencyResult;
62 import org.eclipse.aether.util.filter.DependencyFilterUtils;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 import static java.util.Objects.requireNonNull;
67
68
69
70
71 @Singleton
72 @Named
73 public class DefaultDependencyResolver implements DependencyResolver {
74 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDependencyResolver.class);
75
76 private final ArtifactHandlerManager artifactHandlerManager;
77
78 private final RepositorySystem repositorySystem;
79
80 @Inject
81 public DefaultDependencyResolver(ArtifactHandlerManager artifactHandlerManager, RepositorySystem repositorySystem) {
82 this.artifactHandlerManager = requireNonNull(artifactHandlerManager);
83 this.repositorySystem = requireNonNull(repositorySystem);
84 }
85
86 @Override
87 public Map<DependencySet, Set<Artifact>> resolveDependencySets(
88 final Assembly assembly,
89 ModuleSet moduleSet,
90 final AssemblerConfigurationSource configSource,
91 List<DependencySet> dependencySets)
92 throws DependencyResolutionException {
93 Map<DependencySet, Set<Artifact>> result = new LinkedHashMap<>();
94
95 for (DependencySet dependencySet : dependencySets) {
96
97 final MavenProject currentProject = configSource.getProject();
98
99 final ResolutionManagementInfo info = new ResolutionManagementInfo();
100 updateDependencySetResolutionRequirements(
101 configSource.getMavenSession().getRepositorySession(), dependencySet, info, currentProject);
102 updateModuleSetResolutionRequirements(moduleSet, dependencySet, info, configSource);
103
104 result.put(dependencySet, info.getArtifacts());
105 }
106 return result;
107 }
108
109 @Override
110 public Map<DependencySet, Set<Artifact>> resolveDependencySets(
111 final Assembly assembly,
112 final AssemblerConfigurationSource configSource,
113 List<DependencySet> dependencySets)
114 throws DependencyResolutionException {
115 Map<DependencySet, Set<Artifact>> result = new LinkedHashMap<>();
116
117 for (DependencySet dependencySet : dependencySets) {
118
119 final MavenProject currentProject = configSource.getProject();
120
121 final ResolutionManagementInfo info = new ResolutionManagementInfo();
122 updateDependencySetResolutionRequirements(
123 configSource.getMavenSession().getRepositorySession(), dependencySet, info, currentProject);
124
125 result.put(dependencySet, info.getArtifacts());
126 }
127 return result;
128 }
129
130 void updateModuleSetResolutionRequirements(
131 ModuleSet set,
132 DependencySet dependencySet,
133 final ResolutionManagementInfo requirements,
134 final AssemblerConfigurationSource configSource)
135 throws DependencyResolutionException {
136 final ModuleBinaries binaries = set.getBinaries();
137 if (binaries != null) {
138 Set<MavenProject> projects;
139 try {
140 projects = ModuleSetAssemblyPhase.getModuleProjects(set, configSource, LOGGER);
141 } catch (final ArchiveCreationException e) {
142 throw new DependencyResolutionException(
143 "Error determining project-set for moduleSet with binaries.", e);
144 }
145
146 for (final MavenProject p : projects) {
147 if (p.getArtifact() == null) {
148 p.setArtifact(createArtifact(p.getGroupId(), p.getArtifactId(), p.getVersion(), p.getPackaging()));
149 }
150 }
151
152 if (binaries.isIncludeDependencies()) {
153 updateDependencySetResolutionRequirements(
154 configSource.getMavenSession().getRepositorySession(),
155 dependencySet,
156 requirements,
157 projects.toArray(new MavenProject[0]));
158 }
159 }
160 }
161
162 private Artifact createArtifact(String groupId, String artifactId, String version, String type) {
163 VersionRange versionRange = null;
164 if (version != null) {
165 versionRange = VersionRange.createFromVersion(version);
166 }
167 return new DefaultArtifact(
168 groupId,
169 artifactId,
170 versionRange,
171 null,
172 type,
173 null,
174 artifactHandlerManager.getArtifactHandler(type),
175 false);
176 }
177
178 void updateDependencySetResolutionRequirements(
179 RepositorySystemSession systemSession,
180 final DependencySet set,
181 final ResolutionManagementInfo requirements,
182 final MavenProject... projects)
183 throws DependencyResolutionException {
184 for (final MavenProject project : projects) {
185 if (project == null) {
186 continue;
187 }
188
189 Set<Artifact> dependencyArtifacts = null;
190 if (set.isUseTransitiveDependencies()) {
191 try {
192
193 dependencyArtifacts = resolveTransitive(systemSession, set.getScope(), project);
194 } catch (org.eclipse.aether.resolution.DependencyResolutionException e) {
195 throw new DependencyResolutionException(e.getMessage(), e);
196 }
197 } else {
198
199 dependencyArtifacts = project.getDependencyArtifacts();
200 }
201
202 requirements.addArtifacts(dependencyArtifacts);
203 if (LOGGER.isDebugEnabled()) {
204 LOGGER.debug(
205 "Dependencies for project: {} are:\n{}",
206 project.getId(),
207 StringUtils.join(dependencyArtifacts.iterator(), "\n"));
208 }
209 }
210 }
211
212 private Set<Artifact> resolveTransitive(
213 RepositorySystemSession repositorySession, String scope, MavenProject project)
214 throws org.eclipse.aether.resolution.DependencyResolutionException {
215
216
217 DependencyFilter scoopeDependencyFilter = DependencyFilterUtils.classpathFilter(scope);
218
219
220 List<Dependency> dependencies = project.getDependencies().stream()
221 .map(d -> RepositoryUtils.toDependency(d, repositorySession.getArtifactTypeRegistry()))
222 .filter(d -> scoopeDependencyFilter.accept(new DefaultDependencyNode(d), null))
223 .collect(Collectors.toList());
224
225 List<Dependency> managedDependencies = Optional.ofNullable(project.getDependencyManagement())
226 .map(DependencyManagement::getDependencies)
227 .map(list -> list.stream()
228 .map(d -> RepositoryUtils.toDependency(d, repositorySession.getArtifactTypeRegistry()))
229 .collect(Collectors.toList()))
230 .orElse(null);
231
232 CollectRequest collectRequest = new CollectRequest();
233 collectRequest.setManagedDependencies(managedDependencies);
234 collectRequest.setRepositories(project.getRemoteProjectRepositories());
235 collectRequest.setDependencies(dependencies);
236 collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
237
238 DependencyRequest request = new DependencyRequest(collectRequest, scoopeDependencyFilter);
239
240 DependencyResult dependencyResult = repositorySystem.resolveDependencies(repositorySession, request);
241
242
243 Map<org.eclipse.aether.artifact.Artifact, Artifact> aetherToMavenArtifacts = new HashMap<>();
244 Deque<String> stack = new ArrayDeque<>();
245 stack.push(project.getArtifact().getId());
246
247 Set<Artifact> artifacts = new HashSet<>();
248
249
250 dependencyResult.getRoot().accept(new DependencyVisitor() {
251 @Override
252 public boolean visitEnter(DependencyNode node) {
253 if (node.getDependency() != null) {
254 stack.push(aetherToMavenArtifacts
255 .computeIfAbsent(node.getDependency().getArtifact(), RepositoryUtils::toArtifact)
256 .getId());
257 }
258 return true;
259 }
260
261 @Override
262 public boolean visitLeave(DependencyNode node) {
263 Dependency dependency = node.getDependency();
264 if (dependency != null) {
265 Artifact artifact = aetherToMavenArtifacts.computeIfAbsent(
266 dependency.getArtifact(), RepositoryUtils::toArtifact);
267 if (artifact.isResolved() && artifact.getFile() != null) {
268 List<String> depTrail = new ArrayList<>();
269 stack.descendingIterator().forEachRemaining(depTrail::add);
270 artifact.setDependencyTrail(depTrail);
271 artifact.setOptional(dependency.isOptional());
272 artifact.setScope(dependency.getScope());
273 artifacts.add(artifact);
274 }
275 stack.pop();
276 }
277 return true;
278 }
279 });
280
281 return artifacts;
282 }
283 }