1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.plugin.util;
import org.apache.maven.artifact.Artifact;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Logger;
import static java.util.stream.Collectors.toList;
/**
* Translates the scope of dependencies when constructing a test bundle.
* Used by {@link Artifacts} to determine which artifacts that are provided by the runtime or must be included in the bundle.
*
* Dependencies of scope 'test' are by default translated to 'compile'. Dependencies of other scopes are kept as is.
*
* Default scope translation for 'test' scope dependencies can be overridden through a comma-separated configuration string.
* Each substring is a triplet on the form [groupId]:[artifactId]:[scope].
* Scope translation overrides affects all transitive dependencies.
* The ordering of the triplets determines the priority - only the first matching override will affect a given dependency.
*
* @author bjorncs
*/
public class TestBundleDependencyScopeTranslator implements Artifacts.ScopeTranslator {
private static final Logger log = Logger.getLogger(TestBundleDependencyScopeTranslator.class.getName());
private final Map<Artifact, String> dependencyScopes;
private TestBundleDependencyScopeTranslator(Map<Artifact, String> dependencyScopes) {
this.dependencyScopes = dependencyScopes;
}
@Override public String scopeOf(Artifact artifact) { return Objects.requireNonNull(dependencyScopes.get(artifact)); }
public static TestBundleDependencyScopeTranslator from(Map<String, Artifact> dependencies, String rawConfig) {
List<DependencyOverride> dependencyOverrides = toDependencyOverrides(rawConfig);
Map<Artifact, String> dependencyScopes = new HashMap<>();
for (Artifact dependency : dependencies.values()) {
dependencyScopes.put(dependency, getScopeForDependency(dependency, dependencyOverrides, dependencies));
}
return new TestBundleDependencyScopeTranslator(dependencyScopes);
}
private static List<DependencyOverride> toDependencyOverrides(String rawConfig) {
if (rawConfig == null || rawConfig.isBlank()) return List.of();
return Arrays.stream(rawConfig.split(","))
.map(String::strip)
.filter(s -> !s.isBlank())
.map(TestBundleDependencyScopeTranslator::toDependencyOverride)
.collect(toList());
}
private static DependencyOverride toDependencyOverride(String overrideString) {
String[] elements = overrideString.split(":");
if (elements.length != 3) {
throw new IllegalArgumentException("Invalid dependency override: " + overrideString);
}
return new DependencyOverride(elements[0], elements[1], elements[2]);
}
private static String stripVersionAndScope(String idInDependencyTrail) {
int firstDelimiter = idInDependencyTrail.indexOf(':');
int secondDelimiter = idInDependencyTrail.indexOf(':', firstDelimiter + 1);
return idInDependencyTrail.substring(0, secondDelimiter);
}
private static String getScopeForDependency(
Artifact dependency, List<DependencyOverride> overrides, Map<String, Artifact> otherArtifacts) {
String oldScope = dependency.getScope();
if (!oldScope.equals(Artifact.SCOPE_TEST)) return oldScope;
for (DependencyOverride override : overrides) {
for (Artifact dependent : dependencyTrailOf(dependency, otherArtifacts)) {
if (override.isForArtifact(dependent)) {
log.fine(() -> String.format(
"Overriding scope of '%s'; scope '%s' overridden to '%s'",
dependency.getId(), oldScope, override.scope));
return override.scope;
}
}
}
log.fine(() -> String.format(
"Using default scope translation for '%s'; scope 'test' translated to 'compile'",
dependency.getId()));
return Artifact.SCOPE_COMPILE;
}
private static List<Artifact> dependencyTrailOf(Artifact artifact, Map<String, Artifact> otherArtifacts) {
return artifact.getDependencyTrail().stream()
.skip(1) // Maven project itself is the first entry
.map(parentId -> otherArtifacts.get(stripVersionAndScope(parentId)))
.filter(Objects::nonNull)
.collect(toList());
}
private static class DependencyOverride {
final String groupId;
final String artifactId;
final String scope;
DependencyOverride(String groupId, String artifactId, String scope) {
this.groupId = groupId;
this.artifactId = artifactId;
this.scope = scope;
}
boolean isForArtifact(Artifact artifact) {
return artifact.getGroupId().equals(groupId) && artifact.getArtifactId().equals(artifactId);
}
}
}
|