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 import javax.inject.Singleton;
24 import javax.xml.stream.XMLStreamException;
25
26 import java.io.IOException;
27 import java.io.Writer;
28 import java.nio.file.Files;
29 import java.nio.file.Path;
30 import java.nio.file.Paths;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.List;
34 import java.util.Set;
35 import java.util.concurrent.CopyOnWriteArraySet;
36
37 import org.apache.maven.api.feature.Features;
38 import org.apache.maven.api.model.Model;
39 import org.apache.maven.api.services.ModelBuilder;
40 import org.apache.maven.api.services.ModelBuilderException;
41 import org.apache.maven.internal.transformation.ConsumerPomArtifactTransformer;
42 import org.apache.maven.model.v4.MavenStaxWriter;
43 import org.apache.maven.project.MavenProject;
44 import org.apache.maven.project.artifact.ProjectArtifact;
45 import org.eclipse.aether.RepositorySystemSession;
46 import org.eclipse.aether.artifact.Artifact;
47 import org.eclipse.aether.artifact.DefaultArtifact;
48 import org.eclipse.aether.deployment.DeployRequest;
49 import org.eclipse.aether.installation.InstallRequest;
50 import org.eclipse.sisu.PreDestroy;
51
52
53
54
55
56
57 @Singleton
58 @Named("consumer-pom")
59 class DefaultConsumerPomArtifactTransformer implements ConsumerPomArtifactTransformer {
60
61 private static final String NAMESPACE_FORMAT = "http://maven.apache.org/POM/%s";
62
63 private static final String SCHEMA_LOCATION_FORMAT = "https://maven.apache.org/xsd/maven-%s.xsd";
64
65 private final Set<Path> toDelete = new CopyOnWriteArraySet<>();
66
67 private final ConsumerPomBuilder builder;
68
69 @Inject
70 DefaultConsumerPomArtifactTransformer(ConsumerPomBuilder builder) {
71 this.builder = builder;
72 }
73
74 @SuppressWarnings("deprecation")
75 public void injectTransformedArtifacts(RepositorySystemSession session, MavenProject project) throws IOException {
76 if (project.getFile() == null) {
77
78 return;
79 }
80 boolean isModel40 = ModelBuilder.MODEL_VERSION_4_0_0.equals(project.getModelVersion());
81 if (Features.consumerPom(session.getUserProperties(), !isModel40)) {
82 Path buildDir =
83 project.getBuild() != null ? Paths.get(project.getBuild().getDirectory()) : null;
84 if (buildDir != null) {
85 Files.createDirectories(buildDir);
86 }
87 Path consumer = buildDir != null
88 ? Files.createTempFile(buildDir, CONSUMER_POM_CLASSIFIER + "-", ".pom")
89 : Files.createTempFile(CONSUMER_POM_CLASSIFIER + "-", ".pom");
90 deferDeleteFile(consumer);
91
92 project.addAttachedArtifact(createConsumerPomArtifact(project, consumer, session));
93 } else if (project.getModel().getDelegate().isRoot()) {
94 throw new IllegalStateException(
95 "The use of the root attribute on the model requires the buildconsumer feature to be active");
96 }
97 }
98
99 TransformedArtifact createConsumerPomArtifact(
100 MavenProject project, Path consumer, RepositorySystemSession session) {
101 return new TransformedArtifact(
102 this,
103 project,
104 consumer,
105 session,
106 new ProjectArtifact(project),
107 () -> project.getFile().toPath(),
108 CONSUMER_POM_CLASSIFIER,
109 "pom");
110 }
111
112 void transform(MavenProject project, RepositorySystemSession session, Path src, Path tgt)
113 throws ModelBuilderException, XMLStreamException, IOException {
114 Model model = builder.build(session, project, src);
115 write(model, tgt);
116 }
117
118 private void deferDeleteFile(Path generatedFile) {
119 toDelete.add(generatedFile.toAbsolutePath());
120 }
121
122 @PreDestroy
123 private void doDeleteFiles() {
124 for (Path file : toDelete) {
125 try {
126 Files.delete(file);
127 } catch (IOException e) {
128
129 }
130 }
131 }
132
133 public InstallRequest remapInstallArtifacts(RepositorySystemSession session, InstallRequest request) {
134 if (consumerPomPresent(request.getArtifacts())) {
135 request.setArtifacts(replacePom(request.getArtifacts()));
136 }
137 return request;
138 }
139
140 public DeployRequest remapDeployArtifacts(RepositorySystemSession session, DeployRequest request) {
141 if (consumerPomPresent(request.getArtifacts())) {
142 request.setArtifacts(replacePom(request.getArtifacts()));
143 }
144 return request;
145 }
146
147 private boolean consumerPomPresent(Collection<Artifact> artifacts) {
148 return artifacts.stream()
149 .anyMatch(a -> "pom".equals(a.getExtension()) && CONSUMER_POM_CLASSIFIER.equals(a.getClassifier()));
150 }
151
152 private Collection<Artifact> replacePom(Collection<Artifact> artifacts) {
153 List<Artifact> consumers = new ArrayList<>();
154 List<Artifact> mains = new ArrayList<>();
155 for (Artifact artifact : artifacts) {
156 if ("pom".equals(artifact.getExtension()) || artifact.getExtension().startsWith("pom.")) {
157 if (CONSUMER_POM_CLASSIFIER.equals(artifact.getClassifier())) {
158 consumers.add(artifact);
159 } else if ("".equals(artifact.getClassifier())) {
160 mains.add(artifact);
161 }
162 }
163 }
164 if (!mains.isEmpty() && !consumers.isEmpty()) {
165 ArrayList<Artifact> result = new ArrayList<>(artifacts);
166 for (Artifact main : mains) {
167 result.remove(main);
168 result.add(new DefaultArtifact(
169 main.getGroupId(),
170 main.getArtifactId(),
171 BUILD_POM_CLASSIFIER,
172 main.getExtension(),
173 main.getVersion(),
174 main.getProperties(),
175 main.getFile()));
176 }
177 for (Artifact consumer : consumers) {
178 result.remove(consumer);
179 result.add(new DefaultArtifact(
180 consumer.getGroupId(),
181 consumer.getArtifactId(),
182 "",
183 consumer.getExtension(),
184 consumer.getVersion(),
185 consumer.getProperties(),
186 consumer.getFile()));
187 }
188 artifacts = result;
189 }
190 return artifacts;
191 }
192
193 void write(Model model, Path dest) throws IOException, XMLStreamException {
194 String version = model.getModelVersion();
195 Files.createDirectories(dest.getParent());
196 try (Writer w = Files.newBufferedWriter(dest)) {
197 MavenStaxWriter writer = new MavenStaxWriter();
198 writer.setNamespace(String.format(NAMESPACE_FORMAT, version));
199 writer.setSchemaLocation(String.format(SCHEMA_LOCATION_FORMAT, version));
200 writer.setAddLocationInformation(false);
201 writer.write(w, model);
202 }
203 }
204 }