1 package org.apache.maven.plugins.shade.mojo;
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.artifact.Artifact;
23 import org.apache.maven.artifact.repository.ArtifactRepository;
24 import org.apache.maven.execution.MavenSession;
25 import org.apache.maven.model.Dependency;
26 import org.apache.maven.model.Exclusion;
27 import org.apache.maven.model.Model;
28 import org.apache.maven.plugin.AbstractMojo;
29 import org.apache.maven.plugin.MojoExecutionException;
30 import org.apache.maven.plugins.annotations.Component;
31 import org.apache.maven.plugins.annotations.LifecyclePhase;
32 import org.apache.maven.plugins.annotations.Mojo;
33 import org.apache.maven.plugins.annotations.Parameter;
34 import org.apache.maven.plugins.annotations.ResolutionScope;
35 import org.apache.maven.plugins.shade.ShadeRequest;
36 import org.apache.maven.plugins.shade.Shader;
37 import org.apache.maven.plugins.shade.filter.Filter;
38 import org.apache.maven.plugins.shade.filter.MinijarFilter;
39 import org.apache.maven.plugins.shade.filter.SimpleFilter;
40 import org.apache.maven.plugins.shade.pom.PomWriter;
41 import org.apache.maven.plugins.shade.relocation.Relocator;
42 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
43 import org.apache.maven.plugins.shade.resource.ManifestResourceTransformer;
44 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
45 import org.apache.maven.project.DefaultProjectBuildingRequest;
46 import org.apache.maven.project.MavenProject;
47 import org.apache.maven.project.MavenProjectHelper;
48 import org.apache.maven.project.ProjectBuilder;
49 import org.apache.maven.project.ProjectBuildingException;
50 import org.apache.maven.project.ProjectBuildingRequest;
51 import org.apache.maven.project.ProjectBuildingResult;
52 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
53 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
54 import org.apache.maven.shared.dependency.graph.DependencyNode;
55 import org.apache.maven.shared.transfer.artifact.DefaultArtifactCoordinate;
56 import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver;
57 import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException;
58 import org.codehaus.plexus.util.IOUtil;
59 import org.codehaus.plexus.util.WriterFactory;
60
61 import java.io.File;
62 import java.io.FileInputStream;
63 import java.io.FileOutputStream;
64 import java.io.IOException;
65 import java.io.InputStream;
66 import java.io.OutputStream;
67 import java.io.Writer;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Collections;
71 import java.util.HashMap;
72 import java.util.HashSet;
73 import java.util.LinkedHashSet;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Set;
77
78 import javax.inject.Inject;
79 import static org.apache.maven.plugins.shade.resource.UseDependencyReducedPom.createPomReplaceTransformers;
80
81
82
83
84
85
86
87
88
89
90 @Mojo( name = "shade", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true, requiresDependencyResolution = ResolutionScope.RUNTIME )
91
92 public class ShadeMojo
93 extends AbstractMojo
94 {
95
96
97
98 @Parameter( defaultValue = "${session}", readonly = true, required = true )
99 private MavenSession session;
100
101
102
103
104 @Parameter( defaultValue = "${project}", readonly = true, required = true )
105 private MavenProject project;
106
107 @Component
108 private MavenProjectHelper projectHelper;
109
110 @Component( hint = "default", role = org.apache.maven.plugins.shade.Shader.class )
111 private Shader shader;
112
113
114
115
116 @Component
117 private DependencyGraphBuilder dependencyGraphBuilder;
118
119
120
121
122 @Component
123 private ProjectBuilder projectBuilder;
124
125
126
127
128 @Parameter( readonly = true, required = true, defaultValue = "${project.remoteArtifactRepositories}" )
129 protected List<ArtifactRepository> remoteArtifactRepositories;
130
131
132
133
134 @Parameter( readonly = true, required = true, defaultValue = "${localRepository}" )
135 protected ArtifactRepository localRepository;
136
137
138
139
140 @Component
141 protected ArtifactResolver artifactResolver;
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162 @Parameter
163 private ArtifactSet artifactSet;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 @SuppressWarnings( "MismatchedReadAndWriteOfArray" )
186 @Parameter
187 private PackageRelocation[] relocations;
188
189
190
191
192
193 @Parameter
194 private ResourceTransformer[] transformers;
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 @SuppressWarnings( "MismatchedReadAndWriteOfArray" )
219 @Parameter
220 private ArchiveFilter[] filters;
221
222
223
224
225 @Parameter( defaultValue = "${project.build.directory}" )
226 private File outputDirectory;
227
228
229
230
231
232
233
234
235 @Parameter
236 private String finalName;
237
238
239
240
241
242
243 @Parameter( defaultValue = "${project.artifactId}" )
244 private String shadedArtifactId;
245
246
247
248
249 @Parameter
250 private String shadedGroupFilter;
251
252
253
254
255
256 @Parameter
257 private boolean shadedArtifactAttached;
258
259
260
261
262
263
264
265
266 @Parameter( defaultValue = "true" )
267 private boolean createDependencyReducedPom;
268
269
270
271
272
273
274
275
276 @Parameter( defaultValue = "${basedir}/dependency-reduced-pom.xml" )
277 private File dependencyReducedPomLocation;
278
279
280
281
282
283
284
285
286 @Parameter( defaultValue = "false" )
287 private boolean generateUniqueDependencyReducedPom;
288
289
290
291
292
293
294
295 @Parameter( defaultValue = "false" )
296 private boolean useDependencyReducedPomInJar;
297
298
299
300
301 @Parameter
302 private boolean keepDependenciesWithProvidedScope;
303
304
305
306
307
308 @Parameter
309 private boolean promoteTransitiveDependencies;
310
311
312
313
314 @Parameter( defaultValue = "shaded" )
315 private String shadedClassifierName;
316
317
318
319
320 @Parameter
321 private boolean createSourcesJar;
322
323
324
325
326 @Parameter
327 private boolean createTestSourcesJar;
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 @Parameter( property = "shadeSourcesContent", defaultValue = "false" )
345 private boolean shadeSourcesContent;
346
347
348
349
350
351
352
353 @Parameter
354 private boolean minimizeJar;
355
356
357
358
359
360
361
362
363
364 @Parameter
365 private File outputFile;
366
367
368
369
370
371
372 @Parameter
373 private String shaderHint;
374
375
376
377
378
379
380
381
382
383 @Parameter( defaultValue = "false" )
384 private boolean useBaseVersion;
385
386
387
388
389 @Parameter( defaultValue = "false" )
390 private boolean shadeTestJar;
391
392
393
394
395 @Inject
396 private Map<String, Shader> shaders;
397
398
399
400
401
402 @Parameter( defaultValue = "false" )
403 private boolean skip;
404
405
406
407
408 public void execute()
409 throws MojoExecutionException
410 {
411 if ( skip )
412 {
413 getLog().info( "Shading has been skipped." );
414 return;
415 }
416
417 setupHintedShader();
418
419 Set<File> artifacts = new LinkedHashSet<>();
420 Set<String> artifactIds = new LinkedHashSet<>();
421 Set<File> sourceArtifacts = new LinkedHashSet<>();
422 Set<File> testArtifacts = new LinkedHashSet<>();
423 Set<File> testSourceArtifacts = new LinkedHashSet<>();
424
425 ArtifactSelector artifactSelector =
426 new ArtifactSelector( project.getArtifact(), artifactSet, shadedGroupFilter );
427
428 if ( artifactSelector.isSelected( project.getArtifact() ) && !"pom".equals( project.getArtifact().getType() ) )
429 {
430 if ( invalidMainArtifact() )
431 {
432 createErrorOutput();
433 throw new MojoExecutionException( "Failed to create shaded artifact, "
434 + "project main artifact does not exist." );
435 }
436
437 artifacts.add( project.getArtifact().getFile() );
438
439 if ( createSourcesJar )
440 {
441 File file = shadedSourcesArtifactFile();
442 if ( file.isFile() )
443 {
444 sourceArtifacts.add( file );
445 }
446 }
447
448 if ( shadeTestJar )
449 {
450 File file = shadedTestArtifactFile();
451 if ( file.isFile() )
452 {
453 testArtifacts.add( file );
454 }
455 }
456
457 if ( createTestSourcesJar )
458 {
459 File file = shadedTestSourcesArtifactFile();
460 if ( file.isFile() )
461 {
462 testSourceArtifacts.add( file );
463 }
464 }
465 }
466
467 processArtifactSelectors( artifacts, artifactIds, sourceArtifacts, testArtifacts, testSourceArtifacts,
468 artifactSelector );
469
470 File outputJar = ( outputFile != null ) ? outputFile : shadedArtifactFileWithClassifier();
471 File sourcesJar = shadedSourceArtifactFileWithClassifier();
472 File testJar = shadedTestArtifactFileWithClassifier();
473 File testSourcesJar = shadedTestSourceArtifactFileWithClassifier();
474
475
476 try
477 {
478 List<Filter> filters = getFilters();
479
480 List<Relocator> relocators = getRelocators();
481
482 List<ResourceTransformer> resourceTransformers = getResourceTransformers();
483
484 if ( createDependencyReducedPom )
485 {
486 createDependencyReducedPom( artifactIds );
487
488 if ( useDependencyReducedPomInJar )
489 {
490
491 resourceTransformers = new ArrayList<>( resourceTransformers );
492 resourceTransformers.addAll(
493 createPomReplaceTransformers( project, dependencyReducedPomLocation ) );
494 }
495 }
496
497 ShadeRequest shadeRequest = shadeRequest( "jar", artifacts, outputJar, filters, relocators,
498 resourceTransformers );
499
500 shader.shade( shadeRequest );
501
502 if ( createSourcesJar )
503 {
504 ShadeRequest shadeSourcesRequest =
505 createShadeSourcesRequest( "sources-jar", sourceArtifacts, sourcesJar, filters, relocators,
506 resourceTransformers );
507
508 shader.shade( shadeSourcesRequest );
509 }
510
511 if ( shadeTestJar )
512 {
513 ShadeRequest shadeTestRequest =
514 shadeRequest( "test-jar", testArtifacts, testJar, filters, relocators, resourceTransformers );
515
516 shader.shade( shadeTestRequest );
517 }
518
519 if ( createTestSourcesJar )
520 {
521 ShadeRequest shadeTestSourcesRequest =
522 createShadeSourcesRequest( "test-sources-jar", testSourceArtifacts, testSourcesJar, filters,
523 relocators, resourceTransformers );
524
525 shader.shade( shadeTestSourcesRequest );
526 }
527
528 if ( outputFile == null )
529 {
530 boolean renamed = false;
531
532
533
534
535 if ( finalName != null && finalName.length() > 0
536 && !finalName.equals( project.getBuild().getFinalName() ) )
537 {
538 String finalFileName = finalName + "." + project.getArtifact().getArtifactHandler().getExtension();
539 File finalFile = new File( outputDirectory, finalFileName );
540 replaceFile( finalFile, outputJar );
541 outputJar = finalFile;
542
543
544 if ( createSourcesJar )
545 {
546 finalFileName = finalName + "-sources.jar";
547 finalFile = new File( outputDirectory, finalFileName );
548 replaceFile( finalFile, sourcesJar );
549 sourcesJar = finalFile;
550 }
551
552
553 if ( shadeTestJar )
554 {
555 finalFileName = finalName + "-tests.jar";
556 finalFile = new File( outputDirectory, finalFileName );
557 replaceFile( finalFile, testJar );
558 testJar = finalFile;
559 }
560
561 if ( createTestSourcesJar )
562 {
563 finalFileName = finalName + "-test-sources.jar";
564 finalFile = new File( outputDirectory, finalFileName );
565 replaceFile( finalFile, testSourcesJar );
566 testSourcesJar = finalFile;
567 }
568
569 renamed = true;
570 }
571
572 if ( shadedArtifactAttached )
573 {
574 getLog().info( "Attaching shaded artifact." );
575 projectHelper.attachArtifact( project, project.getArtifact().getType(), shadedClassifierName,
576 outputJar );
577 if ( createSourcesJar )
578 {
579 projectHelper.attachArtifact( project, "java-source", shadedClassifierName + "-sources",
580 sourcesJar );
581 }
582
583 if ( shadeTestJar )
584 {
585 projectHelper.attachArtifact( project, "test-jar", shadedClassifierName + "-tests",
586 testJar );
587 }
588
589 if ( createTestSourcesJar )
590 {
591 projectHelper.attachArtifact( project, "java-source",
592 shadedClassifierName + "-test-sources", testSourcesJar );
593 }
594 }
595 else if ( !renamed )
596 {
597 getLog().info( "Replacing original artifact with shaded artifact." );
598 File originalArtifact = project.getArtifact().getFile();
599 if ( originalArtifact != null )
600 {
601 replaceFile( originalArtifact, outputJar );
602
603 if ( createSourcesJar )
604 {
605 getLog().info( "Replacing original source artifact with shaded source artifact." );
606 File shadedSources = shadedSourcesArtifactFile();
607
608 replaceFile( shadedSources, sourcesJar );
609
610 projectHelper.attachArtifact( project, "java-source", "sources", shadedSources );
611 }
612
613 if ( shadeTestJar )
614 {
615 getLog().info( "Replacing original test artifact with shaded test artifact." );
616 File shadedTests = shadedTestArtifactFile();
617
618 replaceFile( shadedTests, testJar );
619
620 projectHelper.attachArtifact( project, "test-jar", shadedTests );
621 }
622
623 if ( createTestSourcesJar )
624 {
625 getLog().info( "Replacing original test source artifact "
626 + "with shaded test source artifact." );
627 File shadedTestSources = shadedTestSourcesArtifactFile();
628
629 replaceFile( shadedTestSources, testSourcesJar );
630
631 projectHelper.attachArtifact( project, "java-source", "test-sources",
632 shadedTestSources );
633 }
634 }
635 }
636 }
637 }
638 catch ( Exception e )
639 {
640 throw new MojoExecutionException( "Error creating shaded jar: " + e.getMessage(), e );
641 }
642 }
643
644 private void createErrorOutput()
645 {
646 getLog().error( "The project main artifact does not exist. This could have the following" );
647 getLog().error( "reasons:" );
648 getLog().error( "- You have invoked the goal directly from the command line. This is not" );
649 getLog().error( " supported. Please add the goal to the default lifecycle via an" );
650 getLog().error( " <execution> element in your POM and use \"mvn package\" to have it run." );
651 getLog().error( "- You have bound the goal to a lifecycle phase before \"package\". Please" );
652 getLog().error( " remove this binding from your POM such that the goal will be run in" );
653 getLog().error( " the proper phase." );
654 getLog().error( "- You removed the configuration of the maven-jar-plugin that produces the main artifact." );
655 }
656
657 private ShadeRequest shadeRequest( String shade, Set<File> artifacts, File outputJar, List<Filter> filters,
658 List<Relocator> relocators, List<ResourceTransformer> resourceTransformers )
659 {
660 ShadeRequest shadeRequest = new ShadeRequest();
661 shadeRequest.setJars( artifacts );
662 shadeRequest.setUberJar( outputJar );
663 shadeRequest.setFilters( filters );
664 shadeRequest.setRelocators( relocators );
665 shadeRequest.setResourceTransformers( toResourceTransformers( shade, resourceTransformers ) );
666 return shadeRequest;
667 }
668
669 private ShadeRequest createShadeSourcesRequest( String shade, Set<File> testArtifacts, File testJar,
670 List<Filter> filters, List<Relocator> relocators,
671 List<ResourceTransformer> resourceTransformers )
672 {
673 ShadeRequest shadeSourcesRequest =
674 shadeRequest( shade, testArtifacts, testJar, filters, relocators, resourceTransformers );
675 shadeSourcesRequest.setShadeSourcesContent( shadeSourcesContent );
676 return shadeSourcesRequest;
677 }
678
679 private void setupHintedShader()
680 throws MojoExecutionException
681 {
682 if ( shaderHint != null )
683 {
684 shader = shaders.get( shaderHint );
685
686 if ( shader == null )
687 {
688 throw new MojoExecutionException(
689 "unable to lookup own Shader implementation with hint: '" + shaderHint + "'"
690 );
691 }
692 }
693 }
694
695 private void processArtifactSelectors( Set<File> artifacts, Set<String> artifactIds, Set<File> sourceArtifacts,
696 Set<File> testArtifacts, Set<File> testSourceArtifacts,
697 ArtifactSelector artifactSelector )
698 {
699
700 List<String> excludedArtifacts = new ArrayList<>();
701 List<String> pomArtifacts = new ArrayList<>();
702 List<String> emptySourceArtifacts = new ArrayList<>();
703 List<String> emptyTestArtifacts = new ArrayList<>();
704 List<String> emptyTestSourceArtifacts = new ArrayList<>();
705
706 for ( Artifact artifact : project.getArtifacts() )
707 {
708 if ( !artifactSelector.isSelected( artifact ) )
709 {
710 excludedArtifacts.add( artifact.getId() );
711
712 continue;
713 }
714
715 if ( "pom".equals( artifact.getType() ) )
716 {
717 pomArtifacts.add( artifact.getId() );
718 continue;
719 }
720
721 getLog().info( "Including " + artifact.getId() + " in the shaded jar." );
722
723 artifacts.add( artifact.getFile() );
724 artifactIds.add( getId( artifact ) );
725
726 if ( createSourcesJar )
727 {
728 File file = resolveArtifactForClassifier( artifact, "sources" );
729 if ( file != null )
730 {
731 if ( file.length() > 0 )
732 {
733 sourceArtifacts.add( file );
734 }
735 else
736 {
737 emptySourceArtifacts.add( artifact.getArtifactId() );
738 }
739 }
740 }
741
742 if ( shadeTestJar )
743 {
744 File file = resolveArtifactForClassifier( artifact, "tests" );
745 if ( file != null )
746 {
747 if ( file.length() > 0 )
748 {
749 testArtifacts.add( file );
750 }
751 else
752 {
753 emptyTestArtifacts.add( artifact.getId() );
754 }
755 }
756 }
757
758 if ( createTestSourcesJar )
759 {
760 File file = resolveArtifactForClassifier( artifact, "test-sources" );
761 if ( file != null )
762 {
763 testSourceArtifacts.add( file );
764 }
765 else
766 {
767 emptyTestSourceArtifacts.add( artifact.getId() );
768 }
769 }
770 }
771
772 for ( String artifactId : excludedArtifacts )
773 {
774 getLog().info( "Excluding " + artifactId + " from the shaded jar." );
775 }
776 for ( String artifactId : pomArtifacts )
777 {
778 getLog().info( "Skipping pom dependency " + artifactId + " in the shaded jar." );
779 }
780 for ( String artifactId : emptySourceArtifacts )
781 {
782 getLog().warn( "Skipping empty source jar " + artifactId + "." );
783 }
784 for ( String artifactId : emptyTestArtifacts )
785 {
786 getLog().warn( "Skipping empty test jar " + artifactId + "." );
787 }
788 for ( String artifactId : emptyTestArtifacts )
789 {
790 getLog().warn( "Skipping empty test source jar " + artifactId + "." );
791 }
792 }
793
794 private boolean invalidMainArtifact()
795 {
796 return project.getArtifact().getFile() == null || !project.getArtifact().getFile().isFile();
797 }
798
799 private void replaceFile( File oldFile, File newFile )
800 throws MojoExecutionException
801 {
802 getLog().info( "Replacing " + oldFile + " with " + newFile );
803
804 File origFile = new File( outputDirectory, "original-" + oldFile.getName() );
805 if ( oldFile.exists() && !oldFile.renameTo( origFile ) )
806 {
807
808 System.gc();
809 System.gc();
810
811 if ( !oldFile.renameTo( origFile ) )
812 {
813
814 try
815 {
816 copyFiles( oldFile, origFile );
817 }
818 catch ( IOException ex )
819 {
820
821 getLog().warn( ex );
822 }
823 }
824 }
825 if ( !newFile.renameTo( oldFile ) )
826 {
827
828 System.gc();
829 System.gc();
830
831 if ( !newFile.renameTo( oldFile ) )
832 {
833
834 try
835 {
836 copyFiles( newFile, oldFile );
837 }
838 catch ( IOException ex )
839 {
840 throw new MojoExecutionException( "Could not replace original artifact with shaded artifact!", ex );
841 }
842 }
843 }
844 }
845
846 private void copyFiles( File source, File target )
847 throws IOException
848 {
849 try ( InputStream in = new FileInputStream( source );
850 OutputStream out = new FileOutputStream( target ) )
851 {
852 IOUtil.copy( in, out );
853 }
854 }
855
856 private File resolveArtifactForClassifier( Artifact artifact, String classifier )
857 {
858 DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
859 coordinate.setGroupId( artifact.getGroupId() );
860 coordinate.setArtifactId( artifact.getArtifactId() );
861 coordinate.setVersion( artifact.getVersion() );
862 coordinate.setExtension( "jar" );
863 coordinate.setClassifier( classifier );
864
865 Artifact resolvedArtifact;
866 try
867 {
868 resolvedArtifact =
869 artifactResolver.resolveArtifact( session.getProjectBuildingRequest(), coordinate ).getArtifact();
870 }
871 catch ( ArtifactResolverException e )
872 {
873 getLog().warn( "Could not get " + classifier + " for " + artifact );
874 return null;
875 }
876
877 if ( resolvedArtifact.isResolved() )
878 {
879 return resolvedArtifact.getFile();
880 }
881 return null;
882 }
883
884 private List<Relocator> getRelocators()
885 {
886 List<Relocator> relocators = new ArrayList<>();
887
888 if ( relocations == null )
889 {
890 return relocators;
891 }
892
893 for ( PackageRelocation r : relocations )
894 {
895 relocators.add( new SimpleRelocator( r.getPattern(), r.getShadedPattern(), r.getIncludes(), r.getExcludes(),
896 r.isRawString() ) );
897 }
898
899 return relocators;
900 }
901
902 private List<ResourceTransformer> getResourceTransformers()
903 {
904 if ( transformers == null )
905 {
906 return Collections.emptyList();
907 }
908
909 return Arrays.asList( transformers );
910 }
911
912 private List<Filter> getFilters()
913 throws MojoExecutionException
914 {
915 List<Filter> filters = new ArrayList<>();
916 List<SimpleFilter> simpleFilters = new ArrayList<>();
917
918 if ( this.filters != null && this.filters.length > 0 )
919 {
920 Map<Artifact, ArtifactId> artifacts = new HashMap<>();
921
922 artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) );
923
924 for ( Artifact artifact : project.getArtifacts() )
925 {
926 artifacts.put( artifact, new ArtifactId( artifact ) );
927 }
928
929 for ( ArchiveFilter filter : this.filters )
930 {
931 ArtifactId pattern = new ArtifactId( filter.getArtifact() );
932
933 Set<File> jars = new HashSet<>();
934
935 for ( Map.Entry<Artifact, ArtifactId> entry : artifacts.entrySet() )
936 {
937 if ( entry.getValue().matches( pattern ) )
938 {
939 Artifact artifact = entry.getKey();
940
941 jars.add( artifact.getFile() );
942
943 if ( createSourcesJar )
944 {
945 File file = resolveArtifactForClassifier( artifact, "sources" );
946 if ( file != null )
947 {
948 jars.add( file );
949 }
950 }
951
952 if ( shadeTestJar )
953 {
954 File file = resolveArtifactForClassifier( artifact, "tests" );
955 if ( file != null )
956 {
957 jars.add( file );
958 }
959 }
960 }
961 }
962
963 if ( jars.isEmpty() )
964 {
965 getLog().info( "No artifact matching filter " + filter.getArtifact() );
966
967 continue;
968 }
969
970 simpleFilters.add( new SimpleFilter( jars, filter ) );
971 }
972 }
973
974 filters.addAll( simpleFilters );
975
976 if ( minimizeJar )
977 {
978 getLog().info( "Minimizing jar " + project.getArtifact() );
979
980 try
981 {
982 filters.add( new MinijarFilter( project, getLog(), simpleFilters ) );
983 }
984 catch ( IOException e )
985 {
986 throw new MojoExecutionException( "Failed to analyze class dependencies", e );
987 }
988 }
989
990 return filters;
991 }
992
993 private File shadedArtifactFileWithClassifier()
994 {
995 Artifact artifact = project.getArtifact();
996 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "."
997 + artifact.getArtifactHandler().getExtension();
998 return new File( outputDirectory, shadedName );
999 }
1000
1001 private File shadedSourceArtifactFileWithClassifier()
1002 {
1003 return shadedArtifactFileWithClassifier( "sources" );
1004 }
1005
1006 private File shadedTestSourceArtifactFileWithClassifier()
1007 {
1008 return shadedArtifactFileWithClassifier( "test-sources" );
1009 }
1010
1011 private File shadedArtifactFileWithClassifier( String classifier )
1012 {
1013 Artifact artifact = project.getArtifact();
1014 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName
1015 + "-" + classifier + "." + artifact.getArtifactHandler().getExtension();
1016 return new File( outputDirectory, shadedName );
1017 }
1018
1019 private File shadedTestArtifactFileWithClassifier()
1020 {
1021 return shadedArtifactFileWithClassifier( "tests" );
1022 }
1023
1024 private File shadedSourcesArtifactFile()
1025 {
1026 return shadedArtifactFile( "sources" );
1027 }
1028
1029 private File shadedTestSourcesArtifactFile()
1030 {
1031 return shadedArtifactFile( "test-sources" );
1032 }
1033
1034 private File shadedArtifactFile( String classifier )
1035 {
1036 Artifact artifact = project.getArtifact();
1037
1038 String shadedName;
1039
1040 if ( project.getBuild().getFinalName() != null )
1041 {
1042 shadedName = project.getBuild().getFinalName() + "-" + classifier + "."
1043 + artifact.getArtifactHandler().getExtension();
1044 }
1045 else
1046 {
1047 shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + classifier + "."
1048 + artifact.getArtifactHandler().getExtension();
1049 }
1050
1051 return new File( outputDirectory, shadedName );
1052 }
1053
1054 private File shadedTestArtifactFile()
1055 {
1056 return shadedArtifactFile( "tests" );
1057 }
1058
1059
1060
1061 private void createDependencyReducedPom( Set<String> artifactsToRemove )
1062 throws IOException, DependencyGraphBuilderException, ProjectBuildingException
1063 {
1064 List<Dependency> dependencies = new ArrayList<>();
1065
1066 boolean modified = false;
1067
1068 List<Dependency> transitiveDeps = new ArrayList<>();
1069
1070
1071
1072 for ( Artifact artifact : project.getArtifacts() )
1073 {
1074 if ( "pom".equals( artifact.getType() ) )
1075 {
1076
1077 continue;
1078 }
1079
1080
1081 Dependency dep = createDependency( artifact );
1082
1083
1084 transitiveDeps.add( dep );
1085 }
1086 List<Dependency> origDeps = project.getDependencies();
1087
1088 if ( promoteTransitiveDependencies )
1089 {
1090 origDeps = transitiveDeps;
1091 }
1092
1093 Model model = project.getOriginalModel();
1094
1095
1096
1097 List<Dependency> originalDependencies = model.getDependencies();
1098 removeSystemScopedDependencies( artifactsToRemove, originalDependencies );
1099
1100 for ( Dependency d : origDeps )
1101 {
1102 dependencies.add( d );
1103
1104 String id = getId( d );
1105
1106 if ( artifactsToRemove.contains( id ) )
1107 {
1108 modified = true;
1109
1110 if ( keepDependenciesWithProvidedScope )
1111 {
1112 d.setScope( "provided" );
1113 }
1114 else
1115 {
1116 dependencies.remove( d );
1117 }
1118 }
1119 }
1120
1121
1122 model.setArtifactId( shadedArtifactId );
1123
1124
1125
1126
1127 addSystemScopedDependencyFromNonInterpolatedPom( dependencies, originalDependencies );
1128
1129
1130 rewriteDependencyReducedPomIfWeHaveReduction( dependencies, modified, transitiveDeps, model );
1131 }
1132
1133 private void rewriteDependencyReducedPomIfWeHaveReduction( List<Dependency> dependencies, boolean modified,
1134 List<Dependency> transitiveDeps, Model model )
1135 throws IOException, ProjectBuildingException,
1136 DependencyGraphBuilderException
1137 {
1138 if ( modified )
1139 {
1140 for ( int loopCounter = 0; modified; loopCounter++ )
1141 {
1142
1143 model.setDependencies( dependencies );
1144
1145 if ( generateUniqueDependencyReducedPom )
1146 {
1147 dependencyReducedPomLocation =
1148 File.createTempFile( "dependency-reduced-pom-", ".xml", project.getBasedir() );
1149 project.getProperties().setProperty( "maven.shade.dependency-reduced-pom",
1150 dependencyReducedPomLocation.getAbsolutePath() );
1151 }
1152 else
1153 {
1154 if ( dependencyReducedPomLocation == null )
1155 {
1156
1157 dependencyReducedPomLocation = new File( project.getBasedir(), "dependency-reduced-pom.xml" );
1158 }
1159 }
1160
1161 File f = dependencyReducedPomLocation;
1162
1163
1164 if ( loopCounter == 0 )
1165 {
1166 getLog().info( "Dependency-reduced POM written at: " + f.getAbsolutePath() );
1167 }
1168
1169 if ( f.exists() )
1170 {
1171
1172 f.delete();
1173 }
1174
1175 Writer w = WriterFactory.newXmlWriter( f );
1176
1177 String replaceRelativePath = null;
1178 if ( model.getParent() != null )
1179 {
1180 replaceRelativePath = model.getParent().getRelativePath();
1181
1182 }
1183
1184 if ( model.getParent() != null )
1185 {
1186 File parentFile =
1187 new File( project.getBasedir(), model.getParent().getRelativePath() ).getCanonicalFile();
1188 if ( !parentFile.isFile() )
1189 {
1190 parentFile = new File( parentFile, "pom.xml" );
1191 }
1192
1193 parentFile = parentFile.getCanonicalFile();
1194
1195 String relPath = RelativizePath.convertToRelativePath( parentFile, f );
1196 model.getParent().setRelativePath( relPath );
1197 }
1198
1199 try
1200 {
1201 PomWriter.write( w, model, true );
1202 }
1203 finally
1204 {
1205 if ( model.getParent() != null )
1206 {
1207 model.getParent().setRelativePath( replaceRelativePath );
1208 }
1209 w.close();
1210 }
1211
1212 ProjectBuildingRequest projectBuildingRequest =
1213 new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
1214 projectBuildingRequest.setLocalRepository( localRepository );
1215 projectBuildingRequest.setRemoteRepositories( remoteArtifactRepositories );
1216
1217 ProjectBuildingResult result = projectBuilder.build( f, projectBuildingRequest );
1218
1219 getLog().debug( "updateExcludesInDeps()" );
1220 modified = updateExcludesInDeps( result.getProject(), dependencies, transitiveDeps );
1221 }
1222
1223 project.setFile( dependencyReducedPomLocation );
1224 }
1225 }
1226
1227 private void removeSystemScopedDependencies( Set<String> artifactsToRemove, List<Dependency> originalDependencies )
1228 {
1229 for ( Dependency dependency : originalDependencies )
1230 {
1231 if ( dependency.getScope() != null && dependency.getScope().equalsIgnoreCase( "system" ) )
1232 {
1233 artifactsToRemove.add( getId( dependency ) );
1234 }
1235 }
1236 }
1237
1238 private void addSystemScopedDependencyFromNonInterpolatedPom( List<Dependency> dependencies,
1239 List<Dependency> originalDependencies )
1240 {
1241 for ( Dependency dependency : originalDependencies )
1242 {
1243 if ( dependency.getScope() != null && dependency.getScope().equalsIgnoreCase( "system" ) )
1244 {
1245 dependencies.add( dependency );
1246 }
1247 }
1248 }
1249
1250 private Dependency createDependency( Artifact artifact )
1251 {
1252 Dependency dep = new Dependency();
1253 dep.setArtifactId( artifact.getArtifactId() );
1254 if ( artifact.hasClassifier() )
1255 {
1256 dep.setClassifier( artifact.getClassifier() );
1257 }
1258 dep.setGroupId( artifact.getGroupId() );
1259 dep.setOptional( artifact.isOptional() );
1260 dep.setScope( artifact.getScope() );
1261 dep.setType( artifact.getType() );
1262 if ( useBaseVersion )
1263 {
1264 dep.setVersion( artifact.getBaseVersion() );
1265 }
1266 else
1267 {
1268 dep.setVersion( artifact.getVersion() );
1269 }
1270 return dep;
1271 }
1272
1273 private String getId( Artifact artifact )
1274 {
1275 return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getType(), artifact.getClassifier() );
1276 }
1277
1278 private String getId( Dependency dependency )
1279 {
1280 return getId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(),
1281 dependency.getClassifier() );
1282 }
1283
1284 private String getId( String groupId, String artifactId, String type, String classifier )
1285 {
1286 return groupId + ":" + artifactId + ":" + type + ":" + ( ( classifier != null ) ? classifier : "" );
1287 }
1288
1289 public boolean updateExcludesInDeps( MavenProject project, List<Dependency> dependencies,
1290 List<Dependency> transitiveDeps )
1291 throws DependencyGraphBuilderException
1292 {
1293 MavenProject original = session.getProjectBuildingRequest().getProject();
1294 try
1295 {
1296 session.getProjectBuildingRequest().setProject( project );
1297 DependencyNode node = dependencyGraphBuilder
1298 .buildDependencyGraph( session.getProjectBuildingRequest(), null );
1299 boolean modified = false;
1300 for ( DependencyNode n2 : node.getChildren() )
1301 {
1302 for ( DependencyNode n3 : n2.getChildren() )
1303 {
1304
1305
1306
1307
1308
1309
1310 boolean found = false;
1311 for ( Dependency dep : transitiveDeps )
1312 {
1313 if ( getId( dep ).equals( getId( n3.getArtifact() ) ) )
1314 {
1315 found = true;
1316 break;
1317 }
1318 }
1319
1320
1321
1322
1323
1324 if ( !found && !"provided".equals( n3.getArtifact().getScope() ) )
1325 {
1326 for ( Dependency dep : dependencies )
1327 {
1328 if ( getId( dep ).equals( getId( n2.getArtifact() ) ) )
1329 {
1330 Exclusion exclusion = new Exclusion();
1331 exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
1332 exclusion.setGroupId( n3.getArtifact().getGroupId() );
1333 dep.addExclusion( exclusion );
1334 modified = true;
1335 break;
1336 }
1337 }
1338 }
1339 }
1340 }
1341 return modified;
1342 }
1343 finally
1344 {
1345
1346 session.getProjectBuildingRequest().setProject( original );
1347 }
1348 }
1349
1350 private List<ResourceTransformer> toResourceTransformers(
1351 String shade, List<ResourceTransformer> resourceTransformers )
1352 {
1353 List<ResourceTransformer> forShade = new ArrayList<>();
1354 ManifestResourceTransformer lastMt = null;
1355 for ( ResourceTransformer transformer : resourceTransformers )
1356 {
1357 if ( !( transformer instanceof ManifestResourceTransformer ) )
1358 {
1359 forShade.add( transformer );
1360 }
1361 else if ( ( ( ManifestResourceTransformer ) transformer ) .isForShade( shade ) )
1362 {
1363 final ManifestResourceTransformer mt = (ManifestResourceTransformer) transformer;
1364 if ( mt.isUsedForDefaultShading() && lastMt != null && !lastMt.isUsedForDefaultShading() )
1365 {
1366 continue;
1367 }
1368 if ( !mt.isUsedForDefaultShading() && lastMt != null && lastMt.isUsedForDefaultShading() )
1369 {
1370 forShade.remove( lastMt );
1371 }
1372 else if ( !mt.isUsedForDefaultShading() && lastMt != null )
1373 {
1374 getLog().warn( "Ambiguous manifest transformer definition for '" + shade + "': "
1375 + mt + " / " + lastMt );
1376 }
1377 if ( lastMt == null || !mt.isUsedForDefaultShading() )
1378 {
1379 lastMt = mt;
1380 }
1381 forShade.add( transformer );
1382 }
1383 }
1384 return forShade;
1385 }
1386 }