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