1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.transformation.impl;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.nio.file.Path;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.stream.Collectors;
28
29 import org.apache.maven.api.SessionData;
30 import org.apache.maven.api.model.Dependency;
31 import org.apache.maven.api.model.DependencyManagement;
32 import org.apache.maven.api.model.DistributionManagement;
33 import org.apache.maven.api.model.Model;
34 import org.apache.maven.api.model.ModelBase;
35 import org.apache.maven.api.model.Profile;
36 import org.apache.maven.api.model.Repository;
37 import org.apache.maven.api.services.ModelBuilder;
38 import org.apache.maven.api.services.ModelBuilderException;
39 import org.apache.maven.api.services.ModelBuilderRequest;
40 import org.apache.maven.api.services.ModelBuilderResult;
41 import org.apache.maven.api.services.ModelSource;
42 import org.apache.maven.api.services.model.LifecycleBindingsInjector;
43 import org.apache.maven.internal.impl.InternalSession;
44 import org.apache.maven.model.v4.MavenModelVersion;
45 import org.apache.maven.project.MavenProject;
46 import org.eclipse.aether.RepositorySystemSession;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 @Named
51 class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
52 private static final String BOM_PACKAGING = "bom";
53
54 public static final String POM_PACKAGING = "pom";
55
56 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultConsumerPomBuilder.class);
57
58 private final LifecycleBindingsInjector lifecycleBindingsInjector;
59
60 @Inject
61 @SuppressWarnings("checkstyle:ParameterNumber")
62 DefaultConsumerPomBuilder(LifecycleBindingsInjector lifecycleBindingsInjector) {
63 this.lifecycleBindingsInjector = lifecycleBindingsInjector;
64 }
65
66 @Override
67 public Model build(RepositorySystemSession session, MavenProject project, Path src) throws ModelBuilderException {
68 Model model = project.getModel().getDelegate();
69 String packaging = model.getPackaging();
70 String originalPackaging = project.getOriginalModel().getPackaging();
71 if (POM_PACKAGING.equals(packaging) && !BOM_PACKAGING.equals(originalPackaging)) {
72 return buildPom(session, project, src);
73 } else {
74 return buildNonPom(session, project, src);
75 }
76 }
77
78 protected Model buildPom(RepositorySystemSession session, MavenProject project, Path src)
79 throws ModelBuilderException {
80 ModelBuilderResult result = buildModel(session, project, src);
81 Model model = result.getRawModel();
82 return transform(model, project);
83 }
84
85 protected Model buildNonPom(RepositorySystemSession session, MavenProject project, Path src)
86 throws ModelBuilderException {
87 ModelBuilderResult result = buildModel(session, project, src);
88 Model model = result.getEffectiveModel();
89 return transform(model, project);
90 }
91
92 private ModelBuilderResult buildModel(RepositorySystemSession session, MavenProject project, Path src)
93 throws ModelBuilderException {
94 InternalSession iSession = InternalSession.from(session);
95 ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder();
96 request.requestType(ModelBuilderRequest.RequestType.BUILD_CONSUMER);
97 request.session(iSession);
98 request.source(ModelSource.fromPath(src));
99 request.locationTracking(false);
100 request.systemProperties(session.getSystemProperties());
101 request.userProperties(session.getUserProperties());
102 request.lifecycleBindingsInjector(lifecycleBindingsInjector::injectLifecycleBindings);
103 ModelBuilder.ModelBuilderSession mbSession =
104 iSession.getData().get(SessionData.key(ModelBuilder.ModelBuilderSession.class));
105 return mbSession.build(request.build());
106 }
107
108 static Model transform(Model model, MavenProject project) {
109 String packaging = model.getPackaging();
110 boolean preserveModelVersion = model.isPreserveModelVersion();
111 if (POM_PACKAGING.equals(packaging)) {
112
113 model = model.withRoot(false).withModules(null).withSubprojects(null);
114 if (model.getParent() != null) {
115 model = model.withParent(model.getParent().withRelativePath(null));
116 }
117
118 if (!preserveModelVersion) {
119 model = model.withPreserveModelVersion(false);
120 String modelVersion = new MavenModelVersion().getModelVersion(model);
121 model = model.withModelVersion(modelVersion);
122 }
123 } else if (BOM_PACKAGING.equals(packaging)) {
124 DependencyManagement dependencyManagement =
125 project.getOriginalModel().getDependencyManagement().getDelegate();
126 List<Dependency> dependencies = new ArrayList<>();
127 String version = model.getVersion();
128
129 dependencyManagement
130 .getDependencies()
131 .forEach((dependency) -> dependencies.add(dependency.withVersion(version)));
132 Model.Builder builder = prune(
133 Model.newBuilder(model, true)
134 .preserveModelVersion(false)
135 .root(false)
136 .parent(null)
137 .dependencyManagement(dependencyManagement.withDependencies(dependencies))
138 .build(null),
139 model);
140 builder.packaging(POM_PACKAGING);
141 builder.profiles(prune(model.getProfiles()));
142
143 model = builder.build();
144 String modelVersion = new MavenModelVersion().getModelVersion(model);
145 if (!ModelBuilder.MODEL_VERSION_4_0_0.equals(modelVersion) && !preserveModelVersion) {
146 warnNotDowngraded(project);
147 }
148 model = model.withModelVersion(modelVersion);
149 } else {
150 Model.Builder builder = prune(
151 Model.newBuilder(model, true)
152 .preserveModelVersion(false)
153 .root(false)
154 .parent(null)
155 .build(null),
156 model);
157 builder.profiles(prune(model.getProfiles()));
158
159 model = builder.build();
160 String modelVersion = new MavenModelVersion().getModelVersion(model);
161 if (!ModelBuilder.MODEL_VERSION_4_0_0.equals(modelVersion) && !preserveModelVersion) {
162 warnNotDowngraded(project);
163 }
164 model = model.withModelVersion(modelVersion);
165 }
166 return model;
167 }
168
169 static void warnNotDowngraded(MavenProject project) {
170 LOGGER.warn("The consumer POM for " + project.getId() + " cannot be downgraded to 4.0.0. "
171 + "If you intent your build to be consumed with Maven 3 projects, you need to remove "
172 + "the features that request a newer model version. If you're fine with having the "
173 + "consumer POM not consumable with Maven 3, add the `preserve.model.version='true'` "
174 + "attribute on the <project> element of your POM.");
175 }
176
177 private static List<Profile> prune(List<Profile> profiles) {
178 return profiles.stream()
179 .map(p -> {
180 Profile.Builder builder = Profile.newBuilder(p, true);
181 prune((ModelBase.Builder) builder, p);
182 return builder.build(null).build();
183 })
184 .filter(p -> !isEmpty(p))
185 .collect(Collectors.toList());
186 }
187
188 private static boolean isEmpty(Profile profile) {
189 return profile.getActivation() == null
190 && profile.getBuild() == null
191 && profile.getDependencies().isEmpty()
192 && (profile.getDependencyManagement() == null
193 || profile.getDependencyManagement().getDependencies().isEmpty())
194 && profile.getDistributionManagement() == null
195 && profile.getModules().isEmpty()
196 && profile.getSubprojects().isEmpty()
197 && profile.getProperties().isEmpty()
198 && profile.getRepositories().isEmpty()
199 && profile.getPluginRepositories().isEmpty()
200 && profile.getReporting() == null;
201 }
202
203 private static <T extends ModelBase.Builder> T prune(T builder, ModelBase model) {
204 builder.properties(null).reporting(null);
205 if (model.getDistributionManagement() != null
206 && model.getDistributionManagement().getRelocation() != null) {
207
208 builder.distributionManagement(DistributionManagement.newBuilder()
209 .relocation(model.getDistributionManagement().getRelocation())
210 .build());
211 }
212
213 builder.pluginRepositories(pruneRepositories(model.getPluginRepositories()));
214 builder.repositories(pruneRepositories(model.getRepositories()));
215 return builder;
216 }
217
218 private static List<Repository> pruneRepositories(List<Repository> repositories) {
219 return repositories.stream()
220 .filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
221 .collect(Collectors.toList());
222 }
223 }