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.model.building;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.nio.file.Files;
25  import java.nio.file.Path;
26  import java.nio.file.Paths;
27  import java.util.Arrays;
28  import java.util.Objects;
29  import java.util.Optional;
30  
31  import org.apache.maven.model.Dependency;
32  import org.apache.maven.model.Model;
33  import org.apache.maven.model.Parent;
34  
35  /**
36   * ModelSourceTransformer for the build pom
37   *
38   * @since 4.0.0
39   */
40  @Named
41  @Singleton
42  class BuildModelSourceTransformer implements ModelSourceTransformer {
43  
44      public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
45  
46      @Override
47      public void transform(Path pomFile, TransformerContext context, Model model) {
48          handleModelVersion(model);
49          handleParent(pomFile, context, model);
50          handleReactorDependencies(context, model);
51          handleCiFriendlyVersion(context, model);
52      }
53  
54      //
55      // Infer modelVersion from namespace URI
56      //
57      void handleModelVersion(Model model) {
58          String namespace = model.getDelegate().getNamespaceUri();
59          if (model.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) {
60              model.setModelVersion(namespace.substring(NAMESPACE_PREFIX.length()));
61          }
62      }
63  
64      //
65      // Infer parent information
66      //
67      void handleParent(Path pomFile, TransformerContext context, Model model) {
68          Parent parent = model.getParent();
69          if (parent != null) {
70              String version = parent.getVersion();
71              String path = Optional.ofNullable(parent.getRelativePath()).orElse("..");
72              if (version == null && !path.isEmpty()) {
73                  Optional<RelativeProject> resolvedParent = resolveRelativePath(
74                          pomFile.getParent(), context, Paths.get(path), parent.getGroupId(), parent.getArtifactId());
75                  resolvedParent.ifPresent(relativeProject -> parent.setVersion(relativeProject.getVersion()));
76              }
77          }
78      }
79  
80      //
81      // CI friendly versions
82      //
83      void handleCiFriendlyVersion(TransformerContext context, Model model) {
84          String version = model.getVersion();
85          String modVersion = replaceCiFriendlyVersion(context, version);
86          model.setVersion(modVersion);
87  
88          Parent parent = model.getParent();
89          if (parent != null) {
90              version = parent.getVersion();
91              modVersion = replaceCiFriendlyVersion(context, version);
92              parent.setVersion(modVersion);
93          }
94      }
95  
96      //
97      // Infer inner reactor dependencies version
98      //
99      void handleReactorDependencies(TransformerContext context, Model model) {
100         for (Dependency dep : model.getDependencies()) {
101             if (dep.getVersion() == null) {
102                 Model depModel = context.getRawModel(dep.getGroupId(), dep.getArtifactId());
103                 if (depModel != null) {
104                     String v = depModel.getVersion();
105                     if (v == null && depModel.getParent() != null) {
106                         v = depModel.getParent().getVersion();
107                     }
108                     dep.setVersion(v);
109                 }
110             }
111         }
112     }
113 
114     protected String replaceCiFriendlyVersion(TransformerContext context, String version) {
115         if (version != null) {
116             for (String key : Arrays.asList("changelist", "revision", "sha1")) {
117                 String val = context.getUserProperty(key);
118                 if (val != null) {
119                     version = version.replace("${" + key + "}", val);
120                 }
121             }
122         }
123         return version;
124     }
125 
126     protected Optional<RelativeProject> resolveRelativePath(
127             Path projectPath, TransformerContext context, Path relativePath, String groupId, String artifactId) {
128         Path pomPath = projectPath.resolve(relativePath).normalize();
129         if (Files.isDirectory(pomPath)) {
130             pomPath = context.locate(pomPath);
131         }
132 
133         if (pomPath == null || !Files.isRegularFile(pomPath)) {
134             return Optional.empty();
135         }
136 
137         Optional<RelativeProject> mappedProject = Optional.ofNullable(context.getRawModel(pomPath.normalize()))
138                 .map(BuildModelSourceTransformer::toRelativeProject);
139 
140         if (mappedProject.isPresent()) {
141             RelativeProject project = mappedProject.get();
142 
143             if (Objects.equals(groupId, project.getGroupId()) && Objects.equals(artifactId, project.getArtifactId())) {
144                 return mappedProject;
145             }
146         }
147         return Optional.empty();
148     }
149 
150     private static RelativeProject toRelativeProject(final org.apache.maven.model.Model m) {
151         String groupId = m.getGroupId();
152         if (groupId == null && m.getParent() != null) {
153             groupId = m.getParent().getGroupId();
154         }
155 
156         String version = m.getVersion();
157         if (version == null && m.getParent() != null) {
158             version = m.getParent().getVersion();
159         }
160 
161         return new RelativeProject(groupId, m.getArtifactId(), version);
162     }
163 
164     static class RelativeProject {
165         private final String groupId;
166 
167         private final String artifactId;
168 
169         private final String version;
170 
171         RelativeProject(String groupId, String artifactId, String version) {
172             this.groupId = groupId;
173             this.artifactId = artifactId;
174             this.version = version;
175         }
176 
177         public String getGroupId() {
178             return groupId;
179         }
180 
181         public String getArtifactId() {
182             return artifactId;
183         }
184 
185         public String getVersion() {
186             return version;
187         }
188     }
189 }