1 package net.sf.statscm;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
45
46
47
48
49 public class StatScmMojo extends AbstractMavenReport
50 {
51
52
53
54
55
56
57
58
59
60 private MavenProject project;
61
62
63
64
65
66
67
68
69
70
71
72
73 private String[] includes;
74
75
76
77
78
79
80
81
82
83
84
85
86 private String[] excludes;
87
88
89
90
91
92
93
94
95
96
97 private String[] nonDeveloperLogins;
98
99
100
101
102
103
104
105
106 private String cacheDir;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 private String notesFile;
130
131
132
133
134
135
136
137 private String configFile = "src/site/stat-scm.properties";
138
139
140
141
142
143
144
145 private boolean skip;
146
147
148
149
150
151
152
153
154 private String title;
155
156
157
158
159 private StatConf statConf = new StatConf();
160
161
162
163
164
165 public void execute()
166 {
167 getLog().error( "StatSCM can not be run directly!" );
168 getLog().info( "Configure it to run with the \"mvn site\" command." );
169 getLog().info( "See: http://sourceforge.net/tracker/index.php?func=detail&aid=1610964&group_id=182522&atid=901553." );
170 }
171
172
173
174
175
176
177
178
179 public void executeReport( Locale locale ) throws MavenReportException
180 {
181 if (skip)
182 {
183 getLog().info( getMessage("info.greeting.skip") );
184 }
185 else
186 {
187
188 getLog().info( getMessage("info.greeting.ok") );
189
190
191 try
192 {
193 getLog().info( "StatSCM Version:" + getStatSCMVersion() );
194 getLog().info( "Configuring StatXXX" );
195 StatConf.setConfigFile(configFile);
196 statConf.configure( project, locale );
197 configFromMojoProperties();
198 getLog().info( "SCM Connection Type :" + statConf.getConnectionType() );
199 getLog().info( "Output Directory :" + this.getOutputDirectory() );
200 }
201 catch ( ConfigurationException e )
202 {
203 getLog().error( getMessage( "error.config" ), e );
204 return;
205 }
206
207
208 SrcManager scm = new SrcManager();
209 if ( !scm.log( statConf.getBaseDirectory(), getLog(), statConf ) )
210 {
211 getLog().error( getMessage( "error.scmlog.file_missing" ) );
212 return;
213 }
214
215
216 if ( !createOutputDirectory() )
217 {
218 getLog().error( getMessage( "error.ouput.can_not_create_output_folder" ) );
219 return;
220 }
221
222
223 try
224 {
225 if ( statConf.isStatSVN() || statConf.isStatCVS() )
226 {
227 if ( statConf.isStatSVN() )
228 {
229 doSvnStats();
230 }
231 else if ( statConf.isStatCVS() )
232 {
233 doCvsStats();
234 }
235 doGenerateReport( getSink() );
236 copyResourceFiles( getOutputDirectory(), getReportingTargetDirectory() );
237 }
238 else
239 {
240 getLog().error( getMessage( "warn.scm.type_xxx" ) );
241 }
242 }
243 catch ( Exception e )
244 {
245 getLog().error( getMessage( "error.config" ), e );
246 }
247 }
248 }
249
250
251
252
253
254
255 private void doSvnStats() throws MavenReportException
256 {
257 Messages.setPrimaryResource( "net.sf.statsvn.statcvs" );
258 try
259 {
260 Messages.setPrimaryResource( "net.sf.statsvn.statcvs" );
261 new SvnCommandLineParser( new String[] { statConf.getSCMLogFileName(), "." } ).parse();
262 SvnStartupUtils.checkSvnVersionSufficient();
263 SvnStartupUtils.checkRepoRootAvailable();
264 net.sf.statsvn.Main.generateDefaultHTMLSuite();
265 }
266 catch ( LogSyntaxException e )
267 {
268 getLog().error( getMessage( "error.scmlog.parsing" ), e );
269 throw new MavenReportException( e.getMessage() );
270 }
271 catch ( IOException e )
272 {
273 getLog().error( "Error generating Subversion Stats.", e );
274 throw new MavenReportException( e.getMessage() );
275 }
276 catch ( ConfigurationException e )
277 {
278 getLog().error( getMessage( "error.config" ), e );
279 throw new MavenReportException( e.getMessage() );
280
281 }
282 catch ( SvnVersionMismatchException e )
283 {
284 getLog().error( e.getMessage(), e );
285 throw new MavenReportException( e.getMessage() );
286 }
287 catch ( NullPointerException e )
288 {
289 getLog().warn("Null Pointer: Sometimes happens when local files are not synced with the repository!");
290 getLog().error( e.getMessage(), e );
291
292 }
293 }
294
295
296
297
298
299
300 private void doCvsStats() throws MavenReportException
301 {
302
303 try
304 {
305 new CommandLineParser( new String[] { statConf.getSCMLogFileName(), "." } ).parse();
306 net.sf.statcvs.Main.generateDefaultHTMLSuite();
307 }
308 catch ( LogSyntaxException e )
309 {
310 getLog().error( getMessage( "error.scmlog.parsing" ), e );
311 throw new MavenReportException( e.getMessage() );
312 }
313 catch ( IOException e )
314 {
315 getLog().error( "Error generating Subversion Stats.", e );
316 throw new MavenReportException( e.getMessage() );
317 }
318 catch ( ConfigurationException e )
319 {
320 getLog().error( getMessage( "error.config" ), e );
321 throw new MavenReportException( e.getMessage() );
322 }
323 }
324
325
326
327
328
329
330 private boolean createOutputDirectory()
331 {
332 File outputDir = new File( getOutputDirectory() );
333 if ( outputDir.exists() )
334 {
335 if ( outputDir.isDirectory() )
336 {
337 return true;
338 }
339 else
340 {
341 getLog().error( getMessage( "error.outputDir.file_in_the_way" )
342 + outputDir.getAbsolutePath() );
343 return false;
344 }
345 }
346 else
347 {
348 if ( outputDir.mkdirs() )
349 {
350 return true;
351 }
352 else
353 {
354 getLog().error( "Can not make output directory at: " + outputDir.getAbsolutePath() );
355 return false;
356 }
357 }
358 }
359
360
361
362
363
364
365 private void configFromMojoProperties() throws ConfigurationException
366 {
367 configIncludeExclude();
368 configNonDeveloperLogins();
369 configCacheSettings();
370 configNotesFile();
371 configTitle();
372 }
373
374
375
376
377
378 private void configTitle()
379 {
380 if ( title != null )
381 {
382 String projectName = title.trim();
383 if ( projectName.length() > 0 )
384 {
385 statConf.setProjectName( projectName );
386 }
387 getLog().info( "Page title: " + statConf.getProjectName() );
388 }
389 }
390
391
392
393
394
395
396 private void configNotesFile() throws ConfigurationException
397 {
398 if ( notesFile != null )
399 {
400 String filename = notesFile.trim();
401 if ( filename.length() > 0 )
402 {
403 try
404 {
405 statConf.setNotesFile( filename );
406 getLog().info( "Notes file: " + filename );
407 }
408 catch ( ConfigurationException e )
409 {
410 getLog().info( "Notes file: " + filename );
411 throw e;
412
413
414 }
415 }
416 }
417 }
418
419
420
421
422
423
424 private void configCacheSettings() throws ConfigurationException
425 {
426 if ( cacheDir != null )
427 {
428 String dir = cacheDir.trim();
429 if ( dir.length() > 0 )
430 {
431 try
432 {
433 SvnConfigurationOptions.setCacheDir( dir );
434 getLog().info( "Cache directory: " + dir );
435 }
436 catch ( ConfigurationException e )
437 {
438 getLog().info( "Cache directory: " + dir );
439 throw e;
440
441 }
442 }
443 }
444 }
445
446
447
448
449
450 private void configIncludeExclude()
451 {
452 String patternList = buildIncludeExcludeString( includes );
453 if ( patternList.length() > 0 )
454 {
455 statConf.setIncludePattern( patternList );
456 getLog().info( "Includes: " + patternList );
457 }
458 else
459 {
460 getLog().info( "Include all" );
461 }
462
463 patternList = buildIncludeExcludeString( excludes );
464 if ( patternList.length() > 0 )
465 {
466 statConf.setExcludePattern( patternList );
467 getLog().info( "Excludes: " + patternList );
468 }
469 else
470 {
471 getLog().info( "Exclude none" );
472 }
473 }
474
475
476
477
478
479
480 protected String buildIncludeExcludeString( String[] list )
481 {
482 StringBuffer patternList;
483 patternList = new StringBuffer();
484 if ( list != null )
485 {
486 for ( int i = 0; i < list.length; i++ )
487 {
488 String include = list[i].trim();
489 if ( include.indexOf( ';' ) > 0 )
490 {
491 getLog().warn(
492 getMessage( "warn.config.include.exclude.delimiter.1" ) + " ':' "
493 + getMessage( "warn.config.include.exclude.delimiter.2" ) + include );
494 }
495 if ( include.indexOf( ':' ) > 0 )
496 {
497 getLog().warn(
498 getMessage( "warn.config.include.exclude.delimiter.1" ) + " ';' "
499 + getMessage( "warn.config.include.exclude.delimiter.2" ) + include );
500 }
501 if ( include.length() > 0 )
502 {
503 if ( patternList.length() > 0 )
504 {
505 patternList.append( ';' );
506 }
507 patternList.append( list[i] );
508 }
509 }
510 }
511 return patternList.toString();
512 }
513
514
515
516
517 private void configNonDeveloperLogins()
518 {
519 if ( nonDeveloperLogins != null )
520 {
521 for ( int i = 0; i < nonDeveloperLogins.length; i++ )
522 {
523 String login = nonDeveloperLogins[i].trim();
524 if ( login.length() > 0 )
525 {
526 statConf.addNonDeveloperLogin( login );
527 getLog().info( "Non-developer login: " + login );
528 }
529 }
530 }
531 }
532
533
534
535
536
537
538 protected Renderer getSiteRenderer()
539 {
540 return null;
541 }
542
543
544
545
546
547
548 protected String getOutputDirectory()
549 {
550 return StatConf.getOutputDir();
551 }
552
553
554
555
556
557
558 protected String getReportingTargetDirectory()
559 {
560 String targetBaseDirectory = null;
561 Reporting reporting = getProject().getReporting();
562 if ( reporting != null)
563 {
564 targetBaseDirectory = reporting.getOutputDirectory();
565 }
566 if ( targetBaseDirectory == null)
567 {
568 targetBaseDirectory = statConf.getBaseDirectory().getAbsolutePath()
569 + statConf.FILE_SEPARATOR + "target"
570 + statConf.FILE_SEPARATOR + "site";
571 }
572 return targetBaseDirectory + statConf.FILE_SEPARATOR + StatConf.STATSCM_DIR_NAME;
573 }
574
575
576
577
578
579
580 public String getOutputName()
581 {
582 return StatConf.STATSCM_DIR_NAME + "/statscm";
583 }
584
585
586
587
588
589
590
591
592 public String getName( Locale locale )
593 {
594 return "StatSCM";
595 }
596
597
598
599
600
601
602
603 public String getDescription( Locale loc )
604 {
605 return getMessage( "statscm.description" );
606 }
607
608
609
610
611
612
613
614
615
616 private void copyResourceFiles( String src, String dest )
617 {
618 getLog().info("Copying resources from " + src + " to " + dest);
619
620 File srcDir = new File( src );
621 if ( !srcDir.isDirectory() )
622 {
623 getLog().error( "Can not copy reources src is not a directory: " + srcDir.getAbsolutePath() );
624 return;
625 }
626 File destDir = new File( dest );
627 if ( !destDir.isDirectory() )
628 {
629 destDir.mkdirs();
630 }
631
632 String[] resoures = srcDir.list( new java.io.FilenameFilter()
633 {
634 public boolean accept( File dir, String name )
635 {
636 String[] extensions = { ".png", ".jar", ".txt" };
637 String fileName = name.toLowerCase( Locale.getDefault() );
638 for ( int i = 0; i < extensions.length; i++ )
639 {
640 if ( fileName.endsWith( extensions[i] ) )
641 {
642 return true;
643 }
644 }
645 return false;
646
647 }
648 } );
649
650 for ( int i = 0; i < resoures.length; i++ )
651 {
652 FileInputStream fis = null;
653 FileOutputStream fos = null;
654 try
655 {
656 fis = new FileInputStream( new File( src + statConf.FILE_SEPARATOR + resoures[i] ) );
657 fos = new FileOutputStream( new File( dest + statConf.FILE_SEPARATOR + resoures[i] ) );
658 int b = -1;
659 while ( ( b = fis.read() ) != -1 )
660 {
661 fos.write( b );
662 }
663
664 fis.close();
665 fos.close();
666 }
667 catch ( FileNotFoundException e )
668 {
669 getLog().error( "Can not find file " + resoures[i], e );
670 }
671 catch ( IOException e )
672 {
673 getLog().error( "Error copying file: " + src + "/" + resoures[i], e );
674 }
675 finally
676 {
677 try
678 {
679 if ( fis != null )
680 {
681 fis.close();
682 }
683 if ( fos != null )
684 {
685 fos.close();
686 }
687 }
688 catch ( IOException e )
689 {
690 getLog().error( "I/O Exception copying resources.", e );
691 }
692 finally
693 {
694 fis = null;
695 fos = null;
696 }
697 }
698 if ( getLog().isDebugEnabled() )
699 {
700 getLog().debug(
701 "Copied file " + src + statConf.FILE_SEPARATOR + resoures[i] + " to " + dest
702 + statConf.FILE_SEPARATOR + resoures[i] );
703 }
704 }
705 }
706
707
708
709
710
711
712
713 private void doGenerateReport( Sink sink )
714 {
715
716
717 if ( sink == null )
718 {
719 return;
720 }
721
722 sink.head();
723 sink.title();
724 sink.text( "StatSCM" );
725 sink.title_();
726 sink.head_();
727
728 sink.body();
729 sink.section1();
730
731 sink.sectionTitle1();
732 sink.text( getDescription( Locale.getDefault() ) );
733 sink.sectionTitle1_();
734
735 sink.bold();
736 sink.link( "index.html" );
737 sink.text( "Main page" );
738 sink.link_();
739 sink.bold_();
740
741 sink.lineBreak();
742
743
744
745 sink.link( "index.html" );
746 sink.figure();
747 sink.figureGraphics( "loc.png" );
748 sink.figure_();
749 sink.link_();
750 sink.lineBreak();
751
752 sink.text( "Generated using " );
753 sink.link( "http://stat-scm.sourceforge.net/" );
754 sink.text( "StatSCM" + getStatSCMVersion() );
755 sink.link_();
756 sink.text( "." );
757
758 sink.flush();
759 sink.close();
760 }
761
762
763
764
765
766
767
768 private String getStatSCMVersion() {
769 String versionText = getMessage("statscm.version");
770 if (versionText == null) {
771 return "";
772 } else if (versionText.equals("${pom.version}")) {
773 return "";
774 }
775
776 return " (" + versionText +")";
777 }
778
779
780
781
782
783
784 protected MavenProject getProject()
785 {
786 return project;
787 }
788
789
790
791
792
793
794 public void setProject( MavenProject project )
795 {
796 this.project = project;
797 }
798
799 public String getMessage(String messageKey) {
800 return ResourceBundle.getBundle( "net.sf.statscm.message", statConf.getLocale() ).getString( messageKey );
801 }
802
803 void setSkipParameter( boolean b )
804 {
805 skip = b;
806 }
807
808 public StatConf getStatConf() {
809 return statConf;
810 }
811
812 public void setConfigFileParameter(String configFile) throws ConfigurationException {
813 if (configFile != null) {
814 this.configFile = configFile;
815 }
816 }
817 }