Coverage Report - org.apache.maven.plugins.shade.mojo.ShadeMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
ShadeMojo
10%
29/276
9%
13/142
6.312
 
 1  
 package org.apache.maven.plugins.shade.mojo;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.artifact.Artifact;
 23  
 import org.apache.maven.artifact.factory.ArtifactFactory;
 24  
 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
 25  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 26  
 import org.apache.maven.artifact.resolver.ArtifactCollector;
 27  
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 28  
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
 29  
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 30  
 import org.apache.maven.execution.MavenSession;
 31  
 import org.apache.maven.model.Dependency;
 32  
 import org.apache.maven.model.Exclusion;
 33  
 import org.apache.maven.model.Model;
 34  
 import org.apache.maven.plugin.AbstractMojo;
 35  
 import org.apache.maven.plugin.MojoExecutionException;
 36  
 import org.apache.maven.plugins.annotations.Component;
 37  
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 38  
 import org.apache.maven.plugins.annotations.Mojo;
 39  
 import org.apache.maven.plugins.annotations.Parameter;
 40  
 import org.apache.maven.plugins.annotations.ResolutionScope;
 41  
 import org.apache.maven.plugins.shade.ShadeRequest;
 42  
 import org.apache.maven.plugins.shade.Shader;
 43  
 import org.apache.maven.plugins.shade.filter.Filter;
 44  
 import org.apache.maven.plugins.shade.filter.MinijarFilter;
 45  
 import org.apache.maven.plugins.shade.filter.SimpleFilter;
 46  
 import org.apache.maven.plugins.shade.pom.PomWriter;
 47  
 import org.apache.maven.plugins.shade.relocation.Relocator;
 48  
 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
 49  
 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
 50  
 import org.apache.maven.project.DefaultProjectBuildingRequest;
 51  
 import org.apache.maven.project.MavenProject;
 52  
 import org.apache.maven.project.MavenProjectHelper;
 53  
 import org.apache.maven.project.ProjectBuilder;
 54  
 import org.apache.maven.project.ProjectBuildingException;
 55  
 import org.apache.maven.project.ProjectBuildingRequest;
 56  
 import org.apache.maven.project.ProjectBuildingResult;
 57  
 import org.apache.maven.shared.dependency.graph.DependencyNode;
 58  
 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
 59  
 import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
 60  
 import org.codehaus.plexus.PlexusConstants;
 61  
 import org.codehaus.plexus.PlexusContainer;
 62  
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 63  
 import org.codehaus.plexus.context.Context;
 64  
 import org.codehaus.plexus.context.ContextException;
 65  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
 66  
 import org.codehaus.plexus.util.IOUtil;
 67  
 import org.codehaus.plexus.util.WriterFactory;
 68  
 
 69  
 import java.io.File;
 70  
 import java.io.FileInputStream;
 71  
 import java.io.FileOutputStream;
 72  
 import java.io.IOException;
 73  
 import java.io.Writer;
 74  
 import java.util.ArrayList;
 75  
 import java.util.Arrays;
 76  
 import java.util.Collections;
 77  
 import java.util.HashMap;
 78  
 import java.util.HashSet;
 79  
 import java.util.LinkedHashSet;
 80  
 import java.util.List;
 81  
 import java.util.Map;
 82  
 import java.util.Set;
 83  
 
 84  
 /**
 85  
  * Mojo that performs shading delegating to the Shader component.
 86  
  *
 87  
  * @author Jason van Zyl
 88  
  * @author Mauro Talevi
 89  
  * @author David Blevins
 90  
  * @author Hiram Chirino
 91  
  */
 92  
 @Mojo( name = "shade", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true,
 93  
        requiresDependencyResolution = ResolutionScope.RUNTIME )
 94  1
 public class ShadeMojo
 95  
     extends AbstractMojo
 96  
     implements Contextualizable
 97  
 {
 98  
     /**
 99  
      * The current Maven session.
 100  
      */
 101  
     @Component
 102  
     private MavenSession session;
 103  
 
 104  
     /**
 105  
      * The current Maven project.
 106  
      */
 107  
     @Component
 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  
      * The dependency graph builder to use.
 118  
      */
 119  
     @Component
 120  
     private DependencyGraphBuilder dependencyGraphBuilder;
 121  
 
 122  
     /**
 123  
      * ProjectBuilder, needed to create projects from the artifacts.
 124  
      */
 125  
     @Component
 126  
     private ProjectBuilder projectBuilder;
 127  
 
 128  
     /**
 129  
      * The artifact metadata source to use.
 130  
      */
 131  
     @Component
 132  
     private ArtifactMetadataSource artifactMetadataSource;
 133  
 
 134  
     /**
 135  
      * Remote repositories which will be searched for source attachments.
 136  
      */
 137  
     @Parameter( readonly = true, required = true, defaultValue = "${project.remoteArtifactRepositories}" )
 138  
     protected List<ArtifactRepository> remoteArtifactRepositories;
 139  
 
 140  
     /**
 141  
      * Local maven repository.
 142  
      */
 143  
     @Parameter( readonly = true, required = true, defaultValue = "${localRepository}" )
 144  
     protected ArtifactRepository localRepository;
 145  
 
 146  
     /**
 147  
      * Artifact factory, needed to download source jars for inclusion in classpath.
 148  
      */
 149  
     @Component
 150  
     protected ArtifactFactory artifactFactory;
 151  
 
 152  
     /**
 153  
      * Artifact resolver, needed to download source jars for inclusion in classpath.
 154  
      */
 155  
     @Component
 156  
     protected ArtifactResolver artifactResolver;
 157  
 
 158  
     /**
 159  
      * Artifacts to include/exclude from the final artifact. Artifacts are denoted by composite identifiers of the
 160  
      * general form <code>groupId:artifactId:type:classifier</code>. Since version 1.3, the wildcard characters '*' and
 161  
      * '?' can be used within the sub parts of those composite identifiers to do pattern matching. For convenience, the
 162  
      * syntax <code>groupId</code> is equivalent to <code>groupId:*:*:*</code>, <code>groupId:artifactId</code> is
 163  
      * equivalent to <code>groupId:artifactId:*:*</code> and <code>groupId:artifactId:classifier</code> is equivalent to
 164  
      * <code>groupId:artifactId:*:classifier</code>. For example:
 165  
      * <pre>
 166  
      * &lt;artifactSet&gt;
 167  
      *   &lt;includes&gt;
 168  
      *     &lt;include&gt;org.apache.maven:*&lt;/include&gt;
 169  
      *   &lt;/includes&gt;
 170  
      *   &lt;excludes&gt;
 171  
      *     &lt;exclude&gt;*:maven-core&lt;/exclude&gt;
 172  
      *   &lt;/excludes&gt;
 173  
      * &lt;/artifactSet&gt;
 174  
      * </pre>
 175  
      */
 176  
     @Parameter
 177  
     private ArtifactSet artifactSet;
 178  
 
 179  
     /**
 180  
      * Packages to be relocated. For example:
 181  
      * <pre>
 182  
      * &lt;relocations&gt;
 183  
      *   &lt;relocation&gt;
 184  
      *     &lt;pattern&gt;org.apache&lt;/pattern&gt;
 185  
      *     &lt;shadedPattern&gt;hidden.org.apache&lt;/shadedPattern&gt;
 186  
      *     &lt;includes&gt;
 187  
      *       &lt;include&gt;org.apache.maven.*&lt;/include&gt;
 188  
      *     &lt;/includes&gt;
 189  
      *     &lt;excludes&gt;
 190  
      *       &lt;exclude&gt;org.apache.maven.Public*&lt;/exclude&gt;
 191  
      *     &lt;/excludes&gt;
 192  
      *   &lt;/relocation&gt;
 193  
      * &lt;/relocations&gt;
 194  
      * </pre>
 195  
      * <em>Note:</em> Support for includes exists only since version 1.4.
 196  
      */
 197  
     @Parameter
 198  
     private PackageRelocation[] relocations;
 199  
 
 200  
     /**
 201  
      * Resource transformers to be used. Please see the "Examples" section for more information on available
 202  
      * transformers and their configuration.
 203  
      */
 204  
     @Parameter
 205  
     private ResourceTransformer[] transformers;
 206  
 
 207  
     /**
 208  
      * Archive Filters to be used. Allows you to specify an artifact in the form of a composite identifier as used by
 209  
      * {@link #artifactSet} and a set of include/exclude file patterns for filtering which contents of the archive are
 210  
      * added to the shaded jar. From a logical perspective, includes are processed before excludes, thus it's possible
 211  
      * to use an include to collect a set of files from the archive then use excludes to further reduce the set. By
 212  
      * default, all files are included and no files are excluded. If multiple filters apply to an artifact, the
 213  
      * intersection of the matched files will be included in the final JAR. For example:
 214  
      * <pre>
 215  
      * &lt;filters&gt;
 216  
      *   &lt;filter&gt;
 217  
      *     &lt;artifact&gt;junit:junit&lt;/artifact&gt;
 218  
      *     &lt;includes&gt;
 219  
      *       &lt;include&gt;org/junit/**&lt;/include&gt;
 220  
      *     &lt;/includes&gt;
 221  
      *     &lt;excludes&gt;
 222  
      *       &lt;exclude&gt;org/junit/experimental/**&lt;/exclude&gt;
 223  
      *     &lt;/excludes&gt;
 224  
      *   &lt;/filter&gt;
 225  
      * &lt;/filters&gt;
 226  
      * </pre>
 227  
      */
 228  
     @Parameter
 229  
     private ArchiveFilter[] filters;
 230  
 
 231  
     /**
 232  
      * The destination directory for the shaded artifact.
 233  
      */
 234  
     @Parameter( defaultValue = "${project.build.directory}" )
 235  
     private File outputDirectory;
 236  
 
 237  
     /**
 238  
      * The name of the shaded artifactId.
 239  
      * <p/>
 240  
      * If you like to change the name of the native artifact, you may use the &lt;build>&lt;finalName> setting.
 241  
      * If this is set to something different than &lt;build>&lt;finalName>, no file replacement
 242  
      * will be performed, even if shadedArtifactAttached is being used.
 243  
      */
 244  
     @Parameter
 245  
     private String finalName;
 246  
 
 247  
     /**
 248  
      * The name of the shaded artifactId. So you may want to use a different artifactId and keep
 249  
      * the standard version. If the original artifactId was "foo" then the final artifact would
 250  
      * be something like foo-1.0.jar. So if you change the artifactId you might have something
 251  
      * like foo-special-1.0.jar.
 252  
      */
 253  
     @Parameter( defaultValue = "${project.artifactId}" )
 254  
     private String shadedArtifactId;
 255  
 
 256  
     /**
 257  
      * If specified, this will include only artifacts which have groupIds which
 258  
      * start with this.
 259  
      */
 260  
     @Parameter
 261  
     private String shadedGroupFilter;
 262  
 
 263  
     /**
 264  
      * Defines whether the shaded artifact should be attached as classifier to
 265  
      * the original artifact.  If false, the shaded jar will be the main artifact
 266  
      * of the project
 267  
      */
 268  
     @Parameter
 269  
     private boolean shadedArtifactAttached;
 270  
 
 271  
     /**
 272  
      * Flag whether to generate a simplified POM for the shaded artifact. If set to <code>true</code>, dependencies that
 273  
      * have been included into the uber JAR will be removed from the <code>&lt;dependencies&gt;</code> section of the
 274  
      * generated POM. The reduced POM will be named <code>dependency-reduced-pom.xml</code> and is stored into the same
 275  
      * directory as the shaded artifact. Unless you also specify dependencyReducedPomLocation, the plugin will
 276  
      * create a temporary file named <code>dependency-reduced-pom.xml</code> in the project basedir.
 277  
      */
 278  
     @Parameter( defaultValue = "true" )
 279  
     private boolean createDependencyReducedPom;
 280  
 
 281  
 
 282  
     /**
 283  
      * Where to put the dependency reduced pom.
 284  
      * Note: setting a value for this parameter with a directory other than ${basedir} will change the value of ${basedir}
 285  
      * for all executions that come after the shade execution. This is often not what you want. This is considered
 286  
      * an open issue with this plugin.
 287  
      *
 288  
      * @since 1.7
 289  
      */
 290  
     @Parameter( defaultValue = "${basedir}/dependency-reduced-pom.xml" )
 291  
     private File dependencyReducedPomLocation;
 292  
 
 293  
     /**
 294  
      * Create a dependency-reduced POM in ${basedir}/drp-UNIQUE.pom. This avoids build collisions
 295  
      * of parallel builds without moving the dependency-reduced POM to a different directory.
 296  
      * The property maven.shade.dependency-reduced-pom is set to the generated filename.
 297  
      *
 298  
      * @since 1.7.2
 299  
      */
 300  
     @Parameter( defaultValue = "false" )
 301  
     private boolean generateUniqueDependencyReducedPom;
 302  
 
 303  
     /**
 304  
      * When true, dependencies are kept in the pom but with scope 'provided'; when false,
 305  
      * the dependency is removed.
 306  
      */
 307  
     @Parameter
 308  
     private boolean keepDependenciesWithProvidedScope;
 309  
 
 310  
     /**
 311  
      * When true, transitive deps of removed dependencies are promoted to direct dependencies.
 312  
      * This should allow the drop in replacement of the removed deps with the new shaded
 313  
      * jar and everything should still work.
 314  
      */
 315  
     @Parameter
 316  
     private boolean promoteTransitiveDependencies;
 317  
 
 318  
     /**
 319  
      * The name of the classifier used in case the shaded artifact is attached.
 320  
      */
 321  
     @Parameter( defaultValue = "shaded" )
 322  
     private String shadedClassifierName;
 323  
 
 324  
     /**
 325  
      * When true, it will attempt to create a sources jar as well
 326  
      */
 327  
     @Parameter
 328  
     private boolean createSourcesJar;
 329  
 
 330  
     /**
 331  
      * When true, it will attempt to shade the contents of the java source files when creating the sources jar.
 332  
      * When false, it will just relocate the java source files to the shaded paths, but will not modify the
 333  
      * actual contents of the java source files.
 334  
      *
 335  
      */
 336  
     @Parameter(property = "shadeSourcesContent", defaultValue = "false")
 337  
     private boolean shadeSourcesContent;
 338  
 
 339  
     /**
 340  
      * When true, dependencies will be stripped down on the class level to only the transitive hull required for the
 341  
      * artifact. <em>Note:</em> Usage of this feature requires Java 1.5 or higher.
 342  
      *
 343  
      * @since 1.4
 344  
      */
 345  
     @Parameter
 346  
     private boolean minimizeJar;
 347  
 
 348  
     /**
 349  
      * The path to the output file for the shaded artifact. When this parameter is set, the created archive will neither
 350  
      * replace the project's main artifact nor will it be attached. Hence, this parameter causes the parameters
 351  
      * {@link #finalName}, {@link #shadedArtifactAttached}, {@link #shadedClassifierName} and
 352  
      * {@link #createDependencyReducedPom} to be ignored when used.
 353  
      *
 354  
      * @since 1.3
 355  
      */
 356  
     @Parameter
 357  
     private File outputFile;
 358  
 
 359  
     /**
 360  
      * You can pass here the roleHint about your own Shader implementation plexus component.
 361  
      *
 362  
      * @since 1.6
 363  
      */
 364  
     @Parameter
 365  
     private String shaderHint;
 366  
 
 367  
     /**
 368  
      * @since 1.6
 369  
      */
 370  
     private PlexusContainer plexusContainer;
 371  
 
 372  
     public void contextualize( Context context )
 373  
         throws ContextException
 374  
     {
 375  0
         plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
 376  0
     }
 377  
 
 378  
     /**
 379  
      * @throws MojoExecutionException
 380  
      */
 381  
     public void execute()
 382  
         throws MojoExecutionException
 383  
     {
 384  
 
 385  0
         if ( shaderHint != null )
 386  
         {
 387  
             try
 388  
             {
 389  0
                 shader = (Shader) plexusContainer.lookup( Shader.ROLE, shaderHint );
 390  
             }
 391  0
             catch ( ComponentLookupException e )
 392  
             {
 393  0
                 throw new MojoExecutionException(
 394  
                     "unable to lookup own Shader implementation with hint:'" + shaderHint + "'", e );
 395  0
             }
 396  
         }
 397  
 
 398  0
         Set<File> artifacts = new LinkedHashSet<File>();
 399  0
         Set<String> artifactIds = new LinkedHashSet<String>();
 400  0
         Set<File> sourceArtifacts = new LinkedHashSet<File>();
 401  
 
 402  0
         ArtifactSelector artifactSelector =
 403  
             new ArtifactSelector( project.getArtifact(), artifactSet, shadedGroupFilter );
 404  
 
 405  0
         if ( artifactSelector.isSelected( project.getArtifact() ) && !"pom".equals( project.getArtifact().getType() ) )
 406  
         {
 407  0
             if ( invalidMainArtifact() )
 408  
             {
 409  0
                 getLog().error( "The project main artifact does not exist. This could have the following" );
 410  0
                 getLog().error( "reasons:" );
 411  0
                 getLog().error( "- You have invoked the goal directly from the command line. This is not" );
 412  0
                 getLog().error( "  supported. Please add the goal to the default lifecycle via an" );
 413  0
                 getLog().error( "  <execution> element in your POM and use \"mvn package\" to have it run." );
 414  0
                 getLog().error( "- You have bound the goal to a lifecycle phase before \"package\". Please" );
 415  0
                 getLog().error( "  remove this binding from your POM such that the goal will be run in" );
 416  0
                 getLog().error( "  the proper phase." );
 417  0
                 getLog().error(
 418  
                     "- You removed the configuration of the maven-jar-plugin that produces the main artifact." );
 419  0
                 throw new MojoExecutionException(
 420  
                     "Failed to create shaded artifact, " + "project main artifact does not exist." );
 421  
             }
 422  
 
 423  0
             artifacts.add( project.getArtifact().getFile() );
 424  
 
 425  0
             if ( createSourcesJar )
 426  
             {
 427  0
                 File file = shadedSourcesArtifactFile();
 428  0
                 if ( file.isFile() )
 429  
                 {
 430  0
                     sourceArtifacts.add( file );
 431  
                 }
 432  
             }
 433  
         }
 434  
 
 435  0
         for ( Artifact artifact : project.getArtifacts() )
 436  
         {
 437  0
             if ( !artifactSelector.isSelected( artifact ) )
 438  
             {
 439  0
                 getLog().info( "Excluding " + artifact.getId() + " from the shaded jar." );
 440  
 
 441  0
                 continue;
 442  
             }
 443  
 
 444  0
             if ( "pom".equals( artifact.getType() ) )
 445  
             {
 446  0
                 getLog().info( "Skipping pom dependency " + artifact.getId() + " in the shaded jar." );
 447  0
                 continue;
 448  
             }
 449  
 
 450  0
             getLog().info( "Including " + artifact.getId() + " in the shaded jar." );
 451  
 
 452  0
             artifacts.add( artifact.getFile() );
 453  0
             artifactIds.add( getId( artifact ) );
 454  
 
 455  0
             if ( createSourcesJar )
 456  
             {
 457  0
                 File file = resolveArtifactSources( artifact );
 458  0
                 if ( file != null )
 459  
                 {
 460  0
                     sourceArtifacts.add( file );
 461  
                 }
 462  0
             }
 463  
         }
 464  
 
 465  0
         File outputJar = ( outputFile != null ) ? outputFile : shadedArtifactFileWithClassifier();
 466  0
         File sourcesJar = shadedSourceArtifactFileWithClassifier();
 467  
 
 468  
         // Now add our extra resources
 469  
         try
 470  
         {
 471  0
             List<Filter> filters = getFilters();
 472  
 
 473  0
             List<Relocator> relocators = getRelocators();
 474  
 
 475  0
             List<ResourceTransformer> resourceTransformers = getResourceTransformers();
 476  
 
 477  0
             ShadeRequest shadeRequest = new ShadeRequest();
 478  0
             shadeRequest.setJars( artifacts );
 479  0
             shadeRequest.setUberJar( outputJar );
 480  0
             shadeRequest.setFilters( filters );
 481  0
             shadeRequest.setRelocators( relocators );
 482  0
             shadeRequest.setResourceTransformers( resourceTransformers );
 483  
 
 484  0
             shader.shade( shadeRequest );
 485  
 
 486  0
             if ( createSourcesJar )
 487  
             {
 488  0
                 ShadeRequest shadeSourcesRequest = new ShadeRequest();
 489  0
                 shadeSourcesRequest.setJars( sourceArtifacts );
 490  0
                 shadeSourcesRequest.setUberJar( sourcesJar );
 491  0
                 shadeSourcesRequest.setFilters( filters );
 492  0
                 shadeSourcesRequest.setRelocators( relocators );
 493  0
                 shadeSourcesRequest.setResourceTransformers( resourceTransformers );
 494  0
                 shadeSourcesRequest.setShadeSourcesContent( shadeSourcesContent );
 495  
 
 496  0
                 shader.shade( shadeSourcesRequest );
 497  
             }
 498  
 
 499  0
             if ( outputFile == null )
 500  
             {
 501  0
                 boolean renamed = false;
 502  
 
 503  
                 // rename the output file if a specific finalName is set
 504  
                 // but don't rename if the finalName is the <build><finalName>
 505  
                 // because this will be handled implicitly later
 506  0
                 if ( finalName != null && finalName.length() > 0 && !finalName.equals(
 507  
                     project.getBuild().getFinalName() ) )
 508  
                 {
 509  0
                     String finalFileName = finalName + "." + project.getArtifact().getArtifactHandler().getExtension();
 510  0
                     File finalFile = new File( outputDirectory, finalFileName );
 511  0
                     replaceFile( finalFile, outputJar );
 512  0
                     outputJar = finalFile;
 513  
 
 514  0
                     renamed = true;
 515  
                 }
 516  
 
 517  0
                 if ( shadedArtifactAttached )
 518  
                 {
 519  0
                     getLog().info( "Attaching shaded artifact." );
 520  0
                     projectHelper.attachArtifact( project, project.getArtifact().getType(), shadedClassifierName,
 521  
                                                   outputJar );
 522  0
                     if ( createSourcesJar )
 523  
                     {
 524  0
                         projectHelper.attachArtifact( project, "jar", shadedClassifierName + "-sources", sourcesJar );
 525  
                     }
 526  
                 }
 527  0
                 else if ( !renamed )
 528  
                 {
 529  0
                     getLog().info( "Replacing original artifact with shaded artifact." );
 530  0
                     File originalArtifact = project.getArtifact().getFile();
 531  0
                     replaceFile( originalArtifact, outputJar );
 532  
 
 533  0
                     if ( createSourcesJar )
 534  
                     {
 535  0
                         File shadedSources = shadedSourcesArtifactFile();
 536  
 
 537  0
                         replaceFile( shadedSources, sourcesJar );
 538  
 
 539  0
                         projectHelper.attachArtifact( project, "jar", "sources", shadedSources );
 540  
                     }
 541  
 
 542  0
                     if ( createDependencyReducedPom )
 543  
                     {
 544  0
                         createDependencyReducedPom( artifactIds );
 545  
                     }
 546  
                 }
 547  
             }
 548  
         }
 549  0
         catch ( Exception e )
 550  
         {
 551  0
             throw new MojoExecutionException( "Error creating shaded jar: " + e.getMessage(), e );
 552  0
         }
 553  0
     }
 554  
 
 555  
     private boolean invalidMainArtifact()
 556  
     {
 557  0
         return project.getArtifact().getFile() == null || !project.getArtifact().getFile().isFile();
 558  
     }
 559  
 
 560  
     private void replaceFile( File oldFile, File newFile )
 561  
         throws MojoExecutionException
 562  
     {
 563  0
         getLog().info( "Replacing " + oldFile + " with " + newFile );
 564  
 
 565  0
         File origFile = new File( outputDirectory, "original-" + oldFile.getName() );
 566  0
         if ( oldFile.exists() && !oldFile.renameTo( origFile ) )
 567  
         {
 568  
             //try a gc to see if an unclosed stream needs garbage collecting
 569  0
             System.gc();
 570  0
             System.gc();
 571  
 
 572  0
             if ( !oldFile.renameTo( origFile ) )
 573  
             {
 574  
                 // Still didn't work.   We'll do a copy
 575  
                 try
 576  
                 {
 577  0
                     FileOutputStream fout = new FileOutputStream( origFile );
 578  0
                     FileInputStream fin = new FileInputStream( oldFile );
 579  
                     try
 580  
                     {
 581  0
                         IOUtil.copy( fin, fout );
 582  
                     }
 583  
                     finally
 584  
                     {
 585  0
                         IOUtil.close( fin );
 586  0
                         IOUtil.close( fout );
 587  0
                     }
 588  
                 }
 589  0
                 catch ( IOException ex )
 590  
                 {
 591  
                     //kind of ignorable here.   We're just trying to save the original
 592  0
                     getLog().warn( ex );
 593  0
                 }
 594  
             }
 595  
         }
 596  0
         if ( !newFile.renameTo( oldFile ) )
 597  
         {
 598  
             //try a gc to see if an unclosed stream needs garbage collecting
 599  0
             System.gc();
 600  0
             System.gc();
 601  
 
 602  0
             if ( !newFile.renameTo( oldFile ) )
 603  
             {
 604  
                 // Still didn't work.   We'll do a copy
 605  
                 try
 606  
                 {
 607  0
                     FileOutputStream fout = new FileOutputStream( oldFile );
 608  0
                     FileInputStream fin = new FileInputStream( newFile );
 609  
                     try
 610  
                     {
 611  0
                         IOUtil.copy( fin, fout );
 612  
                     }
 613  
                     finally
 614  
                     {
 615  0
                         IOUtil.close( fin );
 616  0
                         IOUtil.close( fout );
 617  0
                     }
 618  
                 }
 619  0
                 catch ( IOException ex )
 620  
                 {
 621  0
                     throw new MojoExecutionException( "Could not replace original artifact with shaded artifact!", ex );
 622  0
                 }
 623  
             }
 624  
         }
 625  0
     }
 626  
 
 627  
     private File resolveArtifactSources( Artifact artifact )
 628  
     {
 629  
 
 630  1
         Artifact resolvedArtifact =
 631  
             artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
 632  
                                                           artifact.getVersion(), "java-source", "sources" );
 633  
 
 634  
         try
 635  
         {
 636  1
             artifactResolver.resolve( resolvedArtifact, remoteArtifactRepositories, localRepository );
 637  
         }
 638  0
         catch ( ArtifactNotFoundException e )
 639  
         {
 640  
             // ignore, the jar has not been found
 641  
         }
 642  0
         catch ( ArtifactResolutionException e )
 643  
         {
 644  0
             getLog().warn( "Could not get sources for " + artifact );
 645  1
         }
 646  
 
 647  1
         if ( resolvedArtifact.isResolved() )
 648  
         {
 649  1
             return resolvedArtifact.getFile();
 650  
         }
 651  0
         return null;
 652  
     }
 653  
 
 654  
     private List<Relocator> getRelocators()
 655  
     {
 656  0
         List<Relocator> relocators = new ArrayList<Relocator>();
 657  
 
 658  0
         if ( relocations == null )
 659  
         {
 660  0
             return relocators;
 661  
         }
 662  
 
 663  0
         for ( int i = 0; i < relocations.length; i++ )
 664  
         {
 665  0
             PackageRelocation r = relocations[i];
 666  
 
 667  0
             relocators.add( new SimpleRelocator( r.getPattern(), r.getShadedPattern(), r.getIncludes(), r.getExcludes(),
 668  
                                                  r.isRawString() ) );
 669  
         }
 670  
 
 671  0
         return relocators;
 672  
     }
 673  
 
 674  
     private List<ResourceTransformer> getResourceTransformers()
 675  
     {
 676  0
         if ( transformers == null )
 677  
         {
 678  0
             return Collections.emptyList();
 679  
         }
 680  
 
 681  0
         return Arrays.asList( transformers );
 682  
     }
 683  
 
 684  
     private List<Filter> getFilters()
 685  
         throws MojoExecutionException
 686  
     {
 687  1
         List<Filter> filters = new ArrayList<Filter>();
 688  1
         List<SimpleFilter> simpleFilters = new ArrayList<SimpleFilter>();
 689  
 
 690  1
         if ( this.filters != null && this.filters.length > 0 )
 691  
         {
 692  1
             Map<Artifact, ArtifactId> artifacts = new HashMap<Artifact, ArtifactId>();
 693  
 
 694  1
             artifacts.put( project.getArtifact(), new ArtifactId( project.getArtifact() ) );
 695  
 
 696  1
             for ( Artifact artifact : project.getArtifacts() )
 697  
             {
 698  0
                 artifacts.put( artifact, new ArtifactId( artifact ) );
 699  
             }
 700  
 
 701  2
             for ( ArchiveFilter filter : this.filters )
 702  
             {
 703  1
                 ArtifactId pattern = new ArtifactId( filter.getArtifact() );
 704  
 
 705  1
                 Set<File> jars = new HashSet<File>();
 706  
 
 707  1
                 for ( Map.Entry<Artifact, ArtifactId> entry : artifacts.entrySet() )
 708  
                 {
 709  1
                     if ( entry.getValue().matches( pattern ) )
 710  
                     {
 711  1
                         Artifact artifact = entry.getKey();
 712  
 
 713  1
                         jars.add( artifact.getFile() );
 714  
 
 715  1
                         if ( createSourcesJar )
 716  
                         {
 717  1
                             File file = resolveArtifactSources( artifact );
 718  1
                             if ( file != null )
 719  
                             {
 720  1
                                 jars.add( file );
 721  
                             }
 722  
                         }
 723  1
                     }
 724  
                 }
 725  
 
 726  1
                 if ( jars.isEmpty() )
 727  
                 {
 728  0
                     getLog().info( "No artifact matching filter " + filter.getArtifact() );
 729  
 
 730  0
                     continue;
 731  
                 }
 732  
 
 733  1
                 simpleFilters.add( new SimpleFilter( jars, filter.getIncludes(), filter.getExcludes() ) );
 734  
             }
 735  
         }
 736  
 
 737  1
         filters.addAll( simpleFilters );
 738  
 
 739  1
         if ( minimizeJar )
 740  
         {
 741  0
             getLog().info( "Minimizing jar " + project.getArtifact() );
 742  
 
 743  
             try
 744  
             {
 745  0
                 filters.add( new MinijarFilter( project, getLog(), simpleFilters ) );
 746  
             }
 747  0
             catch ( IOException e )
 748  
             {
 749  0
                 throw new MojoExecutionException( "Failed to analyze class dependencies", e );
 750  0
             }
 751  
         }
 752  
 
 753  1
         return filters;
 754  
     }
 755  
 
 756  
     private File shadedArtifactFileWithClassifier()
 757  
     {
 758  0
         Artifact artifact = project.getArtifact();
 759  0
         final String shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "."
 760  
             + artifact.getArtifactHandler().getExtension();
 761  0
         return new File( outputDirectory, shadedName );
 762  
     }
 763  
 
 764  
     private File shadedSourceArtifactFileWithClassifier()
 765  
     {
 766  0
         Artifact artifact = project.getArtifact();
 767  0
         final String shadedName =
 768  
             shadedArtifactId + "-" + artifact.getVersion() + "-" + shadedClassifierName + "-sources."
 769  
                 + artifact.getArtifactHandler().getExtension();
 770  0
         return new File( outputDirectory, shadedName );
 771  
     }
 772  
 
 773  
     private File shadedSourcesArtifactFile()
 774  
     {
 775  0
         Artifact artifact = project.getArtifact();
 776  
 
 777  
         String shadedName;
 778  
 
 779  0
         if ( project.getBuild().getFinalName() != null )
 780  
         {
 781  0
             shadedName = project.getBuild().getFinalName() + "-sources." + artifact.getArtifactHandler().getExtension();
 782  
         }
 783  
         else
 784  
         {
 785  0
             shadedName = shadedArtifactId + "-" + artifact.getVersion() + "-sources."
 786  
                 + artifact.getArtifactHandler().getExtension();
 787  
         }
 788  
 
 789  0
         return new File( outputDirectory, shadedName );
 790  
     }
 791  
 
 792  
     // We need to find the direct dependencies that have been included in the uber JAR so that we can modify the
 793  
     // POM accordingly.
 794  
     private void createDependencyReducedPom( Set<String> artifactsToRemove )
 795  
         throws IOException, DependencyGraphBuilderException, ProjectBuildingException
 796  
     {
 797  0
         Model model = project.getOriginalModel();
 798  0
         List<Dependency> dependencies = new ArrayList<Dependency>();
 799  
 
 800  0
         boolean modified = false;
 801  
 
 802  0
         List<Dependency> transitiveDeps = new ArrayList<Dependency>();
 803  
 
 804  0
         for ( Artifact artifact : project.getArtifacts() )
 805  
         {
 806  0
             if ( "pom".equals( artifact.getType() ) )
 807  
             {
 808  
                 // don't include pom type dependencies in dependency reduced pom
 809  0
                 continue;
 810  
             }
 811  
 
 812  
             //promote
 813  0
             Dependency dep = new Dependency();
 814  0
             dep.setArtifactId( artifact.getArtifactId() );
 815  0
             if ( artifact.hasClassifier() )
 816  
             {
 817  0
                 dep.setClassifier( artifact.getClassifier() );
 818  
             }
 819  0
             dep.setGroupId( artifact.getGroupId() );
 820  0
             dep.setOptional( artifact.isOptional() );
 821  0
             dep.setScope( artifact.getScope() );
 822  0
             dep.setType( artifact.getType() );
 823  0
             dep.setVersion( artifact.getVersion() );
 824  
 
 825  
             //we'll figure out the exclusions in a bit.
 826  
 
 827  0
             transitiveDeps.add( dep );
 828  0
         }
 829  0
         List<Dependency> origDeps = project.getDependencies();
 830  
 
 831  0
         if ( promoteTransitiveDependencies )
 832  
         {
 833  0
             origDeps = transitiveDeps;
 834  
         }
 835  
 
 836  0
         for ( Dependency d : origDeps )
 837  
         {
 838  0
             dependencies.add( d );
 839  
 
 840  0
             String id = getId( d );
 841  
 
 842  0
             if ( artifactsToRemove.contains( id ) )
 843  
             {
 844  0
                 modified = true;
 845  
 
 846  0
                 if ( keepDependenciesWithProvidedScope )
 847  
                 {
 848  0
                     d.setScope( "provided" );
 849  
                 }
 850  
                 else
 851  
                 {
 852  0
                     dependencies.remove( d );
 853  
                 }
 854  
             }
 855  0
         }
 856  
 
 857  
         // Check to see if we have a reduction and if so rewrite the POM.
 858  0
         if ( modified )
 859  
         {
 860  0
             while ( modified )
 861  
             {
 862  
 
 863  0
                 model.setDependencies( dependencies );
 864  
 
 865  0
                 if ( generateUniqueDependencyReducedPom )
 866  
                 {
 867  0
                     dependencyReducedPomLocation = File.createTempFile( "dependency-reduced-pom-", ".xml", project.getBasedir() );
 868  0
                     project.getProperties().setProperty( "maven.shade.dependency-reduced-pom", dependencyReducedPomLocation.getAbsolutePath() );
 869  
                 }
 870  
                 else
 871  
                 {
 872  0
                     if ( dependencyReducedPomLocation == null )
 873  
                     {
 874  
                         // MSHADE-123: We can't default to 'target' because it messes up uses of ${project.basedir}
 875  0
                         dependencyReducedPomLocation = new File( project.getBasedir(), "dependency-reduced-pom.xml" );
 876  
                     }
 877  
                 }
 878  
 
 879  0
                 File f = dependencyReducedPomLocation;
 880  0
                 getLog().info( "Dependency-reduced POM written at: " + f.getAbsolutePath() );
 881  
 
 882  0
                 if ( f.exists() )
 883  
                 {
 884  0
                     f.delete();
 885  
                 }
 886  
 
 887  0
                 Writer w = WriterFactory.newXmlWriter( f );
 888  
 
 889  0
                 String origRelativePath = null;
 890  0
                 String replaceRelativePath = null;
 891  0
                 if ( model.getParent() != null )
 892  
                 {
 893  0
                     origRelativePath = model.getParent().getRelativePath();
 894  
 
 895  
                 }
 896  0
                 replaceRelativePath = origRelativePath;
 897  
 
 898  0
                 if ( origRelativePath == null )
 899  
                 {
 900  0
                     origRelativePath = "../pom.xml";
 901  
                 }
 902  
 
 903  0
                 if ( model.getParent() != null )
 904  
                 {
 905  0
                     File parentFile =
 906  
                         new File( project.getBasedir(), model.getParent().getRelativePath() ).getCanonicalFile();
 907  0
                     if ( !parentFile.isFile() )
 908  
                     {
 909  0
                         parentFile = new File( parentFile, "pom.xml" );
 910  
                     }
 911  
 
 912  0
                     parentFile = parentFile.getCanonicalFile();
 913  
 
 914  0
                     String relPath = RelativizePath.convertToRelativePath( parentFile, f );
 915  0
                     model.getParent().setRelativePath( relPath );
 916  
                 }
 917  
 
 918  
                 try
 919  
                 {
 920  0
                     PomWriter.write( w, model, true );
 921  
                 }
 922  
                 finally
 923  
                 {
 924  0
                     if ( model.getParent() != null )
 925  
                     {
 926  0
                         model.getParent().setRelativePath( replaceRelativePath );
 927  
                     }
 928  0
                     w.close();
 929  0
                 }
 930  
 
 931  0
                 ProjectBuildingRequest projectBuildingRequest =
 932  
                     new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
 933  0
                 projectBuildingRequest.setLocalRepository( localRepository );
 934  0
                 projectBuildingRequest.setRemoteRepositories( remoteArtifactRepositories );
 935  
 
 936  0
                 ProjectBuildingResult result = projectBuilder.build( f, projectBuildingRequest );
 937  
 
 938  0
                 modified = updateExcludesInDeps( result.getProject(), dependencies, transitiveDeps );
 939  0
             }
 940  
 
 941  0
             project.setFile( dependencyReducedPomLocation );
 942  
         }
 943  0
     }
 944  
 
 945  
     private String getId( Artifact artifact )
 946  
     {
 947  0
         return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getType(), artifact.getClassifier() );
 948  
     }
 949  
 
 950  
     private String getId( Dependency dependency )
 951  
     {
 952  0
         return getId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(),
 953  
                       dependency.getClassifier() );
 954  
     }
 955  
 
 956  
     private String getId( String groupId, String artifactId, String type, String classifier )
 957  
     {
 958  0
         return groupId + ":" + artifactId + ":" + type + ":" + ( ( classifier != null ) ? classifier : "" );
 959  
     }
 960  
 
 961  
     public boolean updateExcludesInDeps( MavenProject project, List<Dependency> dependencies,
 962  
                                          List<Dependency> transitiveDeps )
 963  
         throws DependencyGraphBuilderException
 964  
     {
 965  0
         DependencyNode node = dependencyGraphBuilder.buildDependencyGraph( project, null );
 966  0
         boolean modified = false;
 967  0
         for ( DependencyNode n2 : node.getChildren() )
 968  
         {
 969  0
             for ( DependencyNode n3 : n2.getChildren() )
 970  
             {
 971  
                 //check if it really isn't in the list of original dependencies.  Maven
 972  
                 //prior to 2.0.8 may grab versions from transients instead of
 973  
                 //from the direct deps in which case they would be marked included
 974  
                 //instead of OMITTED_FOR_DUPLICATE
 975  
 
 976  
                 //also, if not promoting the transitives, level 2's would be included
 977  0
                 boolean found = false;
 978  0
                 for ( Dependency dep : transitiveDeps )
 979  
                 {
 980  0
                     if ( dep.getArtifactId().equals( n3.getArtifact().getArtifactId() )
 981  
                         && dep.getGroupId().equals( n3.getArtifact().getGroupId() ) )
 982  
                     {
 983  0
                         found = true;
 984  0
                         break;
 985  
                     }
 986  
                 }
 987  
 
 988  0
                 if ( !found )
 989  
                 {
 990  0
                     for ( Dependency dep : dependencies )
 991  
                     {
 992  0
                         if ( dep.getArtifactId().equals( n2.getArtifact().getArtifactId() )
 993  
                             && dep.getGroupId().equals( n2.getArtifact().getGroupId() ) )
 994  
                         {
 995  0
                             Exclusion exclusion = new Exclusion();
 996  0
                             exclusion.setArtifactId( n3.getArtifact().getArtifactId() );
 997  0
                             exclusion.setGroupId( n3.getArtifact().getGroupId() );
 998  0
                             dep.addExclusion( exclusion );
 999  0
                             modified = true;
 1000  0
                             break;
 1001  
                         }
 1002  
                     }
 1003  
                 }
 1004  0
             }
 1005  
         }
 1006  0
         return modified;
 1007  
     }
 1008  
 }