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