Coverage Report - net.sf.statscm.StatScmMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
StatScmMojo
49%
121/246
51%
41/80
3.714
StatScmMojo$1
100%
7/7
100%
4/4
3.714
 
 1  
 package net.sf.statscm;
 2  
 
 3  
 /*
 4  
  * Copyright 2006 Doug Culnane
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import net.sf.statsvn.util.SvnStartupUtils;
 20  
 import net.sf.statsvn.util.SvnVersionMismatchException;
 21  
 import net.sf.statcvs.Messages;
 22  
 import net.sf.statcvs.input.LogSyntaxException;
 23  
 import net.sf.statcvs.output.CommandLineParser;
 24  
 import net.sf.statsvn.output.SvnCommandLineParser;
 25  
 import net.sf.statsvn.output.SvnConfigurationOptions;
 26  
 import net.sf.statcvs.output.ConfigurationException;
 27  
 import org.apache.maven.doxia.sink.Sink;
 28  
 import org.apache.maven.doxia.siterenderer.Renderer;
 29  
 import org.apache.maven.reporting.AbstractMavenReport;
 30  
 import org.apache.maven.reporting.MavenReportException;
 31  
 
 32  
 import java.io.File;
 33  
 import java.io.FileInputStream;
 34  
 import java.io.FileNotFoundException;
 35  
 import java.io.FileOutputStream;
 36  
 import java.io.IOException;
 37  
 import java.util.Locale;
 38  
 import java.util.ResourceBundle;
 39  
 
 40  
 import org.apache.maven.model.Reporting;
 41  
 import org.apache.maven.project.MavenProject;
 42  
 
 43  
 /**
 44  
  * Generate a Source Code Management Metrics Report.
 45  
  * 
 46  
  * @goal stats
 47  
  * @phase site
 48  
  */
 49  27
 public class StatScmMojo extends AbstractMavenReport
 50  
 {
 51  
 
 52  
     /**
 53  
      * Maven Project. This represents the POM where StatSCM gets most of its configuration from. This object is provided
 54  
      * by Maven.
 55  
      * 
 56  
      * @parameter expression="${project}"
 57  
      * @required
 58  
      * @readonly
 59  
      */
 60  
     private MavenProject project;
 61  
 
 62  
     /**
 63  
      * Each <include> tag inside here gives one Ant-style wildcard pattern indicating what to include. Example:
 64  
      * "src / ** / *.java" matches all java files in the src directory or its subdirectories. Note that "*.java "only
 65  
      * matches java files in the root directory, because '*' does not match subdirectories. (Quotes not needed.)<br/>
 66  
      * <br/>
 67  
      * If not specified, all files will be included.<br/>
 68  
      * <br/>
 69  
      * First we add in all files or all these files and then we subtract all the excluded files.
 70  
      * 
 71  
      * @parameter
 72  
      */
 73  
     private String[] includes;
 74  
 
 75  
     /**
 76  
      * Each &lt;exclude&gt; tag inside here gives one Ant-style wildcard pattern indicating what to exclude. Example:
 77  
      * "** /test/*.java" matches all java files in with a 'test' folder somewhere in the path. Note that "*.java" only
 78  
      * matches java files in the root directory, because '*' does not match subdirectories. (Quotes not needed.)<br/>
 79  
      * <br/>
 80  
      * If not specified, no files will be excluded.<br/>
 81  
      * <br/>
 82  
      * First we add in all files or all these files and then we subtract all the excluded files.
 83  
      * 
 84  
      * @parameter
 85  
      */
 86  
     private String[] excludes;
 87  
 
 88  
     /**
 89  
      * Each &lt;nonDeveloperLogin&gt; tag in inside here gives one scm login account name. Each account name given here
 90  
      * will be excluded from all developer reports. This is useful to reduce noise from administrative and other
 91  
      * non-developer accounts. <br/>
 92  
      * <br/>
 93  
      * Multiple accounts can be excluded by adding a tag for each such account.
 94  
      * 
 95  
      * @parameter
 96  
      */
 97  
     private String[] nonDeveloperLogins;
 98  
 
 99  
     /**
 100  
      * Specify a cache directory for information retrieved from the Subversion server (e.g. line counts). The data will
 101  
      * be saved in this directory. The directory will be created if it doesn't exist. By default, the current user
 102  
      * directory is used. This is only relevant when the SCM is subversion and is ignored if it is CVS.
 103  
      * 
 104  
      * @parameter
 105  
      */
 106  
     private String cacheDir;
 107  
 
 108  
     /**
 109  
      * The contents of the specified file will be included at the top of the report's index page. The file should
 110  
      * contain a valid block-level HTML fragment, for example: <br/>
 111  
      * 
 112  
      * <pre>
 113  
      * &lt;p&gt;
 114  
      *     These are development statistics for the
 115  
      *     &lt;a href=&quot;http://www.statsvn.org&quot;&gt;StatSVN&lt;/a&gt;
 116  
      *     project, created by StatSVN itself.
 117  
      * &lt;/p&gt;
 118  
      * &lt;p&gt;
 119  
      *     &lt;strong&gt;Note:&lt;/strong&gt;
 120  
      *     This report was generated by an unreleased
 121  
      *     development version of StatSVN. It might
 122  
      *     contain features not yet found in the
 123  
      *     official release.
 124  
      * &lt;/p&gt;
 125  
      * </pre>
 126  
      * 
 127  
      * 
 128  
      */
 129  
     private String notesFile;
 130  
     
 131  
     /**
 132  
      * The config file allows you to set some user or chart configurations.
 133  
      * 
 134  
      * @see http://statcvs.sourceforge.net/manual.html#section_config
 135  
      * @parameter
 136  
      */
 137  27
            private String configFile = "src/site/stat-scm.properties";
 138  
     
 139  
         /**
 140  
      * Set this true to avoid running the stat-scm report in this project. Useful in child projects where the parent pom 
 141  
      * project specifies the stat-scm report.
 142  
      * 
 143  
      * @parameter expression="false"
 144  
      */
 145  
     private boolean skip;
 146  
 
 147  
     /**
 148  
      * Specifies a display title to be used in the reports. The setting in &lt;project&gt;&lt;name&gt; is used if no
 149  
      * title is specified here and the name of the Subversion module will be used as default if no title is otherwise
 150  
      * specified.
 151  
      * 
 152  
      * @parameter
 153  
      */
 154  
     private String title;
 155  
 
 156  
     /**
 157  
      * Configuration for this instance.
 158  
      */
 159  27
     private StatConf statConf = new StatConf();
 160  
     
 161  
     /**
 162  
      * For running directly.
 163  
      * @todo This direct call should generate HTML reports by changing the output from Xdoc to html and the outputDir.
 164  
      */
 165  
     public void execute()
 166  
     {
 167  3
         getLog().error( "StatSCM can not be run directly!" );
 168  3
         getLog().info( "Configure it to run with the \"mvn site\" command." );
 169  3
         getLog().info( "See: http://sourceforge.net/tracker/index.php?func=detail&aid=1610964&group_id=182522&atid=901553." );
 170  3
     }
 171  
 
 172  
     /**
 173  
      * Main mojo execution method called by plugin environment.
 174  
      * 
 175  
      * @param locale Locale for 118n.
 176  
      * @throws MavenReportException
 177  
      *             Throws an error if any failure.
 178  
      */
 179  
     public void executeReport( Locale locale ) throws MavenReportException
 180  
     {
 181  6
         if (skip) 
 182  
         {
 183  3
             getLog().info( getMessage("info.greeting.skip") );
 184  
         }
 185  
         else
 186  
         {
 187  
             // Start
 188  3
             getLog().info( getMessage("info.greeting.ok") );
 189  
             
 190  
             // Configure
 191  
             try
 192  
             {
 193  3
                 getLog().info( "StatSCM Version:" + getStatSCMVersion() );
 194  3
                 getLog().info( "Configuring StatXXX" );
 195  3
                 StatConf.setConfigFile(configFile);
 196  3
                 statConf.configure( project, locale );
 197  3
                 configFromMojoProperties();
 198  3
                 getLog().info( "SCM Connection Type :" + statConf.getConnectionType() );
 199  3
                 getLog().info( "Output Directory    :" + this.getOutputDirectory() );
 200  
             }
 201  0
             catch ( ConfigurationException e )
 202  
             {
 203  0
                 getLog().error( getMessage( "error.config" ), e );
 204  0
                 return;
 205  3
             }
 206  
     
 207  
             // Get the Log file
 208  3
             SrcManager scm = new SrcManager();
 209  3
             if ( !scm.log( statConf.getBaseDirectory(), getLog(), statConf ) )
 210  
             {
 211  0
                 getLog().error( getMessage( "error.scmlog.file_missing" ) );
 212  0
                 return;
 213  
             }
 214  
     
 215  
             // Create Output dirs
 216  3
             if ( !createOutputDirectory() )
 217  
             {
 218  0
                 getLog().error( getMessage( "error.ouput.can_not_create_output_folder" )  );
 219  0
                 return;
 220  
             }
 221  
     
 222  
             // Perform report
 223  
             try
 224  
             {
 225  3
                 if ( statConf.isStatSVN() || statConf.isStatCVS() )
 226  
                 {
 227  3
                     if ( statConf.isStatSVN() )
 228  
                     {
 229  3
                         doSvnStats();
 230  
                     }
 231  0
                     else if ( statConf.isStatCVS() )
 232  
                     {
 233  0
                         doCvsStats();
 234  
                     }
 235  3
                     doGenerateReport( getSink() );
 236  3
                     copyResourceFiles( getOutputDirectory(), getReportingTargetDirectory() );
 237  
                 }
 238  
                 else
 239  
                 {
 240  0
                     getLog().error( getMessage( "warn.scm.type_xxx" ) );
 241  
                 }
 242  
             }
 243  0
             catch ( Exception e )
 244  
             {
 245  0
                 getLog().error( getMessage( "error.config" ), e );
 246  3
             }
 247  
         }        
 248  6
     }
 249  
 
 250  
     /**
 251  
      * Use StatSVN to generate xDoc output.
 252  
      * 
 253  
      * @throws MavenReportException if there is an error.
 254  
      */
 255  
     private void doSvnStats() throws MavenReportException
 256  
     {
 257  3
         Messages.setPrimaryResource( "net.sf.statsvn.statcvs" );
 258  
         try
 259  
         {
 260  3
             Messages.setPrimaryResource( "net.sf.statsvn.statcvs" );
 261  3
             new SvnCommandLineParser( new String[] { statConf.getSCMLogFileName(), "." } ).parse();
 262  3
             SvnStartupUtils.checkSvnVersionSufficient();
 263  3
             SvnStartupUtils.checkRepoRootAvailable();
 264  3
             net.sf.statsvn.Main.generateDefaultHTMLSuite();
 265  
         }
 266  0
         catch ( LogSyntaxException e )
 267  
         {
 268  0
             getLog().error( getMessage( "error.scmlog.parsing" ), e );
 269  0
             throw new MavenReportException( e.getMessage() );
 270  
         }
 271  0
         catch ( IOException e )
 272  
         {
 273  0
             getLog().error( "Error generating Subversion Stats.", e );
 274  0
             throw new MavenReportException( e.getMessage() );
 275  
         }
 276  0
         catch ( ConfigurationException e )
 277  
         {
 278  0
             getLog().error( getMessage( "error.config" ), e );
 279  0
             throw new MavenReportException( e.getMessage() );
 280  
 
 281  
         }
 282  0
         catch ( SvnVersionMismatchException e )
 283  
         {
 284  0
             getLog().error( e.getMessage(), e );
 285  0
             throw new MavenReportException( e.getMessage() );
 286  
         }
 287  0
         catch ( NullPointerException e )
 288  
         {
 289  0
                 getLog().warn("Null Pointer: Sometimes happens when local files are not synced with the repository!");
 290  0
             getLog().error( e.getMessage(), e );
 291  
             //throw new MavenReportException( e.getMessage() );
 292  3
         }
 293  3
     }
 294  
 
 295  
     /**
 296  
      * Use StatCVS to generate xDoc output.
 297  
      * 
 298  
      * @throws MavenReportException if there is an error.
 299  
      */
 300  
     private void doCvsStats() throws MavenReportException
 301  
     {
 302  
 
 303  
         try
 304  
         {
 305  0
             new CommandLineParser( new String[] { statConf.getSCMLogFileName(), "." } ).parse();
 306  0
             net.sf.statcvs.Main.generateDefaultHTMLSuite();
 307  
         }
 308  0
         catch ( LogSyntaxException e )
 309  
         {
 310  0
             getLog().error( getMessage( "error.scmlog.parsing" ), e );
 311  0
             throw new MavenReportException( e.getMessage() );
 312  
         }
 313  0
         catch ( IOException e )
 314  
         {
 315  0
             getLog().error( "Error generating Subversion Stats.", e );
 316  0
             throw new MavenReportException( e.getMessage() );
 317  
         }
 318  0
         catch ( ConfigurationException e )
 319  
         {
 320  0
             getLog().error( getMessage( "error.config" ), e );
 321  0
             throw new MavenReportException( e.getMessage() );
 322  0
         }
 323  0
     }
 324  
 
 325  
     /**
 326  
      * Create the output directory for generated xdoc output.
 327  
      * 
 328  
      * @return True if directory there or was sucessfully created.
 329  
      */
 330  
     private boolean createOutputDirectory()
 331  
     {
 332  3
         File outputDir = new File( getOutputDirectory() );
 333  3
         if ( outputDir.exists() )
 334  
         {
 335  3
             if ( outputDir.isDirectory() )
 336  
             {
 337  3
                 return true;
 338  
             }
 339  
             else
 340  
             {
 341  0
                 getLog().error( getMessage( "error.outputDir.file_in_the_way" )
 342  
                                                 + outputDir.getAbsolutePath() );
 343  0
                 return false;
 344  
             }
 345  
         }
 346  
         else
 347  
         {
 348  0
             if ( outputDir.mkdirs() )
 349  
             {
 350  0
                 return true;
 351  
             }
 352  
             else
 353  
             {
 354  0
                 getLog().error( "Can  not make output directory at: " + outputDir.getAbsolutePath() );
 355  0
                 return false;
 356  
             }
 357  
         }
 358  
     }
 359  
 
 360  
     /**
 361  
      * Use settings in the POM to configure some more things for STATSCM.
 362  
      * 
 363  
      * @throws ConfigurationException if any of the POM settings are invalid 
 364  
      */
 365  
     private void configFromMojoProperties() throws ConfigurationException
 366  
     {
 367  3
         configIncludeExclude();
 368  3
         configNonDeveloperLogins();
 369  3
         configCacheSettings();
 370  3
         configNotesFile();
 371  3
         configTitle();        
 372  3
     }
 373  
 
 374  
     /**
 375  
      * Use POM content to set the title appearing on the window. This takes precedence over the name of the POM project
 376  
      * name, which is the default title.
 377  
      */
 378  
     private void configTitle()
 379  
     {
 380  3
         if ( title != null )
 381  
         {
 382  0
             String projectName = title.trim();
 383  0
             if ( projectName.length() > 0 )
 384  
             {
 385  0
                 statConf.setProjectName( projectName );
 386  
             }
 387  0
             getLog().info( "Page title: " + statConf.getProjectName() );
 388  
         }
 389  3
     }
 390  
 
 391  
     /**
 392  
      * Use POM settings to configure a 'notes' file holding HTML to appear at the top of pages.
 393  
      * 
 394  
      * @throws ConfigurationException if the notes file can't be used
 395  
      */
 396  
     private void configNotesFile() throws ConfigurationException
 397  
     {
 398  3
         if ( notesFile != null )
 399  
         {
 400  0
             String filename = notesFile.trim();
 401  0
             if ( filename.length() > 0 )
 402  
             {
 403  
                 try
 404  
                 {
 405  0
                     statConf.setNotesFile( filename );
 406  0
                     getLog().info( "Notes file: " + filename );
 407  
                 }
 408  0
                 catch ( ConfigurationException e )
 409  
                 {
 410  0
                     getLog().info( "Notes file: " + filename );
 411  0
                     throw e;
 412  
                     // @todo: convert this to use message file
 413  
 //                    getLog().error( e.getMessage() );
 414  0
                 }
 415  
             }
 416  
         }
 417  3
     }
 418  
 
 419  
     /**
 420  
      * Use POM setting to configure where the cache file is stored.
 421  
      * 
 422  
      * @throws ConfigurationException if the cache folder cannot be used
 423  
      */
 424  
     private void configCacheSettings() throws ConfigurationException
 425  
     {
 426  3
         if ( cacheDir != null )
 427  
         {
 428  0
             String dir = cacheDir.trim();
 429  0
             if ( dir.length() > 0 )
 430  
             {
 431  
                 try
 432  
                 {
 433  0
                     SvnConfigurationOptions.setCacheDir( dir );
 434  0
                     getLog().info( "Cache directory: " + dir );
 435  
                 }
 436  0
                 catch ( ConfigurationException e )
 437  
                 {
 438  0
                     getLog().info( "Cache directory: " + dir );
 439  0
                     throw e;
 440  
 //                    getLog().error( getMessage( "error.config.bad_cache_dir" ) + dir );
 441  0
                 }
 442  
             }
 443  
         }
 444  3
     }
 445  
 
 446  
     /**
 447  
      * Use the parameters configured in the POM to set things up for the list of files that will be included or
 448  
      * excluded.
 449  
      */
 450  
     private void configIncludeExclude()
 451  
     {
 452  3
         String patternList = buildIncludeExcludeString( includes );
 453  3
         if ( patternList.length() > 0 )
 454  
         {
 455  0
             statConf.setIncludePattern( patternList );
 456  0
             getLog().info( "Includes: " + patternList );
 457  
         }
 458  
         else
 459  
         {
 460  3
             getLog().info( "Include all" );
 461  
         }
 462  
 
 463  3
         patternList = buildIncludeExcludeString( excludes );
 464  3
         if ( patternList.length() > 0 )
 465  
         {
 466  0
             statConf.setExcludePattern( patternList );
 467  0
             getLog().info( "Excludes: " + patternList );
 468  
         }
 469  
         else
 470  
         {
 471  3
             getLog().info( "Exclude none" );
 472  
         }
 473  3
     }
 474  
 
 475  
     /**
 476  
      * Convert an array of strings to a single semi-colon delimited string of the values. Blank values are discarded.
 477  
      * 
 478  
      * @return the delimited string or an empty string if there are no non-blank values.
 479  
      */
 480  
     protected String buildIncludeExcludeString( String[] list )
 481  
     {
 482  
         StringBuffer patternList;
 483  15
         patternList = new StringBuffer();
 484  15
         if ( list != null )
 485  
         {
 486  36
             for ( int i = 0; i < list.length; i++ )
 487  
             {
 488  27
                 String include = list[i].trim();
 489  27
                 if ( include.indexOf( ';' ) > 0 )
 490  
                 {
 491  3
                     getLog().warn(
 492  
                             getMessage( "warn.config.include.exclude.delimiter.1" ) + " ':' "
 493  
                                     + getMessage( "warn.config.include.exclude.delimiter.2" ) + include );
 494  
                 }
 495  27
                 if ( include.indexOf( ':' ) > 0 )
 496  
                 {
 497  3
                     getLog().warn(
 498  
                             getMessage( "warn.config.include.exclude.delimiter.1" ) + " ';' "
 499  
                                     + getMessage( "warn.config.include.exclude.delimiter.2" ) + include );
 500  
                 }
 501  27
                 if ( include.length() > 0 )
 502  
                 {
 503  27
                     if ( patternList.length() > 0 )
 504  
                     {
 505  18
                         patternList.append( ';' );
 506  
                     }
 507  27
                     patternList.append( list[i] );
 508  
                 }
 509  
             }
 510  
         }
 511  15
         return patternList.toString();
 512  
     }
 513  
 
 514  
     /**
 515  
      * Set the list of non-developers so these guys will be ignored in SCM info.
 516  
      */
 517  
     private void configNonDeveloperLogins()
 518  
     {
 519  3
         if ( nonDeveloperLogins != null )
 520  
         {
 521  0
             for ( int i = 0; i < nonDeveloperLogins.length; i++ )
 522  
             {
 523  0
                 String login = nonDeveloperLogins[i].trim();
 524  0
                 if ( login.length() > 0 )
 525  
                 {
 526  0
                     statConf.addNonDeveloperLogin( login );
 527  0
                     getLog().info( "Non-developer login: " + login );
 528  
                 }
 529  
             }
 530  
         }
 531  3
     }
 532  
 
 533  
     /**
 534  
      * Called my Maven Repoerint API.
 535  
      * 
 536  
      * @return Null becuase we handel the rendering ourselves.
 537  
      */
 538  
     protected Renderer getSiteRenderer()
 539  
     {
 540  0
         return null;
 541  
     }
 542  
 
 543  
     /**
 544  
      * String repesentation of the output generated XDOC Directory.
 545  
      * 
 546  
      * @return Absolute path to the generated XDOC Directory.
 547  
      */
 548  
     protected String getOutputDirectory()
 549  
     {
 550  9
         return StatConf.getOutputDir();
 551  
     }
 552  
 
 553  
     /**
 554  
      * Returns the StatSCM report target directory.
 555  
      * 
 556  
      * @return Absolute path to the directory with final HTML result.
 557  
      */
 558  
     protected String getReportingTargetDirectory()
 559  
     {
 560  9
         String targetBaseDirectory = null;
 561  9
         Reporting reporting = getProject().getReporting();
 562  9
         if ( reporting != null)
 563  
         {
 564  3
             targetBaseDirectory = reporting.getOutputDirectory();
 565  
         }
 566  9
         if ( targetBaseDirectory == null)
 567  
         {
 568  6
             targetBaseDirectory = statConf.getBaseDirectory().getAbsolutePath()
 569  
                             + statConf.FILE_SEPARATOR + "target"
 570  
                             + statConf.FILE_SEPARATOR + "site";
 571  
         }
 572  9
         return targetBaseDirectory + statConf.FILE_SEPARATOR + StatConf.STATSCM_DIR_NAME;
 573  
     }
 574  
 
 575  
     /**
 576  
      * String name of the html file that the Reporting Menu uses for a link.
 577  
      * 
 578  
      * @return Name of Html file to link to.
 579  
      */
 580  
     public String getOutputName()
 581  
     {
 582  0
         return StatConf.STATSCM_DIR_NAME + "/statscm";
 583  
     }
 584  
 
 585  
     /**
 586  
      * Menu Item name for Reporting API.
 587  
      * 
 588  
      * @param locale
 589  
      *            Locale for i18n.
 590  
      * @return link menu name.
 591  
      */
 592  
     public String getName( Locale locale )
 593  
     {
 594  0
         return "StatSCM";
 595  
     }
 596  
 
 597  
     /**
 598  
      * Description of Report for Reporting API.
 599  
      * 
 600  
      * @param loc Locale fro 118n.
 601  
      * @return i18n Description of Report.
 602  
      */
 603  
     public String getDescription( Locale loc )
 604  
     {
 605  0
         return getMessage( "statscm.description" );
 606  
     }
 607  
 
 608  
     /**
 609  
      * Utility method for copying resource files.
 610  
      * 
 611  
      * @param src
 612  
      *            Source Directory.
 613  
      * @param dest
 614  
      *            Target Directory.
 615  
      */
 616  
     private void copyResourceFiles( String src, String dest )
 617  
     {
 618  3
             getLog().info("Copying resources from " + src + " to " + dest);
 619  
             
 620  3
         File srcDir = new File( src );
 621  3
         if ( !srcDir.isDirectory() )
 622  
         {
 623  0
             getLog().error( "Can not copy reources src is not a directory: " + srcDir.getAbsolutePath() );
 624  0
             return;
 625  
         }
 626  3
         File destDir = new File( dest );
 627  3
         if ( !destDir.isDirectory() )
 628  
         {
 629  0
             destDir.mkdirs();
 630  
         }
 631  
 
 632  3
         String[] resoures = srcDir.list( new java.io.FilenameFilter()
 633  3
         {
 634  
             public boolean accept( File dir, String name )
 635  
             {
 636  306
                 String[] extensions = { ".png", ".jar", ".txt" };
 637  306
                 String fileName = name.toLowerCase( Locale.getDefault() );
 638  909
                 for ( int i = 0; i < extensions.length; i++ )
 639  
                 {
 640  711
                     if ( fileName.endsWith( extensions[i] ) )
 641  
                     {
 642  108
                         return true;
 643  
                     }
 644  
                 }
 645  198
                 return false;
 646  
 
 647  
             }
 648  
         } );
 649  
 
 650  111
         for ( int i = 0; i < resoures.length; i++ )
 651  
         {
 652  108
             FileInputStream fis = null;
 653  108
             FileOutputStream fos = null;
 654  
             try
 655  
             {
 656  108
                 fis = new FileInputStream( new File( src + statConf.FILE_SEPARATOR + resoures[i] ) );
 657  108
                 fos = new FileOutputStream( new File( dest + statConf.FILE_SEPARATOR + resoures[i] ) );
 658  108
                 int b = -1;
 659  1716327
                 while ( ( b = fis.read() ) != -1 )
 660  
                 {
 661  1716219
                     fos.write( b );
 662  
                 }
 663  
 
 664  108
                 fis.close();
 665  108
                 fos.close();
 666  
             }
 667  0
             catch ( FileNotFoundException e )
 668  
             {
 669  0
                 getLog().error( "Can not find file " + resoures[i], e );
 670  
             }
 671  0
             catch ( IOException e )
 672  
             {
 673  0
                 getLog().error( "Error copying file: " + src + "/" + resoures[i], e );
 674  
             }
 675  
             finally
 676  
             {
 677  0
                 try
 678  
                 {
 679  108
                     if ( fis != null )
 680  
                     {
 681  108
                         fis.close();
 682  
                     }
 683  108
                     if ( fos != null )
 684  
                     {
 685  108
                         fos.close();
 686  
                     }
 687  
                 }
 688  0
                 catch ( IOException e )
 689  
                 {
 690  0
                     getLog().error( "I/O Exception copying resources.", e );
 691  
                 }
 692  
                 finally
 693  
                 {
 694  108
                     fis = null;
 695  108
                     fos = null;
 696  108
                 }
 697  108
             }
 698  108
             if ( getLog().isDebugEnabled() )
 699  
             {
 700  0
                 getLog().debug(
 701  
                                 "Copied file " + src + statConf.FILE_SEPARATOR + resoures[i] + " to " + dest
 702  
                                                 + statConf.FILE_SEPARATOR + resoures[i] );
 703  
             }
 704  
         }
 705  3
     }
 706  
 
 707  
     /**
 708  
      * Create a structured StatSCM / StatSVN report front page.
 709  
      * 
 710  
      * @param sink
 711  
      *            used to write structured report to.
 712  
      */
 713  
     private void doGenerateReport( Sink sink )
 714  
     {
 715  
 
 716  
         // protect against direct runs.
 717  3
         if ( sink == null )
 718  
         {
 719  3
             return;
 720  
         }
 721  
         
 722  0
         sink.head();
 723  0
         sink.title();
 724  0
         sink.text( "StatSCM" );
 725  0
         sink.title_();
 726  0
         sink.head_();
 727  
 
 728  0
         sink.body();
 729  0
         sink.section1();
 730  
 
 731  0
         sink.sectionTitle1();
 732  0
         sink.text( getDescription( Locale.getDefault() ) );
 733  0
         sink.sectionTitle1_();
 734  
 
 735  0
         sink.bold();
 736  0
         sink.link( "index.html" );
 737  0
         sink.text( "Main page" );
 738  0
         sink.link_();
 739  0
         sink.bold_();
 740  
         // sink.link_();
 741  0
         sink.lineBreak();
 742  
 
 743  
         // TODO Think about adding first page links this back in once the StatSVN and StatCVS output stableises.
 744  
 
 745  0
         sink.link( "index.html" );
 746  0
         sink.figure();
 747  0
         sink.figureGraphics( "loc.png" );
 748  0
         sink.figure_();
 749  0
         sink.link_();
 750  0
         sink.lineBreak();
 751  
 
 752  0
         sink.text( "Generated using " );
 753  0
         sink.link( "http://stat-scm.sourceforge.net/" );
 754  0
         sink.text( "StatSCM" + getStatSCMVersion() );
 755  0
         sink.link_();
 756  0
         sink.text( "." );
 757  
 
 758  0
         sink.flush();
 759  0
         sink.close();
 760  0
     }
 761  
 
 762  
     /**
 763  
      * Get the version of StatSCM.  This uses the filtered resource so that 
 764  
      * Maven automatically sets this at build time.
 765  
      *
 766  
      * @return The pom.version or an empty string if this fails.
 767  
      */
 768  
     private String getStatSCMVersion() {
 769  3
         String versionText = getMessage("statscm.version");
 770  3
         if (versionText == null) {
 771  0
             return "";
 772  3
         } else if (versionText.equals("${pom.version}")) {
 773  0
             return "";
 774  
         }
 775  
         
 776  3
         return " (" + versionText +")";
 777  
     }
 778  
 
 779  
     /**
 780  
      * Access to the Maven Project representation for Reporting API.
 781  
      * 
 782  
      * @return MavenProject.
 783  
      */
 784  
     protected MavenProject getProject()
 785  
     {
 786  9
         return project;
 787  
     }
 788  
 
 789  
     /**
 790  
      * Setter to allow unit tests to set up Mojo.
 791  
      * 
 792  
      * @param project Maven Project
 793  
      */
 794  
     public void setProject( MavenProject project )
 795  
     {
 796  12
         this.project = project;
 797  12
     }
 798  
     
 799  
     public String getMessage(String messageKey) {
 800  39
         return ResourceBundle.getBundle( "net.sf.statscm.message", statConf.getLocale() ).getString( messageKey );
 801  
     }
 802  
 
 803  
     void setSkipParameter( boolean b )
 804  
     {
 805  3
         skip = b;
 806  3
     }
 807  
 
 808  
         public StatConf getStatConf() {
 809  27
                 return statConf;
 810  
         }
 811  
 
 812  
         public void setConfigFileParameter(String configFile) throws ConfigurationException {
 813  0
                 if (configFile != null) {
 814  0
                         this.configFile = configFile;
 815  
                 }
 816  0
         }
 817  
 }