1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl.model;
20
21 import java.nio.file.Files;
22 import java.nio.file.Path;
23 import java.nio.file.Paths;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.Optional;
29
30 import org.apache.maven.api.di.Named;
31 import org.apache.maven.api.di.Singleton;
32 import org.apache.maven.api.model.Dependency;
33 import org.apache.maven.api.model.Model;
34 import org.apache.maven.api.model.Parent;
35 import org.apache.maven.api.services.ModelTransformer;
36 import org.apache.maven.api.services.ModelTransformerContext;
37
38
39
40
41
42
43 @Named
44 @Singleton
45 public class BuildModelTransformer implements ModelTransformer {
46
47 public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
48
49 @Override
50 public Model transform(ModelTransformerContext context, Model model, Path path) {
51 Model.Builder builder = Model.newBuilder(model);
52 handleModelVersion(context, model, path, builder);
53 handleParent(context, model, path, builder);
54 handleReactorDependencies(context, model, path, builder);
55 handleCiFriendlyVersion(context, model, path, builder);
56 return builder.build();
57 }
58
59
60
61
62 void handleModelVersion(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) {
63 String namespace = model.getNamespaceUri();
64 if (model.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) {
65 builder.modelVersion(namespace.substring(NAMESPACE_PREFIX.length()));
66 }
67 }
68
69
70
71
72 void handleParent(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) {
73 Parent parent = model.getParent();
74 if (parent != null) {
75 String version = parent.getVersion();
76 String path = Optional.ofNullable(parent.getRelativePath()).orElse("..");
77 if (version == null && !path.isEmpty()) {
78 Optional<RelativeProject> resolvedParent = resolveRelativePath(
79 pomFile, context, Paths.get(path), parent.getGroupId(), parent.getArtifactId());
80 if (resolvedParent.isPresent()) {
81 version = resolvedParent.get().getVersion();
82 }
83 }
84
85 String modVersion = replaceCiFriendlyVersion(context, version);
86 builder.parent(parent.withVersion(modVersion));
87 }
88 }
89
90
91
92
93 void handleCiFriendlyVersion(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) {
94 String version = model.getVersion();
95 String modVersion = replaceCiFriendlyVersion(context, version);
96 builder.version(modVersion);
97 }
98
99
100
101
102 void handleReactorDependencies(ModelTransformerContext context, Model model, Path pomFile, Model.Builder builder) {
103 List<Dependency> newDeps = new ArrayList<>();
104 boolean modified = false;
105 for (Dependency dep : model.getDependencies()) {
106 if (dep.getVersion() == null) {
107 Model depModel = context.getRawModel(model.getPomFile(), dep.getGroupId(), dep.getArtifactId());
108 if (depModel != null) {
109 String v = depModel.getVersion();
110 if (v == null && depModel.getParent() != null) {
111 v = depModel.getParent().getVersion();
112 }
113 dep = dep.withVersion(v);
114 modified = true;
115 }
116 }
117 newDeps.add(dep);
118 }
119 if (modified) {
120 builder.dependencies(newDeps);
121 }
122 }
123
124 protected String replaceCiFriendlyVersion(ModelTransformerContext context, String version) {
125 if (version != null) {
126 for (String key : Arrays.asList("changelist", "revision", "sha1")) {
127 String val = context.getUserProperty(key);
128 if (val != null) {
129 version = version.replace("${" + key + "}", val);
130 }
131 }
132 }
133 return version;
134 }
135
136 protected Optional<RelativeProject> resolveRelativePath(
137 Path pomFile, ModelTransformerContext context, Path relativePath, String groupId, String artifactId) {
138 Path pomPath = pomFile.resolveSibling(relativePath).normalize();
139 if (Files.isDirectory(pomPath)) {
140 pomPath = context.locate(pomPath);
141 }
142
143 if (pomPath == null || !Files.isRegularFile(pomPath)) {
144 return Optional.empty();
145 }
146
147 Optional<RelativeProject> mappedProject = Optional.ofNullable(context.getRawModel(pomFile, pomPath.normalize()))
148 .map(BuildModelTransformer::toRelativeProject);
149
150 if (mappedProject.isPresent()) {
151 RelativeProject project = mappedProject.get();
152
153 if (Objects.equals(groupId, project.getGroupId()) && Objects.equals(artifactId, project.getArtifactId())) {
154 return mappedProject;
155 }
156 }
157 return Optional.empty();
158 }
159
160 private static RelativeProject toRelativeProject(final Model m) {
161 String groupId = m.getGroupId();
162 if (groupId == null && m.getParent() != null) {
163 groupId = m.getParent().getGroupId();
164 }
165
166 String version = m.getVersion();
167 if (version == null && m.getParent() != null) {
168 version = m.getParent().getVersion();
169 }
170
171 return new RelativeProject(groupId, m.getArtifactId(), version);
172 }
173
174 protected static class RelativeProject {
175 private final String groupId;
176
177 private final String artifactId;
178
179 private final String version;
180
181 protected RelativeProject(String groupId, String artifactId, String version) {
182 this.groupId = groupId;
183 this.artifactId = artifactId;
184 this.version = version;
185 }
186
187 public String getGroupId() {
188 return groupId;
189 }
190
191 public String getArtifactId() {
192 return artifactId;
193 }
194
195 public String getVersion() {
196 return version;
197 }
198 }
199 }