1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.deploy;
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.OutputStream;
26 import java.io.Reader;
27 import java.io.Writer;
28 import java.nio.file.Files;
29 import java.util.Enumeration;
30 import java.util.Objects;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarFile;
33 import java.util.regex.Pattern;
34
35 import org.apache.maven.artifact.ArtifactUtils;
36 import org.apache.maven.model.Model;
37 import org.apache.maven.model.Parent;
38 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
39 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
40 import org.apache.maven.plugin.MojoExecutionException;
41 import org.apache.maven.plugin.MojoFailureException;
42 import org.apache.maven.plugins.annotations.Mojo;
43 import org.apache.maven.plugins.annotations.Parameter;
44 import org.codehaus.plexus.util.FileUtils;
45 import org.codehaus.plexus.util.IOUtil;
46 import org.codehaus.plexus.util.StringUtils;
47 import org.codehaus.plexus.util.xml.ReaderFactory;
48 import org.codehaus.plexus.util.xml.WriterFactory;
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.ArtifactType;
53 import org.eclipse.aether.artifact.DefaultArtifact;
54 import org.eclipse.aether.deployment.DeployRequest;
55 import org.eclipse.aether.deployment.DeploymentException;
56 import org.eclipse.aether.repository.RemoteRepository;
57 import org.eclipse.aether.util.artifact.SubArtifact;
58
59
60
61
62
63
64 @Mojo(name = "deploy-file", requiresProject = false, threadSafe = true)
65 public class DeployFileMojo extends AbstractDeployMojo {
66
67
68
69 @Parameter(property = "groupId")
70 private String groupId;
71
72
73
74
75 @Parameter(property = "artifactId")
76 private String artifactId;
77
78
79
80
81 @Parameter(property = "version")
82 private String version;
83
84
85
86
87
88
89
90 @Parameter(property = "packaging")
91 private String packaging;
92
93
94
95
96 @Parameter(property = "generatePom.description")
97 private String description;
98
99
100
101
102 @Parameter(property = "file", required = true)
103 private File file;
104
105
106
107
108
109
110 @Parameter(property = "javadoc")
111 private File javadoc;
112
113
114
115
116
117
118 @Parameter(property = "sources")
119 private File sources;
120
121
122
123
124
125 @Parameter(property = "repositoryId", defaultValue = "remote-repository", required = true)
126 private String repositoryId;
127
128
129
130
131
132 @Parameter(property = "url", required = true)
133 private String url;
134
135
136
137
138 @Parameter(property = "pomFile")
139 private File pomFile;
140
141
142
143
144 @Parameter(property = "generatePom", defaultValue = "true")
145 private boolean generatePom;
146
147
148
149
150 @Parameter(property = "classifier")
151 private String classifier;
152
153
154
155
156
157 @Parameter(property = "types")
158 private String types;
159
160
161
162
163
164 @Parameter(property = "classifiers")
165 private String classifiers;
166
167
168
169
170
171 @Parameter(property = "files")
172 private String files;
173
174
175
176
177
178
179
180
181
182
183
184
185 @Parameter(property = "maven.deploy.file.skip", defaultValue = "false")
186 private String skip = Boolean.FALSE.toString();
187
188 void initProperties() throws MojoExecutionException {
189 if (pomFile == null) {
190 boolean foundPom = false;
191 try (JarFile jarFile = new JarFile(file)) {
192 Pattern pomEntry = Pattern.compile("META-INF/maven/.*/pom\\.xml");
193 Enumeration<JarEntry> jarEntries = jarFile.entries();
194
195 while (jarEntries.hasMoreElements()) {
196 JarEntry entry = jarEntries.nextElement();
197
198 if (pomEntry.matcher(entry.getName()).matches()) {
199 getLog().debug("Using " + entry.getName() + " as pomFile");
200 foundPom = true;
201 String base = file.getName();
202 if (base.indexOf('.') > 0) {
203 base = base.substring(0, base.lastIndexOf('.'));
204 }
205 pomFile = new File(file.getParentFile(), base + ".pom");
206
207 try (InputStream pomInputStream = jarFile.getInputStream(entry)) {
208 try (OutputStream pomOutputStream = Files.newOutputStream(pomFile.toPath())) {
209 IOUtil.copy(pomInputStream, pomOutputStream);
210 }
211 processModel(readModel(pomFile));
212 break;
213 }
214 }
215 }
216
217 if (!foundPom) {
218 getLog().info("pom.xml not found in " + file.getName());
219 }
220 } catch (IOException e) {
221
222 }
223 } else {
224 processModel(readModel(pomFile));
225 }
226
227 if (packaging == null && file != null) {
228 packaging = getExtension(file);
229 }
230 }
231
232 public void execute() throws MojoExecutionException, MojoFailureException {
233 if (Boolean.parseBoolean(skip)
234 || ("releases".equals(skip) && !ArtifactUtils.isSnapshot(version))
235 || ("snapshots".equals(skip) && ArtifactUtils.isSnapshot(version))) {
236 getLog().info("Skipping artifact deployment");
237 return;
238 }
239
240 if (!file.exists()) {
241 throw new MojoExecutionException(file.getPath() + " not found.");
242 }
243
244 initProperties();
245
246 RemoteRepository remoteRepository = getRemoteRepository(repositoryId, url);
247
248 if (StringUtils.isEmpty(remoteRepository.getProtocol())) {
249 throw new MojoExecutionException("No transfer protocol found.");
250 }
251
252 if (groupId == null || artifactId == null || version == null || packaging == null) {
253 throw new MojoExecutionException("The artifact information is incomplete: 'groupId', 'artifactId', "
254 + "'version' and 'packaging' are required.");
255 }
256
257 if (!isValidId(groupId) || !isValidId(artifactId) || !isValidVersion(version)) {
258 throw new MojoExecutionException("The artifact information is not valid: uses invalid characters.");
259 }
260
261 failIfOffline();
262 warnIfAffectedPackagingAndMaven(packaging);
263
264 DeployRequest deployRequest = new DeployRequest();
265 deployRequest.setRepository(remoteRepository);
266
267 boolean isFilePom = classifier == null && "pom".equals(packaging);
268 if (!isFilePom) {
269 ArtifactType artifactType =
270 session.getRepositorySession().getArtifactTypeRegistry().get(packaging);
271 if (artifactType != null
272 && (classifier == null || classifier.isEmpty())
273 && !StringUtils.isEmpty(artifactType.getClassifier())) {
274 classifier = artifactType.getClassifier();
275 }
276 }
277 Artifact mainArtifact = new DefaultArtifact(
278 groupId, artifactId, classifier, isFilePom ? "pom" : getExtension(file), version)
279 .setFile(file);
280 deployRequest.addArtifact(mainArtifact);
281
282 File artifactLocalFile = getLocalRepositoryFile(session.getRepositorySession(), mainArtifact);
283
284 if (file.equals(artifactLocalFile)) {
285 throw new MojoFailureException("Cannot deploy artifact from the local repository: " + file);
286 }
287
288 File temporaryPom = null;
289 if (!"pom".equals(packaging)) {
290 if (pomFile != null) {
291 deployRequest.addArtifact(new SubArtifact(mainArtifact, "", "pom", pomFile));
292 } else if (generatePom) {
293 temporaryPom = generatePomFile();
294 getLog().debug("Deploying generated POM");
295 deployRequest.addArtifact(new SubArtifact(mainArtifact, "", "pom", temporaryPom));
296 } else {
297 getLog().debug("Skipping deploying POM");
298 }
299 }
300
301 if (sources != null) {
302 deployRequest.addArtifact(new SubArtifact(mainArtifact, "sources", "jar", sources));
303 }
304
305 if (javadoc != null) {
306 deployRequest.addArtifact(new SubArtifact(mainArtifact, "javadoc", "jar", javadoc));
307 }
308
309 if (files != null) {
310 if (types == null) {
311 throw new MojoExecutionException("You must specify 'types' if you specify 'files'");
312 }
313 if (classifiers == null) {
314 throw new MojoExecutionException("You must specify 'classifiers' if you specify 'files'");
315 }
316 int filesLength = StringUtils.countMatches(files, ",");
317 int typesLength = StringUtils.countMatches(types, ",");
318 int classifiersLength = StringUtils.countMatches(classifiers, ",");
319 if (typesLength != filesLength) {
320 throw new MojoExecutionException("You must specify the same number of entries in 'files' and "
321 + "'types' (respectively " + filesLength + " and " + typesLength + " entries )");
322 }
323 if (classifiersLength != filesLength) {
324 throw new MojoExecutionException("You must specify the same number of entries in 'files' and "
325 + "'classifiers' (respectively " + filesLength + " and " + classifiersLength + " entries )");
326 }
327 int fi = 0;
328 int ti = 0;
329 int ci = 0;
330 for (int i = 0; i <= filesLength; i++) {
331 int nfi = files.indexOf(',', fi);
332 if (nfi == -1) {
333 nfi = files.length();
334 }
335 int nti = types.indexOf(',', ti);
336 if (nti == -1) {
337 nti = types.length();
338 }
339 int nci = classifiers.indexOf(',', ci);
340 if (nci == -1) {
341 nci = classifiers.length();
342 }
343 File file = new File(files.substring(fi, nfi));
344 if (!file.isFile()) {
345
346 file = new File(files.substring(fi, nfi));
347 }
348 if (file.isFile()) {
349 String extension = getExtension(file);
350 ArtifactType artifactType = session.getRepositorySession()
351 .getArtifactTypeRegistry()
352 .get(types.substring(ti, nti).trim());
353 if (artifactType != null && !Objects.equals(extension, artifactType.getExtension())) {
354 extension = artifactType.getExtension();
355 }
356
357 deployRequest.addArtifact(new SubArtifact(
358 mainArtifact, classifiers.substring(ci, nci).trim(), extension, file));
359 } else {
360 throw new MojoExecutionException("Specified side artifact " + file + " does not exist");
361 }
362 fi = nfi + 1;
363 ti = nti + 1;
364 ci = nci + 1;
365 }
366 } else {
367 if (types != null) {
368 throw new MojoExecutionException("You must specify 'files' if you specify 'types'");
369 }
370 if (classifiers != null) {
371 throw new MojoExecutionException("You must specify 'files' if you specify 'classifiers'");
372 }
373 }
374
375 try {
376 repositorySystem.deploy(session.getRepositorySession(), deployRequest);
377 } catch (DeploymentException e) {
378 throw new MojoExecutionException(e.getMessage(), e);
379 } finally {
380 if (temporaryPom != null) {
381
382 temporaryPom.delete();
383 }
384 }
385 }
386
387
388
389
390
391 private File getLocalRepositoryFile(RepositorySystemSession session, Artifact artifact) {
392 String path = session.getLocalRepositoryManager().getPathForLocalArtifact(artifact);
393 return new File(session.getLocalRepository().getBasedir(), path);
394 }
395
396
397
398
399
400
401 private void processModel(Model model) {
402 Parent parent = model.getParent();
403
404 if (this.groupId == null) {
405 this.groupId = model.getGroupId();
406 if (this.groupId == null && parent != null) {
407 this.groupId = parent.getGroupId();
408 }
409 }
410 if (this.artifactId == null) {
411 this.artifactId = model.getArtifactId();
412 }
413 if (this.version == null) {
414 this.version = model.getVersion();
415 if (this.version == null && parent != null) {
416 this.version = parent.getVersion();
417 }
418 }
419 if (this.packaging == null) {
420 this.packaging = model.getPackaging();
421 }
422 }
423
424
425
426
427
428
429
430
431 Model readModel(File pomFile) throws MojoExecutionException {
432 try (Reader reader = ReaderFactory.newXmlReader(pomFile)) {
433 return new MavenXpp3Reader().read(reader);
434 } catch (FileNotFoundException e) {
435 throw new MojoExecutionException("POM not found " + pomFile, e);
436 } catch (IOException e) {
437 throw new MojoExecutionException("Error reading POM " + pomFile, e);
438 } catch (XmlPullParserException e) {
439 throw new MojoExecutionException("Error parsing POM " + pomFile, e);
440 }
441 }
442
443
444
445
446
447
448
449 private File generatePomFile() throws MojoExecutionException {
450 Model model = generateModel();
451
452 try {
453 File tempFile = File.createTempFile("mvndeploy", ".pom");
454 tempFile.deleteOnExit();
455
456 try (Writer fw = WriterFactory.newXmlWriter(tempFile)) {
457 new MavenXpp3Writer().write(fw, model);
458 }
459
460 return tempFile;
461 } catch (IOException e) {
462 throw new MojoExecutionException("Error writing temporary pom file: " + e.getMessage(), e);
463 }
464 }
465
466
467
468
469
470
471 private Model generateModel() {
472 Model model = new Model();
473
474 model.setModelVersion("4.0.0");
475
476 model.setGroupId(groupId);
477 model.setArtifactId(artifactId);
478 model.setVersion(version);
479 model.setPackaging(packaging);
480
481 model.setDescription(description);
482
483 return model;
484 }
485
486 void setGroupId(String groupId) {
487 this.groupId = groupId;
488 }
489
490 void setArtifactId(String artifactId) {
491 this.artifactId = artifactId;
492 }
493
494 void setVersion(String version) {
495 this.version = version;
496 }
497
498 void setPackaging(String packaging) {
499 this.packaging = packaging;
500 }
501
502 void setPomFile(File pomFile) {
503 this.pomFile = pomFile;
504 }
505
506 String getGroupId() {
507 return groupId;
508 }
509
510 String getArtifactId() {
511 return artifactId;
512 }
513
514 String getVersion() {
515 return version;
516 }
517
518 String getPackaging() {
519 return packaging;
520 }
521
522 File getFile() {
523 return file;
524 }
525
526 String getClassifier() {
527 return classifier;
528 }
529
530 void setClassifier(String classifier) {
531 this.classifier = classifier;
532 }
533
534
535
536
537
538
539 private String getExtension(final File file) {
540 String filename = file.getName();
541 if (filename.contains(".tar.")) {
542 return "tar." + FileUtils.getExtension(filename);
543 } else {
544 return FileUtils.getExtension(filename);
545 }
546 }
547
548
549
550
551 private boolean isValidId(String id) {
552 if (id == null) {
553 return false;
554 }
555 for (int i = 0; i < id.length(); i++) {
556 char c = id.charAt(i);
557 if (!(c >= 'a' && c <= 'z'
558 || c >= 'A' && c <= 'Z'
559 || c >= '0' && c <= '9'
560 || c == '-'
561 || c == '_'
562 || c == '.')) {
563 return false;
564 }
565 }
566 return true;
567 }
568
569 private static final String ILLEGAL_VERSION_CHARS = "\\/:\"<>|?*[](){},";
570
571
572
573
574 private boolean isValidVersion(String version) {
575 if (version == null) {
576 return false;
577 }
578 for (int i = version.length() - 1; i >= 0; i--) {
579 if (ILLEGAL_VERSION_CHARS.indexOf(version.charAt(i)) >= 0) {
580 return false;
581 }
582 }
583 return true;
584 }
585 }