Coverage Report - org.apache.maven.plugin.dependency.BuildClasspathMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
BuildClasspathMojo
63%
78/124
58%
35/60
2.346
 
 1  
 package org.apache.maven.plugin.dependency;
 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 java.io.BufferedReader;
 23  
 import java.io.BufferedWriter;
 24  
 import java.io.File;
 25  
 import java.io.FileReader;
 26  
 import java.io.FileWriter;
 27  
 import java.io.IOException;
 28  
 import java.io.Writer;
 29  
 import java.util.ArrayList;
 30  
 import java.util.Comparator;
 31  
 import java.util.Iterator;
 32  
 import java.util.List;
 33  
 import java.util.Set;
 34  
 
 35  
 import org.apache.maven.artifact.Artifact;
 36  
 import org.apache.maven.plugin.MojoExecutionException;
 37  
 import org.apache.maven.plugin.dependency.utils.DependencyUtil;
 38  
 import org.apache.maven.project.MavenProjectHelper;
 39  
 import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
 40  
 import org.codehaus.plexus.util.StringUtils;
 41  
 
 42  
 /**
 43  
  * This goal will output a classpath string of dependencies from the local repository to a file or log.
 44  
  * 
 45  
  * @goal build-classpath
 46  
  * @requiresDependencyResolution test
 47  
  * @phase generate-sources
 48  
  * @author ankostis
 49  
  * @version $Id: BuildClasspathMojo.java 728546 2008-12-21 22:56:51Z bentmann $
 50  
  * @since 2.0-alpha-2
 51  
  */
 52  2
 public class BuildClasspathMojo
 53  
     extends AbstractDependencyFilterMojo
 54  
     implements Comparator
 55  
 {
 56  
 
 57  
     /**
 58  
      * Strip artifact version during copy (only works if prefix is set)
 59  
      * 
 60  
      * @parameter expression="${mdep.stripVersion}" default-value="false"
 61  
      * @parameter
 62  
      */
 63  2
     private boolean stripVersion = false;
 64  
 
 65  
     /**
 66  
      * The prefix to prepend on each dependent artifact. If undefined, the paths refer to the actual files store in the
 67  
      * local repository (the stipVersion parameter does nothing then).
 68  
      * 
 69  
      * @parameter expression="${mdep.prefix}"
 70  
      */
 71  
     private String prefix;
 72  
 
 73  
     /**
 74  
      * The file to write the classpath string. If undefined, it just prints the classpath as [INFO].
 75  
      * This parameter is deprecated. Use outputFile instead.
 76  
      * @parameter expression="${mdep.cpFile}"
 77  
      * @deprecated use outputFile instead
 78  
      * @since 2.0
 79  
      */
 80  
     private File cpFile;
 81  
 
 82  
     /**
 83  
      * The file to write the classpath string. If undefined, it just prints the classpath as [INFO].
 84  
      * @parameter expression="${mdep.outputFile}"
 85  
      */
 86  
     private File outputFile;
 87  
     
 88  
     /**
 89  
      * If 'true', it skips the up-to-date-check, and always regenerates the classpath file.
 90  
      * 
 91  
      * @parameter default-value="false" expression="${mdep.regenerateFile}"
 92  
      */
 93  
     private boolean regenerateFile;
 94  
 
 95  
     /**
 96  
      * Override the char used between the paths. This field is initialized to contain the first character of the value
 97  
      * of the system property file.separator. On UNIX systems the value of this field is '/'; on Microsoft Windows
 98  
      * systems it is '\'. The default is File.separator
 99  
      * 
 100  
      * @since 2.0
 101  
      * @parameter default-value="" expression="${mdep.fileSeparator}"
 102  
      */
 103  
     private String fileSeparator;
 104  
 
 105  
     /**
 106  
      * Override the char used between path folders. The system-dependent path-separator character. This field is
 107  
      * initialized to contain the first character of the value of the system property path.separator. This character is
 108  
      * used to separate filenames in a sequence of files given as a path list. On UNIX systems, this character is ':';
 109  
      * on Microsoft Windows systems it is ';'.
 110  
      * 
 111  
      * @since 2.0
 112  
      * @parameter default-value="" expression="${mdep.pathSeparator}"
 113  
      */
 114  
     private String pathSeparator;
 115  
 
 116  
     /**
 117  
      * Replace the absolute path to the local repo with this property. This field is ignored it prefix is declared. The
 118  
      * value will be forced to "${M2_REPO}" if no value is provided AND the attach flag is true.
 119  
      * 
 120  
      * @since 2.0
 121  
      * @parameter default-value="" expression="${mdep.localRepoProperty}"
 122  
      */
 123  
     private String localRepoProperty;
 124  
 
 125  
     /**
 126  
      * Attach the classpath file to the main artifact so it can be installed and deployed.
 127  
      * 
 128  
      * @since 2.0
 129  
      * @parameter default-value=false
 130  
      */
 131  
     boolean attach;
 132  
     
 133  
     /**
 134  
      * Write out the classpath in a format compatible with filtering (classpath=xxxxx)
 135  
      * 
 136  
      * @since 2.0
 137  
      * @parameter default-value=false expression="${mdep.outputFilterFile}"
 138  
      */
 139  
     boolean outputFilterFile;
 140  
 
 141  
     /**
 142  
      * Maven ProjectHelper
 143  
      * 
 144  
      * @component
 145  
      * @readonly
 146  
      */
 147  
     private MavenProjectHelper projectHelper;
 148  
 
 149  2
     boolean isFileSepSet = true;
 150  
 
 151  2
     boolean isPathSepSet = true;
 152  
 
 153  
     /**
 154  
      * Main entry into mojo. Gets the list of dependencies and iterates through calling copyArtifact.
 155  
      * 
 156  
      * @throws MojoExecutionException with a message if an error occurs.
 157  
      * @see #getDependencies
 158  
      * @see #copyArtifact(Artifact, boolean)
 159  
      */
 160  
     public void execute()
 161  
         throws MojoExecutionException
 162  
     {
 163  
         
 164  3
         if (cpFile != null)
 165  
         {
 166  0
             getLog().warn( "The parameter cpFile is deprecated. Use outputFile instead." );
 167  0
             this.outputFile = cpFile;
 168  
         }
 169  
         
 170  
         // initialize the separators.
 171  3
         if ( StringUtils.isEmpty( fileSeparator ) )
 172  
         {
 173  2
             isFileSepSet = false;
 174  
         }
 175  
         else
 176  
         {
 177  1
             isFileSepSet = true;
 178  
         }
 179  
 
 180  3
         if ( StringUtils.isEmpty( pathSeparator ) )
 181  
         {
 182  2
             isPathSepSet = false;
 183  
         }
 184  
         else
 185  
         {
 186  1
             isPathSepSet = true;
 187  
         }
 188  
 
 189  
         //don't allow them to have absolute paths when they attach.
 190  3
         if ( attach && StringUtils.isEmpty( localRepoProperty ) )
 191  
         {
 192  0
             localRepoProperty = "${M2_REPO}";
 193  
         }
 194  
 
 195  3
         Set artifacts = getResolvedDependencies( true );
 196  
 
 197  3
         if ( artifacts == null || artifacts.isEmpty() )
 198  
         {
 199  0
             getLog().info( "No dependencies found." );
 200  
         }
 201  
 
 202  3
         List artList = new ArrayList( artifacts );
 203  
 
 204  3
         StringBuffer sb = new StringBuffer();
 205  3
         Iterator i = artList.iterator();
 206  
 
 207  3
         if ( i.hasNext() )
 208  
         {
 209  3
             appendArtifactPath( (Artifact) i.next(), sb );
 210  
 
 211  21
             while ( i.hasNext() )
 212  
             {
 213  18
                 sb.append( isPathSepSet ? this.pathSeparator : File.pathSeparator );
 214  18
                 appendArtifactPath( (Artifact) i.next(), sb );
 215  
             }
 216  
         }
 217  
 
 218  3
         String cpString = sb.toString();
 219  
 
 220  
         // if file separator is set, I need to replace the default one from all
 221  
         // the file paths that were pulled from the artifacts
 222  3
         if ( isFileSepSet )
 223  
         {
 224  1
             String separator = File.separator;
 225  
 
 226  
             // if the file sep is "\" then I need to escape it for the regex
 227  1
             if ( File.separator.equals( "\\" ) )
 228  
             {
 229  1
                 separator = "\\\\";
 230  
             }
 231  
 
 232  1
             cpString = cpString.replaceAll( separator, fileSeparator );
 233  
         }
 234  
 
 235  
         //make the string valid for filtering
 236  3
         if (outputFilterFile)
 237  
         {
 238  0
             cpString = "classpath="+ cpString;
 239  
         }
 240  
         
 241  3
         if ( outputFile == null )
 242  
         {
 243  1
             getLog().info( "Dependencies classpath:\n" + cpString );
 244  
         }
 245  
         else
 246  
         {
 247  2
             if ( regenerateFile || !isUpdToDate( cpString ) )
 248  
             {
 249  2
                 storeClasspathFile( cpString, outputFile );
 250  
             }
 251  
             else
 252  
             {
 253  0
                 this.getLog().info( "Skipped writing classpath file '" + outputFile + "'.  No changes found." );
 254  
             }
 255  
         }
 256  3
         if ( attach )
 257  
         {
 258  0
             attachFile( cpString );
 259  
         }
 260  3
     }
 261  
 
 262  
     protected void attachFile( String cpString )
 263  
         throws MojoExecutionException
 264  
     {
 265  0
         File attachedFile = new File( project.getBuild().getDirectory(), "classpath" );
 266  0
         storeClasspathFile( cpString, attachedFile );
 267  
 
 268  0
         projectHelper.attachArtifact( project, attachedFile, "classpath" );
 269  0
     }
 270  
 
 271  
     /**
 272  
      * Appends the artifact path into the specified stringBuffer.
 273  
      * 
 274  
      * @param art
 275  
      * @param sb
 276  
      */
 277  
     protected void appendArtifactPath( Artifact art, StringBuffer sb )
 278  
     {
 279  26
         if ( prefix == null )
 280  
         {
 281  24
             String file = art.getFile().getPath();
 282  
             // substitute the property for the local repo path to make the classpath file portable.
 283  24
             if ( StringUtils.isNotEmpty( localRepoProperty ) )
 284  
             {
 285  2
                 file = StringUtils.replace( file, local.getBasedir(), localRepoProperty );
 286  
             }
 287  24
             sb.append( file );
 288  24
         }
 289  
         else
 290  
         {
 291  
             // TODO: add param for prepending groupId and version.
 292  2
             sb.append( prefix );
 293  2
             sb.append( File.separator );
 294  2
             sb.append( DependencyUtil.getFormattedFileName( art, this.stripVersion ) );
 295  
         }
 296  26
     }
 297  
 
 298  
     /**
 299  
      * Checks that new classpath differs from that found inside the old classpathFile.
 300  
      * 
 301  
      * @param cpString
 302  
      * @return true if the specified classpath equals to that found inside the file, false otherwise (including when
 303  
      *         file does not exists but new classpath does).
 304  
      */
 305  
     private boolean isUpdToDate( String cpString )
 306  
     {
 307  
         try
 308  
         {
 309  2
             String oldCp = readClasspathFile();
 310  2
             return ( cpString == oldCp || ( cpString != null && cpString.equals( oldCp ) ) );
 311  
         }
 312  0
         catch ( Exception ex )
 313  
         {
 314  0
             this.getLog().warn( "Error while reading old classpath file '" + outputFile + "' for up-to-date check: " + ex );
 315  
 
 316  0
             return false;
 317  
         }
 318  
     }
 319  
 
 320  
     /**
 321  
      * It stores the specified string into that file.
 322  
      * 
 323  
      * @param cpString the string to be written into the file.
 324  
      * @throws MojoExecutionException
 325  
      */
 326  
     private void storeClasspathFile( String cpString, File out )
 327  
         throws MojoExecutionException
 328  
     {
 329  
         
 330  
         //make sure the parent path exists.
 331  2
         out.getParentFile().mkdirs();
 332  
         
 333  
         try
 334  
         {
 335  
            
 336  
             
 337  2
             Writer w = new BufferedWriter( new FileWriter( out ) );
 338  
 
 339  
             try
 340  
             {
 341  2
                 w.write( cpString );
 342  
 
 343  2
                 getLog().info( "Wrote classpath file '" + out + "'." );
 344  
             }
 345  0
             catch ( IOException ex )
 346  
             {
 347  0
                 throw new MojoExecutionException( "Error while writting to classpath file '" + out + "': " +
 348  
                     ex.toString(), ex );
 349  
             }
 350  
             finally
 351  
             {
 352  2
                 w.close();
 353  2
             }
 354  
         }
 355  0
         catch ( IOException ex )
 356  
         {
 357  0
             throw new MojoExecutionException( "Error while opening/closing classpath file '" + out + "': " +
 358  
                 ex.toString(), ex );
 359  2
         }
 360  2
     }
 361  
 
 362  
     /**
 363  
      * Reads into a string the file specified by the mojo param 'outputFile'. Assumes, the instance variable 'outputFile' is not
 364  
      * null.
 365  
      * 
 366  
      * @return the string contained in the classpathFile, if exists, or null ortherwise.
 367  
      * @throws MojoExecutionException
 368  
      */
 369  
     protected String readClasspathFile()
 370  
         throws IOException
 371  
     {
 372  5
         if ( outputFile == null )
 373  
         {
 374  1
             throw new IllegalArgumentException(
 375  
                                                 "The outputFile parameter cannot be null if the file is intended to be read." );
 376  
         }
 377  
 
 378  4
         if ( !outputFile.isFile() )
 379  
         {
 380  1
             return null;
 381  
         }
 382  3
         StringBuffer sb = new StringBuffer();
 383  3
         BufferedReader r = new BufferedReader( new FileReader( outputFile ) );
 384  
 
 385  
         try
 386  
         {
 387  
             String l;
 388  6
             while ( ( l = r.readLine() ) != null )
 389  
             {
 390  3
                 sb.append( l );
 391  
             }
 392  
 
 393  3
             return sb.toString();
 394  
         }
 395  
         finally
 396  
         {
 397  3
             r.close();
 398  
         }
 399  
     }
 400  
 
 401  
     /**
 402  
      * Compares artifacts lexicographically, using pattern [group_id][artifact_id][version].
 403  
      * 
 404  
      * @param arg1 first object
 405  
      * @param arg2 second object
 406  
      * @return the value <code>0</code> if the argument string is equal to this string; a value less than
 407  
      *         <code>0</code> if this string is lexicographically less than the string argument; and a value greater
 408  
      *         than <code>0</code> if this string is lexicographically greater than the string argument.
 409  
      */
 410  
     public int compare( Object arg1, Object arg2 )
 411  
     {
 412  0
         if ( arg1 instanceof Artifact && arg2 instanceof Artifact )
 413  
         {
 414  0
             if ( arg1 == arg2 )
 415  
             {
 416  0
                 return 0;
 417  
             }
 418  0
             else if ( arg1 == null )
 419  
             {
 420  0
                 return -1;
 421  
             }
 422  0
             else if ( arg2 == null )
 423  
             {
 424  0
                 return +1;
 425  
             }
 426  
 
 427  0
             Artifact art1 = (Artifact) arg1;
 428  0
             Artifact art2 = (Artifact) arg2;
 429  
 
 430  0
             String s1 = art1.getGroupId() + art1.getArtifactId() + art1.getVersion();
 431  0
             String s2 = art2.getGroupId() + art2.getArtifactId() + art2.getVersion();
 432  
 
 433  0
             return s1.compareTo( s2 );
 434  
         }
 435  
         else
 436  
         {
 437  0
             return 0;
 438  
         }
 439  
     }
 440  
 
 441  
     protected ArtifactsFilter getMarkedArtifactFilter()
 442  
     {
 443  3
         return null;
 444  
     }
 445  
 
 446  
     /**
 447  
      * @return the outputFile
 448  
      */
 449  
     public File getCpFile()
 450  
     {
 451  0
         return this.outputFile;
 452  
     }
 453  
 
 454  
     /**
 455  
      * @param theCpFile the outputFile to set
 456  
      */
 457  
     public void setCpFile( File theCpFile )
 458  
     {
 459  1
         this.outputFile = theCpFile;
 460  1
     }
 461  
 
 462  
     /**
 463  
      * @return the fileSeparator
 464  
      */
 465  
     public String getFileSeparator()
 466  
     {
 467  0
         return this.fileSeparator;
 468  
     }
 469  
 
 470  
     /**
 471  
      * @param theFileSeparator the fileSeparator to set
 472  
      */
 473  
     public void setFileSeparator( String theFileSeparator )
 474  
     {
 475  1
         this.fileSeparator = theFileSeparator;
 476  1
     }
 477  
 
 478  
     /**
 479  
      * @return the pathSeparator
 480  
      */
 481  
     public String getPathSeparator()
 482  
     {
 483  0
         return this.pathSeparator;
 484  
     }
 485  
 
 486  
     /**
 487  
      * @param thePathSeparator the pathSeparator to set
 488  
      */
 489  
     public void setPathSeparator( String thePathSeparator )
 490  
     {
 491  1
         this.pathSeparator = thePathSeparator;
 492  1
     }
 493  
 
 494  
     /**
 495  
      * @return the prefix
 496  
      */
 497  
     public String getPrefix()
 498  
     {
 499  0
         return this.prefix;
 500  
     }
 501  
 
 502  
     /**
 503  
      * @param thePrefix the prefix to set
 504  
      */
 505  
     public void setPrefix( String thePrefix )
 506  
     {
 507  3
         this.prefix = thePrefix;
 508  3
     }
 509  
 
 510  
     /**
 511  
      * @return the regenerateFile
 512  
      */
 513  
     public boolean isRegenerateFile()
 514  
     {
 515  0
         return this.regenerateFile;
 516  
     }
 517  
 
 518  
     /**
 519  
      * @param theRegenerateFile the regenerateFile to set
 520  
      */
 521  
     public void setRegenerateFile( boolean theRegenerateFile )
 522  
     {
 523  0
         this.regenerateFile = theRegenerateFile;
 524  0
     }
 525  
 
 526  
     /**
 527  
      * @return the stripVersion
 528  
      */
 529  
     public boolean isStripVersion()
 530  
     {
 531  0
         return this.stripVersion;
 532  
     }
 533  
 
 534  
     /**
 535  
      * @param theStripVersion the stripVersion to set
 536  
      */
 537  
     public void setStripVersion( boolean theStripVersion )
 538  
     {
 539  2
         this.stripVersion = theStripVersion;
 540  2
     }
 541  
 
 542  
     public String getLocalRepoProperty()
 543  
     {
 544  0
         return localRepoProperty;
 545  
     }
 546  
 
 547  
     public void setLocalRepoProperty( String localRepoProperty )
 548  
     {
 549  3
         this.localRepoProperty = localRepoProperty;
 550  3
     }
 551  
 
 552  
     public boolean isFileSepSet()
 553  
     {
 554  0
         return isFileSepSet;
 555  
     }
 556  
 
 557  
     public void setFileSepSet( boolean isFileSepSet )
 558  
     {
 559  0
         this.isFileSepSet = isFileSepSet;
 560  0
     }
 561  
 
 562  
     public boolean isPathSepSet()
 563  
     {
 564  0
         return isPathSepSet;
 565  
     }
 566  
 
 567  
     public void setPathSepSet( boolean isPathSepSet )
 568  
     {
 569  0
         this.isPathSepSet = isPathSepSet;
 570  0
     }
 571  
 }