1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.install;
20
21 import java.io.File;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.Writer;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.nio.file.StandardCopyOption;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarFile;
33 import java.util.regex.Pattern;
34
35 import org.apache.maven.api.Artifact;
36 import org.apache.maven.api.ProducedArtifact;
37 import org.apache.maven.api.Session;
38 import org.apache.maven.api.di.Inject;
39 import org.apache.maven.api.model.Model;
40 import org.apache.maven.api.model.Parent;
41 import org.apache.maven.api.plugin.Log;
42 import org.apache.maven.api.plugin.MojoException;
43 import org.apache.maven.api.plugin.annotations.Mojo;
44 import org.apache.maven.api.plugin.annotations.Parameter;
45 import org.apache.maven.api.services.ArtifactInstaller;
46 import org.apache.maven.api.services.ArtifactInstallerException;
47 import org.apache.maven.api.services.ArtifactManager;
48 import org.apache.maven.api.services.xml.ModelXmlFactory;
49 import org.apache.maven.api.services.xml.XmlReaderException;
50
51
52
53
54 @Mojo(name = "install-file", projectRequired = false, aggregator = true)
55 @SuppressWarnings("unused")
56 public class InstallFileMojo implements org.apache.maven.api.plugin.Mojo {
57 private static final String TAR = "tar.";
58 private static final String ILLEGAL_VERSION_CHARS = "\\/:\"<>|?*[](){},";
59
60 @Inject
61 private Log log;
62
63 @Inject
64 private Session session;
65
66
67
68
69
70 @Parameter(property = "groupId")
71 private String groupId;
72
73
74
75
76
77 @Parameter(property = "artifactId")
78 private String artifactId;
79
80
81
82
83
84 @Parameter(property = "version")
85 private String version;
86
87
88
89
90
91 @Parameter(property = "packaging")
92 private String packaging;
93
94
95
96
97
98
99
100 @Parameter(property = "classifier")
101 private String classifier;
102
103
104
105
106 @Parameter(property = "file", required = true)
107 private Path file;
108
109
110
111
112
113
114 @Parameter(property = "javadoc")
115 private Path javadoc;
116
117
118
119
120
121
122 @Parameter(property = "sources")
123 private Path sources;
124
125
126
127
128
129
130
131 @Parameter(property = "pomFile")
132 private Path pomFile;
133
134
135
136
137
138
139
140 @Parameter(property = "generatePom")
141 private Boolean generatePom;
142
143
144
145
146
147
148
149 @Parameter(property = "localRepositoryPath")
150 private Path localRepositoryPath;
151
152 @Override
153 public void execute() {
154 if (!Files.exists(file)) {
155 String message = "The specified file '" + file + "' does not exist";
156 log.error(message);
157 throw new MojoException(message);
158 }
159
160 Session session = this.session;
161
162 List<ProducedArtifact> installableArtifacts = new ArrayList<>();
163
164
165 if (localRepositoryPath != null) {
166 session = session.withLocalRepository(session.createLocalRepository(localRepositoryPath));
167
168 log.debug("localRepoPath: " + localRepositoryPath);
169 }
170
171 Path deployedPom;
172 Path temporaryPom = null;
173 if (pomFile != null) {
174 deployedPom = pomFile;
175 processModel(readModel(deployedPom));
176 } else {
177 if (!Boolean.TRUE.equals(generatePom)) {
178 temporaryPom = readingPomFromJarFile();
179 deployedPom = temporaryPom;
180 if (deployedPom != null) {
181 log.debug("Using JAR embedded POM as pomFile");
182 }
183 } else {
184 deployedPom = null;
185 }
186 }
187
188 if (groupId == null || artifactId == null || version == null || packaging == null) {
189 throw new MojoException("The artifact information is incomplete: 'groupId', 'artifactId', "
190 + "'version' and 'packaging' are required.");
191 }
192
193 if (!isValidId(groupId) || !isValidId(artifactId) || !isValidVersion(version)) {
194 throw new MojoException("The artifact information is not valid: uses invalid characters.");
195 }
196
197 boolean isFilePom = classifier == null && "pom".equals(packaging);
198 ProducedArtifact artifact = session.createProducedArtifact(
199 groupId, artifactId, version, classifier, isFilePom ? "pom" : getExtension(file), packaging);
200
201 if (file.equals(getLocalRepositoryFile(artifact))) {
202 throw new MojoException("Cannot install artifact. "
203 + "Artifact is already in the local repository.\n\nFile in question is: " + file + "\n");
204 }
205
206 ArtifactManager artifactManager = session.getService(ArtifactManager.class);
207 artifactManager.setPath(artifact, file);
208 installableArtifacts.add(artifact);
209
210 ProducedArtifact pomArtifact = null;
211 if (!isFilePom) {
212 pomArtifact = session.createProducedArtifact(groupId, artifactId, version, null, "pom", null);
213 if (deployedPom != null) {
214 artifactManager.setPath(pomArtifact, deployedPom);
215 installableArtifacts.add(pomArtifact);
216 } else {
217 temporaryPom = generatePomFile();
218 deployedPom = temporaryPom;
219 artifactManager.setPath(pomArtifact, deployedPom);
220 if (Boolean.TRUE.equals(generatePom)
221 || (generatePom == null && !Files.exists(getLocalRepositoryFile(pomArtifact)))) {
222 log.debug("Installing generated POM");
223 installableArtifacts.add(pomArtifact);
224 } else if (generatePom == null) {
225 log.debug("Skipping installation of generated POM, already present in local repository");
226 }
227 }
228 }
229
230 if (sources != null) {
231 ProducedArtifact sourcesArtifact =
232 session.createProducedArtifact(groupId, artifactId, version, "sources", "jar", null);
233 artifactManager.setPath(sourcesArtifact, sources);
234 installableArtifacts.add(sourcesArtifact);
235 }
236
237 if (javadoc != null) {
238 ProducedArtifact javadocArtifact =
239 session.createProducedArtifact(groupId, artifactId, version, "javadoc", "jar", null);
240 artifactManager.setPath(javadocArtifact, javadoc);
241 installableArtifacts.add(javadocArtifact);
242 }
243
244 try {
245 ArtifactInstaller artifactInstaller = session.getService(ArtifactInstaller.class);
246 artifactInstaller.install(session, installableArtifacts);
247 } catch (ArtifactInstallerException e) {
248 throw new MojoException(e.getMessage(), e);
249 } finally {
250 if (temporaryPom != null) {
251 try {
252 Files.deleteIfExists(temporaryPom);
253 } catch (IOException e) {
254
255 }
256 if (pomArtifact != null) {
257 artifactManager.setPath(pomArtifact, null);
258 }
259 }
260 }
261 }
262
263 private Path readingPomFromJarFile() {
264 Pattern pomEntry = Pattern.compile("META-INF/maven/.*/pom\\.xml");
265 try {
266 try (JarFile jarFile = new JarFile(file.toFile())) {
267 JarEntry entry = jarFile.stream()
268 .filter(e -> pomEntry.matcher(e.getName()).matches())
269 .findFirst()
270 .orElse(null);
271 if (entry != null) {
272 log.debug("Loading " + entry.getName());
273
274 try (InputStream pomInputStream = jarFile.getInputStream(entry)) {
275 String base = file.getFileName().toString();
276 if (base.indexOf('.') > 0) {
277 base = base.substring(0, base.lastIndexOf('.'));
278 }
279 Path pomFile = File.createTempFile(base, ".pom").toPath();
280
281 Files.copy(pomInputStream, pomFile, StandardCopyOption.REPLACE_EXISTING);
282
283 processModel(readModel(pomFile));
284
285 return pomFile;
286 }
287 } else {
288 log.info("pom.xml not found in " + file.getFileName());
289 }
290 }
291 } catch (IOException e) {
292
293 }
294 return null;
295 }
296
297
298
299
300
301
302
303
304 private Model readModel(Path pomFile) throws MojoException {
305 try {
306 try (InputStream is = Files.newInputStream(pomFile)) {
307 return session.getService(ModelXmlFactory.class).read(is);
308 }
309 } catch (FileNotFoundException e) {
310 throw new MojoException("File not found " + pomFile, e);
311 } catch (IOException e) {
312 throw new MojoException("Error reading POM " + pomFile, e);
313 } catch (XmlReaderException e) {
314 throw new MojoException("Error parsing POM " + pomFile, e);
315 }
316 }
317
318
319
320
321
322
323 private void processModel(Model model) {
324 Parent parent = model.getParent();
325
326 if (this.groupId == null) {
327 this.groupId = model.getGroupId();
328 if (this.groupId == null && parent != null) {
329 this.groupId = parent.getGroupId();
330 }
331 }
332 if (this.artifactId == null) {
333 this.artifactId = model.getArtifactId();
334 }
335 if (this.version == null) {
336 this.version = model.getVersion();
337 if (this.version == null && parent != null) {
338 this.version = parent.getVersion();
339 }
340 }
341 if (this.packaging == null) {
342 this.packaging = model.getPackaging();
343 }
344 }
345
346
347
348
349
350
351 private Model generateModel() {
352 return Model.newBuilder()
353 .modelVersion("4.0.0")
354 .groupId(groupId)
355 .artifactId(artifactId)
356 .version(version)
357 .packaging(packaging)
358 .description("POM was created from install:install-file")
359 .build();
360 }
361
362
363
364
365
366
367
368
369 private Path generatePomFile() throws MojoException {
370 Model model = generateModel();
371 try {
372 Path pomFile = File.createTempFile("mvninstall", ".pom").toPath();
373 try (Writer writer = Files.newBufferedWriter(pomFile)) {
374 session.getService(ModelXmlFactory.class).write(model, writer);
375 }
376 return pomFile;
377 } catch (IOException e) {
378 throw new MojoException("Error writing temporary POM file: " + e.getMessage(), e);
379 }
380 }
381
382
383
384
385
386 private Path getLocalRepositoryFile(Artifact artifact) {
387 return session.getPathForLocalArtifact(artifact);
388 }
389
390
391
392
393 private String getExtension(final Path file) {
394 String filename = file.getFileName().toString();
395 int lastDot = filename.lastIndexOf('.');
396 if (lastDot > 0 && lastDot < filename.length() - 1) {
397 String ext = filename.substring(lastDot + 1);
398 return filename.regionMatches(lastDot + 1 - TAR.length(), TAR, 0, TAR.length()) ? TAR + ext : ext;
399 }
400 return "";
401 }
402
403
404
405
406 private boolean isValidId(String id) {
407 if (id == null) {
408 return false;
409 }
410 for (int i = 0; i < id.length(); i++) {
411 char c = id.charAt(i);
412 if (!(c >= 'a' && c <= 'z'
413 || c >= 'A' && c <= 'Z'
414 || c >= '0' && c <= '9'
415 || c == '-'
416 || c == '_'
417 || c == '.')) {
418 return false;
419 }
420 }
421 return true;
422 }
423
424
425
426
427 private boolean isValidVersion(String version) {
428 if (version == null) {
429 return false;
430 }
431 for (int i = version.length() - 1; i >= 0; i--) {
432 if (ILLEGAL_VERSION_CHARS.indexOf(version.charAt(i)) >= 0) {
433 return false;
434 }
435 }
436 return true;
437 }
438 }