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;
20
21 import javax.annotation.PreDestroy;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.nio.file.StandardCopyOption;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Set;
34 import java.util.concurrent.CopyOnWriteArraySet;
35 import java.util.function.BiConsumer;
36
37 import org.apache.maven.feature.Features;
38 import org.apache.maven.model.building.DefaultBuildPomXMLFilterFactory;
39 import org.apache.maven.model.building.TransformerContext;
40 import org.apache.maven.model.transform.RawToConsumerPomXMLFilterFactory;
41 import org.apache.maven.model.transform.pull.XmlUtils;
42 import org.apache.maven.project.MavenProject;
43 import org.apache.maven.project.artifact.ProjectArtifact;
44 import org.codehaus.plexus.util.ReaderFactory;
45 import org.codehaus.plexus.util.xml.XmlStreamReader;
46 import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
47 import org.codehaus.plexus.util.xml.pull.MXParser;
48 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
49 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
50 import org.eclipse.aether.RepositorySystemSession;
51 import org.eclipse.aether.artifact.Artifact;
52 import org.eclipse.aether.artifact.DefaultArtifact;
53 import org.eclipse.aether.deployment.DeployRequest;
54 import org.eclipse.aether.installation.InstallRequest;
55
56
57
58
59
60
61 @Singleton
62 @Named("consumer-pom")
63 public final class ConsumerPomArtifactTransformer {
64
65 private static final String CONSUMER_POM_CLASSIFIER = "consumer";
66
67 private final Set<Path> toDelete = new CopyOnWriteArraySet<>();
68
69 public void injectTransformedArtifacts(MavenProject project, RepositorySystemSession session) throws IOException {
70 if (project.getFile() == null) {
71
72 return;
73 }
74 if (isActive(session)) {
75 Path generatedFile;
76 String buildDirectory =
77 project.getBuild() != null ? project.getBuild().getDirectory() : null;
78 if (buildDirectory == null) {
79 generatedFile = Files.createTempFile(CONSUMER_POM_CLASSIFIER, "pom");
80 } else {
81 Path buildDir = Paths.get(buildDirectory);
82 Files.createDirectories(buildDir);
83 generatedFile = Files.createTempFile(buildDir, CONSUMER_POM_CLASSIFIER, "pom");
84 }
85 deferDeleteFile(generatedFile);
86 project.addAttachedArtifact(new ConsumerPomArtifact(project, generatedFile, session));
87 } else if (project.getModel().isRoot()) {
88 throw new IllegalStateException(
89 "The use of the root attribute on the model requires the buildconsumer feature to be active");
90 }
91 }
92
93 private void deferDeleteFile(Path generatedFile) {
94 toDelete.add(generatedFile.toAbsolutePath());
95 }
96
97 @PreDestroy
98 private void doDeleteFiles() {
99 for (Path file : toDelete) {
100 try {
101 Files.delete(file);
102 } catch (IOException e) {
103
104 }
105 }
106 }
107
108 public InstallRequest remapInstallArtifacts(RepositorySystemSession session, InstallRequest request) {
109 if (isActive(session) && consumerPomPresent(request.getArtifacts())) {
110 request.setArtifacts(replacePom(request.getArtifacts()));
111 }
112 return request;
113 }
114
115 public DeployRequest remapDeployArtifacts(RepositorySystemSession session, DeployRequest request) {
116 if (isActive(session) && consumerPomPresent(request.getArtifacts())) {
117 request.setArtifacts(replacePom(request.getArtifacts()));
118 }
119 return request;
120 }
121
122 private boolean isActive(RepositorySystemSession session) {
123 return Features.buildConsumer(session.getUserProperties()).isActive();
124 }
125
126 private boolean consumerPomPresent(Collection<Artifact> artifacts) {
127 return artifacts.stream().anyMatch(a -> CONSUMER_POM_CLASSIFIER.equals(a.getClassifier()));
128 }
129
130 private Collection<Artifact> replacePom(Collection<Artifact> artifacts) {
131 ArrayList<Artifact> result = new ArrayList<>(artifacts.size());
132 for (Artifact artifact : artifacts) {
133 if (CONSUMER_POM_CLASSIFIER.equals(artifact.getClassifier())) {
134
135 DefaultArtifact remapped = new DefaultArtifact(
136 artifact.getGroupId(),
137 artifact.getArtifactId(),
138 "",
139 artifact.getExtension(),
140 artifact.getVersion(),
141 artifact.getProperties(),
142 artifact.getFile());
143 result.add(remapped);
144 } else if ("".equals(artifact.getClassifier())
145 && (artifact.getExtension().equals("pom"))
146 || artifact.getExtension().startsWith("pom.")) {
147
148 continue;
149 } else {
150
151 result.add(artifact);
152 }
153 }
154 return result;
155 }
156
157
158
159
160 private static class ConsumerPomArtifact extends TransformedArtifact {
161
162 private ConsumerPomArtifact(MavenProject mavenProject, Path target, RepositorySystemSession session) {
163 super(
164 new ProjectArtifact(mavenProject),
165 () -> mavenProject.getFile().toPath(),
166 CONSUMER_POM_CLASSIFIER,
167 "pom",
168 target,
169 transformer(session));
170 }
171
172 private static BiConsumer<Path, Path> transformer(RepositorySystemSession session) {
173 TransformerContext context = (TransformerContext) session.getData().get(TransformerContext.KEY);
174 return (src, dest) -> {
175 try (InputStream inputStream = transform(src, context)) {
176 Files.createDirectories(dest.getParent());
177 Files.copy(inputStream, dest, StandardCopyOption.REPLACE_EXISTING);
178 } catch (XmlPullParserException | IOException e) {
179 throw new RuntimeException(e);
180 }
181 };
182 }
183 }
184
185
186
187
188 static InputStream transform(Path pomFile, TransformerContext context) throws IOException, XmlPullParserException {
189 XmlStreamReader reader = ReaderFactory.newXmlReader(Files.newInputStream(pomFile));
190 XmlPullParser parser = new MXParser(EntityReplacementMap.defaultEntityReplacementMap);
191 parser.setInput(reader);
192 parser = new RawToConsumerPomXMLFilterFactory(new DefaultBuildPomXMLFilterFactory(context, true))
193 .get(parser, pomFile);
194
195 return XmlUtils.writeDocument(reader, parser);
196 }
197 }