1 package org.apache.maven.plugin.assembly.archive.archiver;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.plugin.assembly.filter.ContainerDescriptorHandler;
23 import org.codehaus.plexus.archiver.ArchiveEntry;
24 import org.codehaus.plexus.archiver.ArchiveFinalizer;
25 import org.codehaus.plexus.archiver.ArchivedFileSet;
26 import org.codehaus.plexus.archiver.Archiver;
27 import org.codehaus.plexus.archiver.ArchiverException;
28 import org.codehaus.plexus.archiver.FileSet;
29 import org.codehaus.plexus.archiver.FinalizerEnabled;
30 import org.codehaus.plexus.archiver.ResourceIterator;
31 import org.codehaus.plexus.archiver.util.DefaultArchivedFileSet;
32 import org.codehaus.plexus.archiver.util.DefaultFileSet;
33 import org.codehaus.plexus.components.io.fileselectors.FileInfo;
34 import org.codehaus.plexus.components.io.fileselectors.FileSelector;
35 import org.codehaus.plexus.components.io.resources.PlexusIoResource;
36 import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
37 import org.codehaus.plexus.logging.Logger;
38
39 import javax.annotation.Nonnull;
40 import java.io.File;
41 import java.io.FileInputStream;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.nio.charset.Charset;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.List;
48 import java.util.Map;
49
50
51
52
53
54
55
56
57
58
59
60
61 public class AssemblyProxyArchiver
62 implements Archiver
63 {
64
65 private final Archiver delegate;
66
67 private final ThreadLocal<Boolean> inPublicApi = new ThreadLocal<Boolean>();
68
69 private final Logger logger;
70
71 private final String assemblyWorkPath;
72
73 private String rootPrefix;
74
75 private FileSelector[] selectors;
76
77 private boolean forced;
78
79
80
81
82 private boolean useJvmChmod;
83
84 public AssemblyProxyArchiver( final String rootPrefix, final Archiver delegate,
85 final List<ContainerDescriptorHandler> containerDescriptorHandlers,
86 final List<FileSelector> extraSelectors, final List<ArchiveFinalizer> extraFinalizers,
87 final File assemblyWorkDir, final Logger logger )
88 {
89 this.rootPrefix = rootPrefix;
90 this.delegate = delegate;
91
92 assemblyWorkPath = assemblyWorkDir.getAbsolutePath().replace( '\\', '/' );
93
94 this.logger = logger;
95
96 if ( !"".equals( rootPrefix ) && !rootPrefix.endsWith( "/" ) )
97 {
98 this.rootPrefix += "/";
99 }
100
101 final List<FileSelector> selectors = new ArrayList<FileSelector>();
102
103 FinalizerEnabled finalizer = ( delegate instanceof FinalizerEnabled ) ? (FinalizerEnabled) delegate : null;
104
105 if ( containerDescriptorHandlers != null )
106 {
107 for ( final ContainerDescriptorHandler handler : containerDescriptorHandlers )
108 {
109 selectors.add( handler );
110
111 if ( finalizer != null )
112 {
113 finalizer.addArchiveFinalizer( handler );
114 }
115 }
116 }
117
118 if ( extraSelectors != null )
119 {
120 for ( final FileSelector selector : extraSelectors )
121 {
122 selectors.add( selector );
123 }
124 }
125
126 if ( ( extraFinalizers != null ) && finalizer != null )
127 {
128 for ( ArchiveFinalizer extraFinalizer : extraFinalizers )
129 {
130 finalizer.addArchiveFinalizer( extraFinalizer );
131 }
132 }
133
134 if ( !selectors.isEmpty() )
135 {
136 this.selectors = selectors.toArray( new FileSelector[selectors.size()] );
137 }
138 }
139
140
141
142
143 @Override
144 public void addArchivedFileSet( @Nonnull final File archiveFile, final String prefix, final String[] includes,
145 final String[] excludes )
146 {
147 inPublicApi.set( Boolean.TRUE );
148 try
149 {
150 final DefaultArchivedFileSet fs = new DefaultArchivedFileSet( archiveFile );
151
152 fs.setIncludes( includes );
153 fs.setExcludes( excludes );
154 fs.setPrefix( rootPrefix + prefix );
155 fs.setFileSelectors( selectors );
156
157 debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
158
159 delegate.addArchivedFileSet( fs );
160 }
161 finally
162 {
163 inPublicApi.set( null );
164 }
165 }
166
167 private void debug( final String message )
168 {
169 if ( ( logger != null ) && logger.isDebugEnabled() )
170 {
171 logger.debug( message );
172 }
173 }
174
175
176
177
178 @Override
179 public void addArchivedFileSet( @Nonnull final File archiveFile, final String prefix )
180 {
181 inPublicApi.set( Boolean.TRUE );
182 try
183 {
184 final DefaultArchivedFileSet fs = new DefaultArchivedFileSet( archiveFile );
185
186 fs.setPrefix( rootPrefix + prefix );
187 fs.setFileSelectors( selectors );
188
189 debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
190
191 delegate.addArchivedFileSet( fs );
192 }
193 finally
194 {
195 inPublicApi.set( null );
196 }
197 }
198
199
200
201
202 @Override
203 public void addArchivedFileSet( final File archiveFile, final String[] includes, final String[] excludes )
204 {
205 inPublicApi.set( Boolean.TRUE );
206 try
207 {
208 final DefaultArchivedFileSet fs = new DefaultArchivedFileSet( archiveFile );
209
210 fs.setIncludes( includes );
211 fs.setExcludes( excludes );
212 fs.setPrefix( rootPrefix );
213 fs.setFileSelectors( selectors );
214
215 debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
216
217 delegate.addArchivedFileSet( fs );
218 }
219 finally
220 {
221 inPublicApi.set( null );
222 }
223 }
224
225
226
227
228 @Override
229 public void addArchivedFileSet( @Nonnull final File archiveFile )
230 {
231 inPublicApi.set( Boolean.TRUE );
232 try
233 {
234 final DefaultArchivedFileSet fs = new DefaultArchivedFileSet( archiveFile );
235
236 fs.setPrefix( rootPrefix );
237 fs.setFileSelectors( selectors );
238
239 debug( "Adding archived file-set in: " + archiveFile + " to archive location: " + fs.getPrefix() );
240
241 delegate.addArchivedFileSet( fs );
242 }
243 finally
244 {
245 inPublicApi.set( null );
246 }
247 }
248
249
250
251
252 @Override
253 public void addDirectory( @Nonnull final File directory, final String prefix, final String[] includes,
254 final String[] excludes )
255 {
256 inPublicApi.set( Boolean.TRUE );
257 try
258 {
259 final DefaultFileSet fs = new DefaultFileSet();
260
261 fs.setDirectory( directory );
262 fs.setIncludes( includes );
263 fs.setExcludes( excludes );
264 fs.setPrefix( rootPrefix + prefix );
265 fs.setFileSelectors( selectors );
266
267 debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
268
269 doAddFileSet( fs );
270 }
271 finally
272 {
273 inPublicApi.set( null );
274 }
275 }
276
277
278
279
280 @Override
281 public void addSymlink( String symlinkName, String symlinkDestination )
282 {
283 inPublicApi.set( Boolean.TRUE );
284 try
285 {
286 delegate.addSymlink( symlinkName, symlinkDestination );
287 }
288 finally
289 {
290 inPublicApi.set( null );
291 }
292
293 }
294
295
296
297
298 @Override
299 public void addSymlink( String symlinkName, int permissions, String symlinkDestination )
300 {
301 inPublicApi.set( Boolean.TRUE );
302 try
303 {
304 delegate.addSymlink( symlinkName, permissions, symlinkDestination );
305 }
306 finally
307 {
308 inPublicApi.set( null );
309 }
310
311 }
312
313
314
315
316 @Override
317 public void addDirectory( @Nonnull final File directory, final String prefix )
318 {
319 inPublicApi.set( Boolean.TRUE );
320 try
321 {
322 final DefaultFileSet fs = new DefaultFileSet();
323
324 fs.setDirectory( directory );
325 fs.setPrefix( rootPrefix + prefix );
326 fs.setFileSelectors( selectors );
327
328 debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
329
330 doAddFileSet( fs );
331 }
332 finally
333 {
334 inPublicApi.set( null );
335 }
336 }
337
338
339
340
341 @Override
342 public void addDirectory( @Nonnull final File directory, final String[] includes, final String[] excludes )
343 {
344 inPublicApi.set( Boolean.TRUE );
345 try
346 {
347 final DefaultFileSet fs = new DefaultFileSet();
348
349 fs.setDirectory( directory );
350 fs.setIncludes( includes );
351 fs.setExcludes( excludes );
352 fs.setPrefix( rootPrefix );
353 fs.setFileSelectors( selectors );
354
355 debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
356
357 doAddFileSet( fs );
358 }
359 finally
360 {
361 inPublicApi.set( null );
362 }
363 }
364
365
366
367
368 @Override
369 public void addDirectory( @Nonnull final File directory )
370 {
371 inPublicApi.set( Boolean.TRUE );
372 try
373 {
374 final DefaultFileSet fs = new DefaultFileSet();
375
376 fs.setDirectory( directory );
377 fs.setPrefix( rootPrefix );
378 fs.setFileSelectors( selectors );
379
380 debug( "Adding directory file-set in: " + directory + " to archive location: " + fs.getPrefix() );
381
382 doAddFileSet( fs );
383 }
384 finally
385 {
386 inPublicApi.set( null );
387 }
388 }
389
390
391
392
393 @Override
394 public void addFile( @Nonnull final File inputFile, @Nonnull final String destFileName, final int permissions )
395 {
396 if ( acceptFile( inputFile ) )
397 {
398 inPublicApi.set( Boolean.TRUE );
399 try
400 {
401 debug( "Adding file: " + inputFile + " to archive location: " + rootPrefix + destFileName );
402
403 delegate.addFile( inputFile, rootPrefix + destFileName, permissions );
404 }
405 finally
406 {
407 inPublicApi.set( null );
408 }
409 }
410 }
411
412
413
414
415 @Override
416 public void addFile( @Nonnull final File inputFile, @Nonnull final String destFileName )
417 {
418 if ( acceptFile( inputFile ) )
419 {
420 inPublicApi.set( Boolean.TRUE );
421 try
422 {
423 debug( "Adding file: " + inputFile + " to archive location: " + rootPrefix + destFileName );
424
425 delegate.addFile( inputFile, rootPrefix + destFileName );
426 }
427 finally
428 {
429 inPublicApi.set( null );
430 }
431 }
432 }
433
434
435
436
437 @Override
438 public void createArchive()
439 throws IOException
440 {
441 inPublicApi.set( Boolean.TRUE );
442 try
443 {
444 delegate.setForced( forced );
445 delegate.createArchive();
446 }
447 finally
448 {
449 inPublicApi.set( null );
450 }
451 }
452
453
454
455
456 @Override
457 public int getDefaultDirectoryMode()
458 {
459 inPublicApi.set( Boolean.TRUE );
460 try
461 {
462 return delegate.getDefaultDirectoryMode();
463 }
464 finally
465 {
466 inPublicApi.set( null );
467 }
468 }
469
470
471
472
473 @Override
474 public void setDefaultDirectoryMode( final int mode )
475 {
476 inPublicApi.set( Boolean.TRUE );
477 try
478 {
479 delegate.setDefaultDirectoryMode( mode );
480 }
481 finally
482 {
483 inPublicApi.set( null );
484 }
485 }
486
487
488
489
490 @Override
491 public int getDefaultFileMode()
492 {
493 inPublicApi.set( Boolean.TRUE );
494 try
495 {
496 return delegate.getDefaultFileMode();
497 }
498 finally
499 {
500 inPublicApi.set( null );
501 }
502 }
503
504
505
506
507 @Override
508 public void setDefaultFileMode( final int mode )
509 {
510 inPublicApi.set( Boolean.TRUE );
511 try
512 {
513 delegate.setDefaultFileMode( mode );
514 }
515 finally
516 {
517 inPublicApi.set( null );
518 }
519 }
520
521
522
523
524 @Override
525 public File getDestFile()
526 {
527 inPublicApi.set( Boolean.TRUE );
528 try
529 {
530 return delegate.getDestFile();
531 }
532 finally
533 {
534 inPublicApi.set( null );
535 }
536 }
537
538
539
540
541 @Override
542 public void setDestFile( final File destFile )
543 {
544 inPublicApi.set( Boolean.TRUE );
545 try
546 {
547 delegate.setDestFile( destFile );
548 }
549 finally
550 {
551 inPublicApi.set( null );
552 }
553 }
554
555 @Override
556 @SuppressWarnings( { "deprecation" } )
557 public Map<String, ArchiveEntry> getFiles()
558 {
559 inPublicApi.set( Boolean.TRUE );
560 try
561 {
562 return delegate.getFiles();
563 }
564 finally
565 {
566 inPublicApi.set( null );
567 }
568 }
569
570
571
572
573 @Override
574 public boolean getIncludeEmptyDirs()
575 {
576 inPublicApi.set( Boolean.TRUE );
577 try
578 {
579 return delegate.getIncludeEmptyDirs();
580 }
581 finally
582 {
583 inPublicApi.set( null );
584 }
585 }
586
587
588
589
590 @Override
591 public void setIncludeEmptyDirs( final boolean includeEmptyDirs )
592 {
593 inPublicApi.set( Boolean.TRUE );
594 try
595 {
596 delegate.setIncludeEmptyDirs( includeEmptyDirs );
597 }
598 finally
599 {
600 inPublicApi.set( null );
601 }
602 }
603
604
605
606
607 @Override
608 public boolean isForced()
609 {
610 inPublicApi.set( Boolean.TRUE );
611 try
612 {
613 return delegate.isForced();
614 }
615 finally
616 {
617 inPublicApi.set( null );
618 }
619 }
620
621
622
623
624 @Override
625 public void setForced( final boolean forced )
626 {
627 inPublicApi.set( Boolean.TRUE );
628 try
629 {
630 this.forced = forced;
631 delegate.setForced( forced );
632 }
633 finally
634 {
635 inPublicApi.set( null );
636 }
637 }
638
639
640
641
642 @Override
643 public boolean isSupportingForced()
644 {
645 inPublicApi.set( Boolean.TRUE );
646 try
647 {
648 return delegate.isSupportingForced();
649 }
650 finally
651 {
652 inPublicApi.set( null );
653 }
654 }
655
656
657
658
659 @Override
660 public void setDotFileDirectory( final File dotFileDirectory )
661 {
662 throw new UnsupportedOperationException(
663 "Undocumented feature of plexus-archiver; this is not yet supported." );
664 }
665
666
667
668
669 @Override
670 public void addArchivedFileSet( final ArchivedFileSet fileSet )
671 {
672 inPublicApi.set( Boolean.TRUE );
673 try
674 {
675 final PrefixedArchivedFileSet fs = new PrefixedArchivedFileSet( fileSet, rootPrefix, selectors );
676
677 debug( "Adding archived file-set in: " + fileSet.getArchive() + " to archive location: " + fs.getPrefix() );
678
679 delegate.addArchivedFileSet( fs );
680 }
681 finally
682 {
683 inPublicApi.set( null );
684 }
685 }
686
687 @Override
688 public void addArchivedFileSet( ArchivedFileSet archivedFileSet, Charset charset )
689 {
690 inPublicApi.set( Boolean.TRUE );
691 try
692 {
693 final PrefixedArchivedFileSet fs = new PrefixedArchivedFileSet( archivedFileSet, rootPrefix, selectors );
694
695 debug( "Adding archived file-set in: " + archivedFileSet.getArchive() + " to archive location: "
696 + fs.getPrefix() );
697
698 delegate.addArchivedFileSet( fs, charset );
699 }
700 finally
701 {
702 inPublicApi.set( null );
703 }
704 }
705
706
707
708
709 @Override
710 public void addFileSet( @Nonnull final FileSet fileSet )
711 {
712 inPublicApi.set( Boolean.TRUE );
713 try
714 {
715 final PrefixedFileSet fs = new PrefixedFileSet( fileSet, rootPrefix, selectors );
716
717 debug( "Adding file-set in: " + fileSet.getDirectory() + " to archive location: " + fs.getPrefix() );
718
719 doAddFileSet( fs );
720 }
721 finally
722 {
723 inPublicApi.set( null );
724 }
725 }
726
727 private void doAddFileSet( final FileSet fs )
728 {
729 final String fsPath = fs.getDirectory().getAbsolutePath().replace( '\\', '/' );
730
731 if ( fsPath.equals( assemblyWorkPath ) )
732 {
733 logger.debug( "SKIPPING fileset with source directory matching assembly working-directory: " + fsPath );
734 }
735 else if ( assemblyWorkPath.startsWith( fsPath ) )
736 {
737 final List<String> newEx = new ArrayList<String>();
738 if ( fs.getExcludes() != null )
739 {
740 newEx.addAll( Arrays.asList( fs.getExcludes() ) );
741 }
742
743 final String workDirExclude = assemblyWorkPath.substring( fsPath.length() + 1 );
744
745 logger.debug(
746 "Adding exclude for assembly working-directory: " + workDirExclude + "\nFile-Set source directory: "
747 + fsPath );
748
749 newEx.add( workDirExclude );
750
751 final List<String> newIn = new ArrayList<String>();
752 if ( fs.getIncludes() != null )
753 {
754 for ( final String include : fs.getIncludes() )
755 {
756 if ( !include.startsWith( workDirExclude ) )
757 {
758 newIn.add( include );
759 }
760 }
761 }
762
763 final DefaultFileSet dfs = new DefaultFileSet();
764
765 dfs.setCaseSensitive( fs.isCaseSensitive() );
766 dfs.setDirectory( fs.getDirectory() );
767 dfs.setExcludes( newEx.toArray( new String[newEx.size()] ) );
768 dfs.setFileSelectors( fs.getFileSelectors() );
769 dfs.setIncludes( newIn.toArray( new String[newIn.size()] ) );
770 dfs.setIncludingEmptyDirectories( fs.isIncludingEmptyDirectories() );
771 dfs.setPrefix( fs.getPrefix() );
772 dfs.setUsingDefaultExcludes( fs.isUsingDefaultExcludes() );
773
774 delegate.addFileSet( dfs );
775 }
776 else
777 {
778 delegate.addFileSet( fs );
779 }
780 }
781
782 private boolean acceptFile( final File inputFile )
783 {
784 if ( !Boolean.TRUE.equals( inPublicApi.get() ) )
785 {
786 if ( selectors != null )
787 {
788 final FileInfo fileInfo = new DefaultFileInfo( inputFile );
789
790 for ( final FileSelector selector : selectors )
791 {
792 try
793 {
794 if ( !selector.isSelected( fileInfo ) )
795 {
796 return false;
797 }
798 }
799 catch ( final IOException e )
800 {
801 throw new ArchiverException(
802 "Error processing file: " + inputFile + " using selector: " + selector, e );
803 }
804 }
805 }
806 }
807
808 return true;
809 }
810
811
812
813
814 @Override
815 public void addResource( final PlexusIoResource resource, final String destFileName, final int permissions )
816 {
817 File file = new File( resource.getName() );
818 if ( acceptFile( file ) )
819 {
820
821 inPublicApi.set( Boolean.TRUE );
822 try
823 {
824 delegate.addResource( resource, rootPrefix + destFileName, permissions );
825 }
826 finally
827 {
828 inPublicApi.set( null );
829 }
830 }
831 }
832
833
834
835
836 @Override
837 public void addResources( final PlexusIoResourceCollection resources )
838 {
839 inPublicApi.set( Boolean.TRUE );
840 try
841 {
842 delegate.addResources( resources );
843 }
844 finally
845 {
846 inPublicApi.set( null );
847 }
848 }
849
850
851
852
853 @Override
854 @Nonnull
855 public ResourceIterator getResources()
856 {
857 return delegate.getResources();
858 }
859
860
861
862
863 @Override
864 public String getDuplicateBehavior()
865 {
866 return delegate.getDuplicateBehavior();
867 }
868
869
870
871
872 @Override
873 public void setDuplicateBehavior( final String duplicate )
874 {
875 inPublicApi.set( Boolean.TRUE );
876 try
877 {
878 delegate.setDuplicateBehavior( duplicate );
879 }
880 finally
881 {
882 inPublicApi.set( null );
883 }
884 }
885
886
887
888
889 @Override
890 public int getDirectoryMode()
891 {
892 return delegate.getDirectoryMode();
893 }
894
895
896
897
898 @Override
899 public void setDirectoryMode( final int mode )
900 {
901 inPublicApi.set( Boolean.TRUE );
902 try
903 {
904 delegate.setDirectoryMode( mode );
905 }
906 finally
907 {
908 inPublicApi.set( null );
909 }
910 }
911
912
913
914
915 @Override
916 public int getFileMode()
917 {
918 return delegate.getFileMode();
919 }
920
921
922
923
924 @Override
925 public void setFileMode( final int mode )
926 {
927 inPublicApi.set( Boolean.TRUE );
928 try
929 {
930 delegate.setFileMode( mode );
931 }
932 finally
933 {
934 inPublicApi.set( null );
935 }
936 }
937
938
939
940
941 @Override
942 public int getOverrideDirectoryMode()
943 {
944 return delegate.getOverrideDirectoryMode();
945 }
946
947
948
949
950 @Override
951 public int getOverrideFileMode()
952 {
953 return delegate.getOverrideFileMode();
954 }
955
956
957
958
959 @Override
960 public boolean isUseJvmChmod()
961 {
962 return useJvmChmod;
963 }
964
965
966
967
968 @Override
969 public void setUseJvmChmod( final boolean useJvmChmod )
970 {
971 this.useJvmChmod = useJvmChmod;
972 }
973
974
975
976
977 @Override
978 public boolean isIgnorePermissions()
979 {
980 return delegate.isIgnorePermissions();
981 }
982
983
984
985
986 @Override
987 public void setIgnorePermissions( final boolean ignorePermissions )
988 {
989 delegate.setIgnorePermissions( ignorePermissions );
990 }
991
992 private static final class DefaultFileInfo
993 implements FileInfo
994 {
995
996 private final File inputFile;
997
998 DefaultFileInfo( final File inputFile )
999 {
1000 this.inputFile = inputFile;
1001 }
1002
1003 @Override
1004 public InputStream getContents()
1005 throws IOException
1006 {
1007 return new FileInputStream( inputFile );
1008 }
1009
1010 @Override
1011 public String getName()
1012 {
1013 return inputFile.getName();
1014 }
1015
1016 @Override
1017 public boolean isDirectory()
1018 {
1019 return inputFile.isDirectory();
1020 }
1021
1022 @Override
1023 public boolean isFile()
1024 {
1025 return inputFile.isFile();
1026 }
1027
1028 @Override
1029 public boolean isSymbolicLink()
1030 {
1031 return false;
1032 }
1033 }
1034
1035 }