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