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 java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.io.Writer;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.LinkedHashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38
39 import org.apache.maven.artifact.Artifact;
40 import org.apache.maven.artifact.repository.ArtifactRepository;
41 import org.apache.maven.execution.MavenSession;
42 import org.apache.maven.model.Dependency;
43 import org.apache.maven.model.Exclusion;
44 import org.apache.maven.model.Model;
45 import org.apache.maven.plugin.AbstractMojo;
46 import org.apache.maven.plugin.MojoExecutionException;
47 import org.apache.maven.plugins.annotations.Component;
48 import org.apache.maven.plugins.annotations.LifecyclePhase;
49 import org.apache.maven.plugins.annotations.Mojo;
50 import org.apache.maven.plugins.annotations.Parameter;
51 import org.apache.maven.plugins.annotations.ResolutionScope;
52 import org.apache.maven.plugins.shade.ShadeRequest;
53 import org.apache.maven.plugins.shade.Shader;
54 import org.apache.maven.plugins.shade.filter.Filter;
55 import org.apache.maven.plugins.shade.filter.MinijarFilter;
56 import org.apache.maven.plugins.shade.filter.SimpleFilter;
57 import org.apache.maven.plugins.shade.pom.PomWriter;
58 import org.apache.maven.plugins.shade.relocation.Relocator;
59 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
60 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
61 import org.apache.maven.project.DefaultProjectBuildingRequest;
62 import org.apache.maven.project.MavenProject;
63 import org.apache.maven.project.MavenProjectHelper;
64 import org.apache.maven.project.ProjectBuilder;
65 import org.apache.maven.project.ProjectBuildingException;
66 import org.apache.maven.project.ProjectBuildingRequest;
67 import org.apache.maven.project.ProjectBuildingResult;
68 import org.apache.maven.shared.artifact.DefaultArtifactCoordinate;
69 import org.apache.maven.shared.artifact.resolve.ArtifactResolver;
70 import org.apache.maven.shared.artifact.resolve.ArtifactResolverException;
71 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
72 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
73 import org.apache.maven.shared.dependency.graph.DependencyNode;
74 import org.codehaus.plexus.PlexusConstants;
75 import org.codehaus.plexus.PlexusContainer;
76 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
77 import org.codehaus.plexus.context.Context;
78 import org.codehaus.plexus.context.ContextException;
79 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
80 import org.codehaus.plexus.util.IOUtil;
81 import org.codehaus.plexus.util.WriterFactory;
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 sourceArtifacts.add( file );
631 }
632 }
633 }
634 }
635
636 private boolean invalidMainArtifact()
637 {
638 return project.getArtifact().getFile() == null || !project.getArtifact().getFile().isFile();
639 }
640
641 private void replaceFile( File oldFile, File newFile )
642 throws MojoExecutionException
643 {
644 getLog().info( "Replacing " + oldFile + " with " + newFile );
645
646 File origFile = new File( outputDirectory, "original-" + oldFile.getName() );
647 if ( oldFile.exists() && !oldFile.renameTo( origFile ) )
648 {
649
650 System.gc();
651 System.gc();
652
653 if ( !oldFile.renameTo( origFile ) )
654 {
655
656 try
657 {
658 copyFiles( oldFile, origFile );
659 }
660 catch ( IOException ex )
661 {
662
663 getLog().warn( ex );
664 }
665 }
666 }
667 if ( !newFile.renameTo( oldFile ) )
668 {
669
670 System.gc();
671 System.gc();
672
673 if ( !newFile.renameTo( oldFile ) )
674 {
675
676 try
677 {
678 copyFiles( newFile, oldFile );
679 }
680 catch ( IOException ex )
681 {
682 throw new MojoExecutionException( "Could not replace original artifact with shaded artifact!", ex );
683 }
684 }
685 }
686 }
687
688 private void copyFiles( File source, File target )
689 throws IOException
690 {
691 InputStream in = null;
692 OutputStream out = null;
693 try
694 {
695 in = new FileInputStream( source );
696 out = new FileOutputStream( target );
697 IOUtil.copy( in, out );
698 out.close();
699 out = null;
700 in.close();
701 in = null;
702 }
703 finally
704 {
705 IOUtil.close( in );
706 IOUtil.close( out );
707 }
708 }
709
710 private File resolveArtifactSources( Artifact artifact )
711 {
712 DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
713 coordinate.setGroupId( artifact.getGroupId() );
714 coordinate.setArtifactId( artifact.getArtifactId() );
715 coordinate.setVersion( artifact.getVersion() );
716 coordinate.setExtension( "jar" );
717 coordinate.setClassifier( "sources" );
718
719 Artifact resolvedArtifact = null;
720 try
721 {
722 resolvedArtifact =
723 artifactResolver.resolveArtifact( session.getProjectBuildingRequest(), coordinate ).getArtifact();
724 }
725 catch ( ArtifactResolverException e )
726 {
727 getLog().warn( "Could not get sources for " + artifact );
728 }
729
730 if ( resolvedArtifact.isResolved() )
731 {
732 return resolvedArtifact.getFile();
733 }
734 return null;
735 }
736
737 private List<Relocator> getRelocators()
738 {
739 List<Relocator> relocators = new ArrayList<Relocator>();
740
741 if ( relocations == null )
742 {
743 return relocators;
744 }
745
746 for ( PackageRelocation r : relocations )
747 {
748 relocators.add( new SimpleRelocator( r.getPattern(), r.getShadedPattern(), r.getIncludes(), r.getExcludes(),
749 r.isRawString() ) );
750 }
751
752 return relocators;
753 }
754
755 private List<ResourceTransformer> getResourceTransformers()
756 {
757 if ( transformers == null )
758 {
759 return Collections.emptyList();
760 }
761
762 return Arrays.asList( transformers );
763 }
764
765 private List<Filter> getFilters()
766 throws MojoExecutionException
767 {
768 List<Filter> filters = new ArrayList<Filter>();
769 List<SimpleFilter> simpleFilters = new ArrayList<SimpleFilter>();
770
771 if ( this.filters != null && this.filters.length > 0 )
772 {
773 Map<Artifact, ArtifactId> artifacts = new HashMap<Artifact, ArtifactId>();
774
775 artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) );
776
777 for ( Artifact artifact : project.getArtifacts() )
778 {
779 artifacts.put( artifact, new ArtifactId( artifact ) );
780 }
781
782 for ( ArchiveFilter filter : this.filters )
783 {
784 ArtifactId pattern = new ArtifactId( filter.getArtifact() );
785
786 Set<File> jars = new HashSet<File>();
787
788 for ( Map.Entry<Artifact, ArtifactId> entry : artifacts.entrySet() )
789 {
790 if ( entry.getValue().matches( pattern ) )
791 {
792 Artifact artifact = entry.getKey();
793
794 jars.add( artifact.getFile() );
795
796 if ( createSourcesJar )
797 {
798 File file = resolveArtifactSources( artifact );
799 if ( file != null )
800 {
801 jars.add( file );
802 }
803 }
804 }
805 }
806
807 if ( jars.isEmpty() )
808 {
809 getLog().info( "No artifact matching filter " + filter.getArtifact() );
810
811 continue;
812 }
813
814 simpleFilters.add( new SimpleFilter( jars, filter.getIncludes(), filter.getExcludes() ) );
815 }
816 }
817
818 filters.addAll( simpleFilters );
819
820 if ( minimizeJar )
821 {
822 getLog().info( "Minimizing jar " + project.getArtifact() );
823
824 try
825 {
826 filters.add( new MinijarFilter( project, getLog(), simpleFilters ) );
827 }
828 catch ( IOException e )
829 {
830 throw new MojoExecutionException( "Failed to analyze class dependencies", e );
831 }
832 }
833
834 return filters;
835 }
836
837 private File shadedArtifactFileWithClassifier()
838 {
839 Artifact artifact = project.getArtifact();
840 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "."
841 + artifact.getArtifactHandler().getExtension();
842 return new File( outputDirectory, shadedName );
843 }
844
845 private File shadedSourceArtifactFileWithClassifier()
846 {
847 Artifact artifact = project.getArtifact();
848 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName
849 + "-sources." + artifact.getArtifactHandler().getExtension();
850 return new File( outputDirectory, shadedName );
851 }
852
853 private File shadedTestArtifactFileWithClassifier()
854 {
855 Artifact artifact = project.getArtifact();
856 final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName
857 + "-tests." + artifact.getArtifactHandler().getExtension();
858 return new File( outputDirectory, shadedName );
859 }
860
861 private File shadedSourcesArtifactFile()
862 {
863 Artifact artifact = project.getArtifact();
864
865 String shadedName;
866
867 if ( project.getBuild().getFinalName() != null )
868 {
869 shadedName = project.getBuild().getFinalName() + "-sources." + artifact.getArtifactHandler().getExtension();
870 }
871 else
872 {
873 shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-sources."
874 + artifact.getArtifactHandler().getExtension();
875 }
876
877 return new File( outputDirectory, shadedName );
878 }
879
880 private File shadedTestArtifactFile()
881 {
882 Artifact artifact = project.getArtifact();
883
884 String shadedName;
885
886 if ( project.getBuild().getFinalName() != null )
887 {
888 shadedName = project.getBuild().getFinalName() + "-tests." + artifact.getArtifactHandler().getExtension();
889 }
890 else
891 {
892 shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-tests."
893 + artifact.getArtifactHandler().getExtension();
894 }
895
896 return new File( outputDirectory, shadedName );
897 }
898
899
900
901 private void createDependencyReducedPom( Set<String> artifactsToRemove )
902 throws IOException, DependencyGraphBuilderException, ProjectBuildingException
903 {
904 List<Dependency> dependencies = new ArrayList<Dependency>();
905
906 boolean modified = false;
907
908 List<Dependency> transitiveDeps = new ArrayList<Dependency>();
909
910
911
912 for ( Artifact artifact : project.getArtifacts() )
913 {
914 if ( "pom".equals( artifact.getType() ) )
915 {
916
917 continue;
918 }
919
920
921 Dependency dep = createDependency( artifact );
922
923
924 transitiveDeps.add( dep );
925 }
926 List<Dependency> origDeps = project.getDependencies();
927
928 if ( promoteTransitiveDependencies )
929 {
930 origDeps = transitiveDeps;
931 }
932
933 Model model = project.getOriginalModel();
934
935
936
937 List<Dependency> originalDependencies = model.getDependencies();
938 removeSystemScopedDependencies( artifactsToRemove, originalDependencies );
939
940 for ( Dependency d : origDeps )
941 {
942 dependencies.add( d );
943
944 String id = getId( d );
945
946 if ( artifactsToRemove.contains( id ) )
947 {
948 modified = true;
949
950 if ( keepDependenciesWithProvidedScope )
951 {
952 d.setScope( "provided" );
953 }
954 else
955 {
956 dependencies.remove( d );
957 }
958 }
959 }
960
961
962 model.setArtifactId( shadedArtifactId );
963
964
965
966
967 addSystemScopedDependencyFromNonInterpolatedPom( dependencies, originalDependencies );
968
969
970 rewriteDependencyReducedPomIfWeHaveReduction( dependencies, modified, transitiveDeps, model );
971 }
972
973 private void rewriteDependencyReducedPomIfWeHaveReduction( List<Dependency> dependencies, boolean modified,
974 List<Dependency> transitiveDeps, Model model )
975 throws IOException, ProjectBuildingException,
976 DependencyGraphBuilderException
977 {
978 if ( modified )
979 {
980 for ( int loopCounter = 0; modified; loopCounter++ )
981 {
982
983 model.setDependencies( dependencies );
984
985 if ( generateUniqueDependencyReducedPom )
986 {
987 dependencyReducedPomLocation =
988 File.createTempFile( "dependency-reduced-pom-", ".xml", project.getBasedir() );
989 project.getProperties().setProperty( "maven.shade.dependency-reduced-pom",
990 dependencyReducedPomLocation.getAbsolutePath() );
991 }
992 else
993 {
994 if ( dependencyReducedPomLocation == null )
995 {
996
997 dependencyReducedPomLocation = new File( project.getBasedir(), "dependency-reduced-pom.xml" );
998 }
999 }
1000
1001 File f = dependencyReducedPomLocation;
1002
1003
1004 if ( loopCounter == 0 )
1005 {
1006 getLog().info( "Dependency-reduced POM written at: " + f.getAbsolutePath() );
1007 }
1008
1009 if ( f.exists() )
1010 {
1011
1012 f.delete();
1013 }
1014
1015 Writer w = WriterFactory.newXmlWriter( f );
1016
1017 String replaceRelativePath = null;
1018 if ( model.getParent() != null )
1019 {
1020 replaceRelativePath = model.getParent().getRelativePath();
1021
1022 }
1023
1024 if ( model.getParent() != null )
1025 {
1026 File parentFile =
1027 new File( project.getBasedir(), model.getParent().getRelativePath() ).getCanonicalFile();
1028 if ( !parentFile.isFile() )
1029 {
1030 parentFile = new File( parentFile, "pom.xml" );
1031 }
1032
1033 parentFile = parentFile.getCanonicalFile();
1034
1035 String relPath = RelativizePath.convertToRelativePath( parentFile, f );
1036 model.getParent().setRelativePath( relPath );
1037 }
1038
1039 try
1040 {
1041 PomWriter.write( w, model, true );
1042 }
1043 finally
1044 {
1045 if ( model.getParent() != null )
1046 {
1047 model.getParent().setRelativePath( replaceRelativePath );
1048 }
1049 w.close();
1050 }
1051
1052 ProjectBuildingRequest projectBuildingRequest =
1053 new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
1054 projectBuildingRequest.setLocalRepository( localRepository );
1055 projectBuildingRequest.setRemoteRepositories( remoteArtifactRepositories );
1056
1057 ProjectBuildingResult result = projectBuilder.build( f, projectBuildingRequest );
1058
1059 getLog().debug( "updateExcludesInDeps()" );
1060 modified = updateExcludesInDeps( result.getProject(), dependencies, transitiveDeps );
1061 }
1062
1063 project.setFile( dependencyReducedPomLocation );
1064 }
1065 }
1066
1067 private void removeSystemScopedDependencies( Set<String> artifactsToRemove, List<Dependency> originalDependencies )
1068 {
1069 for ( Dependency dependency : originalDependencies )
1070 {
1071 if ( dependency.getScope() != null && dependency.getScope().equalsIgnoreCase( "system" ) )
1072 {
1073 artifactsToRemove.add( getId( dependency ) );
1074 }
1075 }
1076 }
1077
1078 private void addSystemScopedDependencyFromNonInterpolatedPom( List<Dependency> dependencies,
1079 List<Dependency> originalDependencies )
1080 {
1081 for ( Dependency dependency : originalDependencies )
1082 {
1083 if ( dependency.getScope() != null && dependency.getScope().equalsIgnoreCase( "system" ) )
1084 {
1085 dependencies.add( dependency );
1086 }
1087 }
1088 }
1089
1090 private Dependency createDependency( Artifact artifact )
1091 {
1092 Dependency dep = new Dependency();
1093 dep.setArtifactId( artifact.getArtifactId() );
1094 if ( artifact.hasClassifier() )
1095 {
1096 dep.setClassifier( artifact.getClassifier() );
1097 }
1098 dep.setGroupId( artifact.getGroupId() );
1099 dep.setOptional( artifact.isOptional() );
1100 dep.setScope( artifact.getScope() );
1101 dep.setType( artifact.getType() );
1102 if ( useBaseVersion )
1103 {
1104 dep.setVersion( artifact.getBaseVersion() );
1105 }
1106 else
1107 {
1108 dep.setVersion( artifact.getVersion() );
1109 }
1110 return dep;
1111 }
1112
1113 private String getId( Artifact artifact )
1114 {
1115 return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getType(), artifact.getClassifier() );
1116 }
1117
1118 private String getId( Dependency dependency )
1119 {
1120 return getId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(),
1121 dependency.getClassifier() );
1122 }
1123
1124 private String getId( String groupId, String artifactId, String type, String classifier )
1125 {
1126 return groupId + ":" + artifactId + ":" + type + ":" + ( ( classifier != null ) ? classifier : "" );
1127 }
1128
1129 public boolean updateExcludesInDeps( MavenProject project, List<Dependency> dependencies,
1130 List<Dependency> transitiveDeps )
1131 throws DependencyGraphBuilderException
1132 {
1133 DependencyNode node = dependencyGraphBuilder.buildDependencyGraph( project, null );
1134 boolean modified = false;
1135 for ( DependencyNode n2 : node.getChildren() )
1136 {
1137 for ( DependencyNode n3 : n2.getChildren() )
1138 {
1139
1140
1141
1142
1143
1144
1145 boolean found = false;
1146 for ( Dependency dep : transitiveDeps )
1147 {
1148 if ( dep.getArtifactId().equals( n3.getArtifact().getArtifactId() )
1149 && dep.getGroupId().equals( n3.getArtifact().getGroupId() )
1150 && ( dep.getType() == null || dep.getType().equals( n3.getArtifact().getType() ) ) )
1151 {
1152 found = true;
1153 break;
1154 }
1155 }
1156
1157 if ( !found )
1158 {
1159 for ( Dependency dep : dependencies )
1160 {
1161 if ( dep.getArtifactId().equals( n2.getArtifact().getArtifactId() )
1162 && dep.getGroupId().equals( n2.getArtifact().getGroupId() )
1163 && ( dep.getType() == null || dep.getType().equals( n2.getArtifact().getType() ) ) )
1164 {
1165 Exclusion exclusion = new Exclusion();
1166 exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
1167 exclusion.setGroupId( n3.getArtifact().getGroupId() );
1168 dep.addExclusion( exclusion );
1169 modified = true;
1170 break;
1171 }
1172 }
1173 }
1174 }
1175 }
1176 return modified;
1177 }
1178 }