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