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
321
322 @Parameter( property = "shadeSourcesContent", defaultValue = "false" )
323 private boolean shadeSourcesContent;
324
325
326
327
328
329
330
331 @Parameter
332 private boolean minimizeJar;
333
334
335
336
337
338
339
340
341
342 @Parameter
343 private File outputFile;
344
345
346
347
348
349
350 @Parameter
351 private String shaderHint;
352
353
354
355
356
357
358
359
360
361 @Parameter( defaultValue = "false" )
362 private boolean useBaseVersion;
363
364 @Parameter( defaultValue = "false" )
365 private boolean shadeTestJar;
366
367
368
369
370 private PlexusContainer plexusContainer;
371
372 public void contextualize( Context context )
373 throws ContextException
374 {
375 plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
376 }
377
378
379
380
381 public void execute()
382 throws MojoExecutionException
383 {
384
385 setupHintedShader();
386
387 Set<File> artifacts = new LinkedHashSet<File>();
388 Set<String> artifactIds = new LinkedHashSet<String>();
389 Set<File> sourceArtifacts = new LinkedHashSet<File>();
390 Set<File> testArtifacts = new LinkedHashSet<File>();
391
392 ArtifactSelector artifactSelector =
393 new ArtifactSelector( project.getArtifact(), artifactSet, shadedGroupFilter );
394
395 if ( artifactSelector.isSelected( project.getArtifact() ) && !"pom".equals( project.getArtifact().getType() ) )
396 {
397 if ( invalidMainArtifact() )
398 {
399 createErrorOutput();
400 throw new MojoExecutionException( "Failed to create shaded artifact, "
401 + "project main artifact does not exist." );
402 }
403
404 artifacts.add( project.getArtifact().getFile() );
405
406 if ( createSourcesJar )
407 {
408 File file = shadedSourcesArtifactFile();
409 if ( file.isFile() )
410 {
411 sourceArtifacts.add( file );
412 }
413 }
414
415 if ( shadeTestJar )
416 {
417 File file = shadedTestArtifactFile();
418 if ( file.isFile() )
419 {
420 testArtifacts.add( file );
421 }
422 }
423 }
424
425 processArtifactSelectors( artifacts, artifactIds, sourceArtifacts, artifactSelector );
426
427 File outputJar = ( outputFile != null ) ? outputFile : shadedArtifactFileWithClassifier();
428 File sourcesJar = shadedSourceArtifactFileWithClassifier();
429 File testJar = shadedTestArtifactFileWithClassifier();
430
431
432 try
433 {
434 List<Filter> filters = getFilters();
435
436 List<Relocator> relocators = getRelocators();
437
438 List<ResourceTransformer> resourceTransformers = getResourceTransformers();
439
440 ShadeRequest shadeRequest = shadeRequest( artifacts, outputJar, filters, relocators, resourceTransformers );
441
442 shader.shade( shadeRequest );
443
444 if ( createSourcesJar )
445 {
446 ShadeRequest shadeSourcesRequest =
447 createShadeSourcesRequest( sourceArtifacts, sourcesJar, filters, relocators, resourceTransformers );
448
449 shader.shade( shadeSourcesRequest );
450 }
451
452 if ( shadeTestJar )
453 {
454
455 ShadeRequest shadeSourcesRequest =
456 createShadeSourcesRequest( testArtifacts, testJar, filters, relocators, resourceTransformers );
457
458 shader.shade( shadeSourcesRequest );
459 }
460
461 if ( outputFile == null )
462 {
463 boolean renamed = false;
464
465
466
467
468 if ( finalName != null && finalName.length() > 0
469 && !finalName.equals( project.getBuild().getFinalName() ) )
470 {
471 String finalFileName = finalName + "." + project.getArtifact().getArtifactHandler().getExtension();
472 File finalFile = new File( outputDirectory, finalFileName );
473 replaceFile( finalFile, outputJar );
474 outputJar = finalFile;
475
476
477 if ( createSourcesJar )
478 {
479 finalFileName = finalName + "-sources.jar";
480 finalFile = new File( outputDirectory, finalFileName );
481 replaceFile( finalFile, sourcesJar );
482 sourcesJar = finalFile;
483 }
484
485
486 if ( shadeTestJar )
487 {
488 finalFileName = finalName + "-tests.jar";
489 finalFile = new File( outputDirectory, finalFileName );
490 replaceFile( finalFile, testJar );
491 testJar = finalFile;
492 }
493
494 renamed = true;
495 }
496
497 if ( shadedArtifactAttached )
498 {
499 getLog().info( "Attaching shaded artifact." );
500 projectHelper.attachArtifact( project, project.getArtifact().getType(), shadedClassifierName,
501 outputJar );
502 if ( createSourcesJar )
503 {
504 projectHelper.attachArtifact( project, "java-source", shadedClassifierName + "-sources",
505 sourcesJar );
506 }
507 }
508 else if ( !renamed )
509 {
510 getLog().info( "Replacing original artifact with shaded artifact." );
511 File originalArtifact = project.getArtifact().getFile();
512 if ( originalArtifact != null )
513 {
514 replaceFile( originalArtifact, outputJar );
515
516 if ( createSourcesJar )
517 {
518 getLog().info( "Replacing original source artifact with shaded source artifact." );
519 File shadedSources = shadedSourcesArtifactFile();
520
521 replaceFile( shadedSources, sourcesJar );
522
523 projectHelper.attachArtifact( project, "java-source", "sources", shadedSources );
524 }
525
526 if ( shadeTestJar )
527 {
528 getLog().info( "Replacing original test artifact with shaded test artifact." );
529 File shadedTests = shadedTestArtifactFile();
530
531 replaceFile( shadedTests, testJar );
532
533 projectHelper.attachArtifact( project, "jar", "tests", shadedTests );
534 }
535
536 if ( createDependencyReducedPom )
537 {
538 createDependencyReducedPom( artifactIds );
539 }
540 }
541 }
542 }
543 }
544 catch ( Exception e )
545 {
546 throw new MojoExecutionException( "Error creating shaded jar: " + e.getMessage(), e );
547 }
548 }
549
550 private void createErrorOutput()
551 {
552 getLog().error( "The project main artifact does not exist. This could have the following" );
553 getLog().error( "reasons:" );
554 getLog().error( "- You have invoked the goal directly from the command line. This is not" );
555 getLog().error( " supported. Please add the goal to the default lifecycle via an" );
556 getLog().error( " <execution> element in your POM and use \"mvn package\" to have it run." );
557 getLog().error( "- You have bound the goal to a lifecycle phase before \"package\". Please" );
558 getLog().error( " remove this binding from your POM such that the goal will be run in" );
559 getLog().error( " the proper phase." );
560 getLog().error( "- You removed the configuration of the maven-jar-plugin that produces the main artifact." );
561 }
562
563 private ShadeRequest shadeRequest( Set<File> artifacts, File outputJar, List<Filter> filters,
564 List<Relocator> relocators, List<ResourceTransformer> resourceTransformers )
565 {
566 ShadeRequest shadeRequest = new ShadeRequest();
567 shadeRequest.setJars( artifacts );
568 shadeRequest.setUberJar( outputJar );
569 shadeRequest.setFilters( filters );
570 shadeRequest.setRelocators( relocators );
571 shadeRequest.setResourceTransformers( resourceTransformers );
572 return shadeRequest;
573 }
574
575 private ShadeRequest createShadeSourcesRequest( Set<File> testArtifacts, File testJar, List<Filter> filters,
576 List<Relocator> relocators,
577 List<ResourceTransformer> resourceTransformers )
578 {
579 ShadeRequest shadeSourcesRequest =
580 shadeRequest( testArtifacts, testJar, filters, relocators, resourceTransformers );
581 shadeSourcesRequest.setShadeSourcesContent( shadeSourcesContent );
582 return shadeSourcesRequest;
583 }
584
585 private void setupHintedShader()
586 throws MojoExecutionException
587 {
588 if ( shaderHint != null )
589 {
590 try
591 {
592 shader = (Shader) plexusContainer.lookup( Shader.ROLE, shaderHint );
593 }
594 catch ( ComponentLookupException e )
595 {
596 throw new MojoExecutionException( "unable to lookup own Shader implementation with hint:'" + shaderHint
597 + "'", e );
598 }
599 }
600 }
601
602 private void processArtifactSelectors( Set<File> artifacts, Set<String> artifactIds, Set<File> sourceArtifacts,
603 ArtifactSelector artifactSelector )
604 {
605 for ( Artifact artifact : project.getArtifacts() )
606 {
607 if ( !artifactSelector.isSelected( artifact ) )
608 {
609 getLog().info( "Excluding " + artifact.getId() + " from the shaded jar." );
610
611 continue;
612 }
613
614 if ( "pom".equals( artifact.getType() ) )
615 {
616 getLog().info( "Skipping pom dependency " + artifact.getId() + " in the shaded jar." );
617 continue;
618 }
619
620 getLog().info( "Including " + artifact.getId() + " in the shaded jar." );
621
622 artifacts.add( artifact.getFile() );
623 artifactIds.add( getId( artifact ) );
624
625 if ( createSourcesJar )
626 {
627 File file = resolveArtifactSources( artifact );
628 if ( file != null )
629 {
630 if ( file.length() > 0 )
631 {
632 sourceArtifacts.add( file );
633 }
634 else
635 {
636 getLog().warn( "Skipping empty source jar " + artifact.getId() + "." );
637 }
638 }
639 }
640 }
641 }
642
643 private boolean invalidMainArtifact()
644 {
645 return project.getArtifact().getFile() == null || !project.getArtifact().getFile().isFile();
646 }
647
648 private void replaceFile( File oldFile, File newFile )
649 throws MojoExecutionException
650 {
651 getLog().info( "Replacing " + oldFile + " with " + newFile );
652
653 File origFile = new File( outputDirectory, "original-" + oldFile.getName() );
654 if ( oldFile.exists() && !oldFile.renameTo( origFile ) )
655 {
656
657 System.gc();
658 System.gc();
659
660 if ( !oldFile.renameTo( origFile ) )
661 {
662
663 try
664 {
665 copyFiles( oldFile, origFile );
666 }
667 catch ( IOException ex )
668 {
669
670 getLog().warn( ex );
671 }
672 }
673 }
674 if ( !newFile.renameTo( oldFile ) )
675 {
676
677 System.gc();
678 System.gc();
679
680 if ( !newFile.renameTo( oldFile ) )
681 {
682
683 try
684 {
685 copyFiles( newFile, oldFile );
686 }
687 catch ( IOException ex )
688 {
689 throw new MojoExecutionException( "Could not replace original artifact with shaded artifact!", ex );
690 }
691 }
692 }
693 }
694
695 private void copyFiles( File source, File target )
696 throws IOException
697 {
698 InputStream in = null;
699 OutputStream out = null;
700 try
701 {
702 in = new FileInputStream( source );
703 out = new FileOutputStream( target );
704 IOUtil.copy( in, out );
705 out.close();
706 out = null;
707 in.close();
708 in = null;
709 }
710 finally
711 {
712 IOUtil.close( in );
713 IOUtil.close( out );
714 }
715 }
716
717 private File resolveArtifactSources( Artifact artifact )
718 {
719 DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
720 coordinate.setGroupId( artifact.getGroupId() );
721 coordinate.setArtifactId( artifact.getArtifactId() );
722 coordinate.setVersion( artifact.getVersion() );
723 coordinate.setExtension( "jar" );
724 coordinate.setClassifier( "sources" );
725
726 Artifact resolvedArtifact;
727 try
728 {
729 resolvedArtifact =
730 artifactResolver.resolveArtifact( session.getProjectBuildingRequest(), coordinate ).getArtifact();
731 }
732 catch ( ArtifactResolverException e )
733 {
734 getLog().warn( "Could not get sources for " + artifact );
735 return null;
736 }
737
738 if ( resolvedArtifact.isResolved() )
739 {
740 return resolvedArtifact.getFile();
741 }
742 return null;
743 }
744
745 private List<Relocator> getRelocators()
746 {
747 List<Relocator> relocators = new ArrayList<Relocator>();
748
749 if ( relocations == null )
750 {
751 return relocators;
752 }
753
754 for ( PackageRelocation r : relocations )
755 {
756 relocators.add( new SimpleRelocator( r.getPattern(), r.getShadedPattern(), r.getIncludes(), r.getExcludes(),
757 r.isRawString() ) );
758 }
759
760 return relocators;
761 }
762
763 private List<ResourceTransformer> getResourceTransformers()
764 {
765 if ( transformers == null )
766 {
767 return Collections.emptyList();
768 }
769
770 return Arrays.asList( transformers );
771 }
772
773 private List<Filter> getFilters()
774 throws MojoExecutionException
775 {
776 List<Filter> filters = new ArrayList<Filter>();
777 List<SimpleFilter> simpleFilters = new ArrayList<SimpleFilter>();
778
779 if ( this.filters != null && this.filters.length > 0 )
780 {
781 Map<Artifact, ArtifactId> artifacts = new HashMap<Artifact, ArtifactId>();
782
783 artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) );
784
785 for ( Artifact artifact : project.getArtifacts() )
786 {
787 artifacts.put( artifact, new ArtifactId( artifact ) );
788 }
789
790 for ( ArchiveFilter filter : this.filters )
791 {
792 ArtifactId pattern = new ArtifactId( filter.getArtifact() );
793
794 Set<File> jars = new HashSet<File>();
795
796 for ( Map.Entry<Artifact, ArtifactId> entry : artifacts.entrySet() )
797 {
798 if ( entry.getValue().matches( pattern ) )
799 {
800 Artifact artifact = entry.getKey();
801
802 jars.add( artifact.getFile() );
803
804 if ( createSourcesJar )
805 {
806 File file = resolveArtifactSources( artifact );
807 if ( file != null )
808 {
809 jars.add( file );
810 }
811 }
812 }
813 }
814
815 if ( jars.isEmpty() )
816 {
817 getLog().info( "No artifact matching filter " + filter.getArtifact() );
818
819 continue;
820 }
821
822 simpleFilters.add( new SimpleFilter( jars, filter.getIncludes(), filter.getExcludes() ) );
823 }
824 }
825
826 filters.addAll( simpleFilters );
827
828 if ( minimizeJar )
829 {
830 getLog().info( "Minimizing jar " + project.getArtifact() );
831
832 try
833 {
834 filters.add( new MinijarFilter( project, getLog(), simpleFilters ) );
835 }
836 catch ( IOException e )
837 {
838 throw new MojoExecutionException( "Failed to analyze class dependencies", e );
839 }
840 }
841
842 return filters;
843 }
844
845 private File shadedArtifactFileWithClassifier()
846 {
847 Artifact artifact = project.getArtifact();
848 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "."
849 + artifact.getArtifactHandler().getExtension();
850 return new File( outputDirectory, shadedName );
851 }
852
853 private File shadedSourceArtifactFileWithClassifier()
854 {
855 Artifact artifact = project.getArtifact();
856 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName
857 + "-sources." + artifact.getArtifactHandler().getExtension();
858 return new File( outputDirectory, shadedName );
859 }
860
861 private File shadedTestArtifactFileWithClassifier()
862 {
863 Artifact artifact = project.getArtifact();
864 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName
865 + "-tests." + artifact.getArtifactHandler().getExtension();
866 return new File( outputDirectory, shadedName );
867 }
868
869 private File shadedSourcesArtifactFile()
870 {
871 Artifact artifact = project.getArtifact();
872
873 String shadedName;
874
875 if ( project.getBuild().getFinalName() != null )
876 {
877 shadedName = project.getBuild().getFinalName() + "-sources." + artifact.getArtifactHandler().getExtension();
878 }
879 else
880 {
881 shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-sources."
882 + artifact.getArtifactHandler().getExtension();
883 }
884
885 return new File( outputDirectory, shadedName );
886 }
887
888 private File shadedTestArtifactFile()
889 {
890 Artifact artifact = project.getArtifact();
891
892 String shadedName;
893
894 if ( project.getBuild().getFinalName() != null )
895 {
896 shadedName = project.getBuild().getFinalName() + "-tests." + artifact.getArtifactHandler().getExtension();
897 }
898 else
899 {
900 shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-tests."
901 + artifact.getArtifactHandler().getExtension();
902 }
903
904 return new File( outputDirectory, shadedName );
905 }
906
907
908
909 private void createDependencyReducedPom( Set<String> artifactsToRemove )
910 throws IOException, DependencyGraphBuilderException, ProjectBuildingException
911 {
912 List<Dependency> dependencies = new ArrayList<Dependency>();
913
914 boolean modified = false;
915
916 List<Dependency> transitiveDeps = new ArrayList<Dependency>();
917
918
919
920 for ( Artifact artifact : project.getArtifacts() )
921 {
922 if ( "pom".equals( artifact.getType() ) )
923 {
924
925 continue;
926 }
927
928
929 Dependency dep = createDependency( artifact );
930
931
932 transitiveDeps.add( dep );
933 }
934 List<Dependency> origDeps = project.getDependencies();
935
936 if ( promoteTransitiveDependencies )
937 {
938 origDeps = transitiveDeps;
939 }
940
941 Model model = project.getOriginalModel();
942
943
944
945 List<Dependency> originalDependencies = model.getDependencies();
946 removeSystemScopedDependencies( artifactsToRemove, originalDependencies );
947
948 for ( Dependency d : origDeps )
949 {
950 dependencies.add( d );
951
952 String id = getId( d );
953
954 if ( artifactsToRemove.contains( id ) )
955 {
956 modified = true;
957
958 if ( keepDependenciesWithProvidedScope )
959 {
960 d.setScope( "provided" );
961 }
962 else
963 {
964 dependencies.remove( d );
965 }
966 }
967 }
968
969
970 model.setArtifactId( shadedArtifactId );
971
972
973
974
975 addSystemScopedDependencyFromNonInterpolatedPom( dependencies, originalDependencies );
976
977
978 rewriteDependencyReducedPomIfWeHaveReduction( dependencies, modified, transitiveDeps, model );
979 }
980
981 private void rewriteDependencyReducedPomIfWeHaveReduction( List<Dependency> dependencies, boolean modified,
982 List<Dependency> transitiveDeps, Model model )
983 throws IOException, ProjectBuildingException,
984 DependencyGraphBuilderException
985 {
986 if ( modified )
987 {
988 for ( int loopCounter = 0; modified; loopCounter++ )
989 {
990
991 model.setDependencies( dependencies );
992
993 if ( generateUniqueDependencyReducedPom )
994 {
995 dependencyReducedPomLocation =
996 File.createTempFile( "dependency-reduced-pom-", ".xml", project.getBasedir() );
997 project.getProperties().setProperty( "maven.shade.dependency-reduced-pom",
998 dependencyReducedPomLocation.getAbsolutePath() );
999 }
1000 else
1001 {
1002 if ( dependencyReducedPomLocation == null )
1003 {
1004
1005 dependencyReducedPomLocation = new File( project.getBasedir(), "dependency-reduced-pom.xml" );
1006 }
1007 }
1008
1009 File f = dependencyReducedPomLocation;
1010
1011
1012 if ( loopCounter == 0 )
1013 {
1014 getLog().info( "Dependency-reduced POM written at: " + f.getAbsolutePath() );
1015 }
1016
1017 if ( f.exists() )
1018 {
1019
1020 f.delete();
1021 }
1022
1023 Writer w = WriterFactory.newXmlWriter( f );
1024
1025 String replaceRelativePath = null;
1026 if ( model.getParent() != null )
1027 {
1028 replaceRelativePath = model.getParent().getRelativePath();
1029
1030 }
1031
1032 if ( model.getParent() != null )
1033 {
1034 File parentFile =
1035 new File( project.getBasedir(), model.getParent().getRelativePath() ).getCanonicalFile();
1036 if ( !parentFile.isFile() )
1037 {
1038 parentFile = new File( parentFile, "pom.xml" );
1039 }
1040
1041 parentFile = parentFile.getCanonicalFile();
1042
1043 String relPath = RelativizePath.convertToRelativePath( parentFile, f );
1044 model.getParent().setRelativePath( relPath );
1045 }
1046
1047 try
1048 {
1049 PomWriter.write( w, model, true );
1050 }
1051 finally
1052 {
1053 if ( model.getParent() != null )
1054 {
1055 model.getParent().setRelativePath( replaceRelativePath );
1056 }
1057 w.close();
1058 }
1059
1060 ProjectBuildingRequest projectBuildingRequest =
1061 new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
1062 projectBuildingRequest.setLocalRepository( localRepository );
1063 projectBuildingRequest.setRemoteRepositories( remoteArtifactRepositories );
1064
1065 ProjectBuildingResult result = projectBuilder.build( f, projectBuildingRequest );
1066
1067 getLog().debug( "updateExcludesInDeps()" );
1068 modified = updateExcludesInDeps( result.getProject(), dependencies, transitiveDeps );
1069 }
1070
1071 project.setFile( dependencyReducedPomLocation );
1072 }
1073 }
1074
1075 private void removeSystemScopedDependencies( Set<String> artifactsToRemove, List<Dependency> originalDependencies )
1076 {
1077 for ( Dependency dependency : originalDependencies )
1078 {
1079 if ( dependency.getScope() != null && dependency.getScope().equalsIgnoreCase( "system" ) )
1080 {
1081 artifactsToRemove.add( getId( dependency ) );
1082 }
1083 }
1084 }
1085
1086 private void addSystemScopedDependencyFromNonInterpolatedPom( List<Dependency> dependencies,
1087 List<Dependency> originalDependencies )
1088 {
1089 for ( Dependency dependency : originalDependencies )
1090 {
1091 if ( dependency.getScope() != null && dependency.getScope().equalsIgnoreCase( "system" ) )
1092 {
1093 dependencies.add( dependency );
1094 }
1095 }
1096 }
1097
1098 private Dependency createDependency( Artifact artifact )
1099 {
1100 Dependency dep = new Dependency();
1101 dep.setArtifactId( artifact.getArtifactId() );
1102 if ( artifact.hasClassifier() )
1103 {
1104 dep.setClassifier( artifact.getClassifier() );
1105 }
1106 dep.setGroupId( artifact.getGroupId() );
1107 dep.setOptional( artifact.isOptional() );
1108 dep.setScope( artifact.getScope() );
1109 dep.setType( artifact.getType() );
1110 if ( useBaseVersion )
1111 {
1112 dep.setVersion( artifact.getBaseVersion() );
1113 }
1114 else
1115 {
1116 dep.setVersion( artifact.getVersion() );
1117 }
1118 return dep;
1119 }
1120
1121 private String getId( Artifact artifact )
1122 {
1123 return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getType(), artifact.getClassifier() );
1124 }
1125
1126 private String getId( Dependency dependency )
1127 {
1128 return getId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(),
1129 dependency.getClassifier() );
1130 }
1131
1132 private String getId( String groupId, String artifactId, String type, String classifier )
1133 {
1134 return groupId + ":" + artifactId + ":" + type + ":" + ( ( classifier != null ) ? classifier : "" );
1135 }
1136
1137 public boolean updateExcludesInDeps( MavenProject project, List<Dependency> dependencies,
1138 List<Dependency> transitiveDeps )
1139 throws DependencyGraphBuilderException
1140 {
1141 MavenProject original = session.getProjectBuildingRequest().getProject();
1142 try
1143 {
1144 session.getProjectBuildingRequest().setProject( project );
1145 DependencyNode node = dependencyGraphBuilder
1146 .buildDependencyGraph( session.getProjectBuildingRequest(), null );
1147 boolean modified = false;
1148 for ( DependencyNode n2 : node.getChildren() )
1149 {
1150 for ( DependencyNode n3 : n2.getChildren() )
1151 {
1152
1153
1154
1155
1156
1157
1158 boolean found = false;
1159 for ( Dependency dep : transitiveDeps )
1160 {
1161 if ( dep.getArtifactId().equals( n3.getArtifact().getArtifactId() )
1162 && dep.getGroupId().equals( n3.getArtifact().getGroupId() )
1163 && ( dep.getType() == null || dep.getType().equals( n3.getArtifact().getType() ) ) )
1164 {
1165 found = true;
1166 break;
1167 }
1168 }
1169
1170 if ( !found )
1171 {
1172 for ( Dependency dep : dependencies )
1173 {
1174 if ( dep.getArtifactId().equals( n2.getArtifact().getArtifactId() )
1175 && dep.getGroupId().equals( n2.getArtifact().getGroupId() )
1176 && ( dep.getType() == null || dep.getType().equals( n2.getArtifact().getType() ) ) )
1177 {
1178 Exclusion exclusion = new Exclusion();
1179 exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
1180 exclusion.setGroupId( n3.getArtifact().getGroupId() );
1181 dep.addExclusion( exclusion );
1182 modified = true;
1183 break;
1184 }
1185 }
1186 }
1187 }
1188 }
1189 return modified;
1190 }
1191 finally
1192 {
1193
1194 session.getProjectBuildingRequest().setProject( original );
1195 }
1196 }
1197 }