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