View Javadoc

1   /*
2    StatCvs - CVS statistics generation
3    Copyright (C) 2002  Lukasz Pekacki <lukasz@pekacki.de>
4    http://statcvs.sf.net/
5   
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10  
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with this library; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  
20   $RCSfile: Main.java,v $
21   Created on $Date: 2005/03/20 19:12:25 $
22   */
23  package net.sf.statsvn;
24  
25  import java.io.FileInputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.PrintWriter;
29  import java.io.StringWriter;
30  import java.util.ArrayList;
31  import java.util.List;
32  import java.util.Locale;
33  import java.util.logging.LogManager;
34  
35  import net.sf.statcvs.Messages;
36  import net.sf.statcvs.input.LogSyntaxException;
37  import net.sf.statcvs.model.Repository;
38  import net.sf.statcvs.output.ConfigurationException;
39  import net.sf.statcvs.output.ConfigurationOptions;
40  import net.sf.statcvs.output.ReportConfig;
41  import net.sf.statcvs.pages.ReportSuiteMaker;
42  import net.sf.statsvn.input.Builder;
43  import net.sf.statsvn.input.RepositoryFileManager;
44  import net.sf.statsvn.input.SvnLogfileParser;
45  import net.sf.statsvn.output.SvnCommandLineParser;
46  import net.sf.statsvn.output.SvnConfigurationOptions;
47  import net.sf.statsvn.util.SvnVersionMismatchException;
48  
49  /**
50   * StatSvn Main Class; it starts the application and controls command-line
51   * related stuff
52   * 
53   * @author Lukasz Pekacki
54   * @author Richard Cyganiak
55   * @version $Id: Main.java,v 1.47 2005/03/20 19:12:25 squig Exp $
56   */
57  public final class Main {
58      private static final int KB_IN_ONE_MB = 1024;
59  
60      private static final int NUMBER_OF_MS_IN_ONE_SEC = 1000;
61  
62      private static final LogManager LM = LogManager.getLogManager();
63  
64      /**
65       * A utility class (only static methods) should be final and have a private
66       * constructor.
67       */
68      private Main() {
69      }
70  
71      /**
72       * Main method of StatSVN
73       * 
74       * @param args
75       *            command line options
76       */
77      public static void main(final String[] args) {
78          init();
79          verifyArguments(args);
80          generate();
81          System.exit(0);
82      }
83  
84      private static void verifyArguments(final String[] args) {
85          if (args.length == 0) {
86              printProperUsageAndExit();
87          }
88          if (args.length == 1) {
89              final String arg = args[0].toLowerCase(Locale.getDefault());
90              if (arg.equals("-h") || arg.equals("-help")) {
91                  printProperUsageAndExit();
92              } else if (arg.equals("-version")) {
93                  printVersionAndExit();
94              }
95          }
96  
97          try {
98              new SvnCommandLineParser(args).parse();
99          } catch (final ConfigurationException cex) {
100             SvnConfigurationOptions.getTaskLogger().error(cex.getMessage());
101             System.exit(1);
102         }
103     }
104 
105     public static void generate() {
106         try {
107             RepositoryFileManager manager = createRepoManager();
108             String version = manager.getProcessor().getVersionProcessor().checkSvnVersionSufficient();
109             final boolean isNewerDiffPossible = manager.getProcessor().getVersionProcessor().checkDiffPerRevPossible(version);
110             // fall-back to older option.
111             if (!isNewerDiffPossible) {
112                 SvnConfigurationOptions.setLegacyDiff(true);
113             }
114 
115             manager.getProcessor().getInfoProcessor().checkRepoRootAvailable();
116             generateDefaultHTMLSuite(manager);
117         } catch (final ConfigurationException cex) {
118             SvnConfigurationOptions.getTaskLogger().error(cex.getMessage());
119             System.exit(1);
120         } catch (final LogSyntaxException lex) {
121             printLogErrorMessageAndExit(lex.getMessage());
122         } catch (final IOException ioex) {
123             printIoErrorMessageAndExit(ioex.getMessage());
124         } catch (final OutOfMemoryError oome) {
125             printOutOfMemMessageAndExit();
126         } catch (final SvnVersionMismatchException ever) {
127             printErrorMessageAndExit(ever.getMessage());
128         }
129     }
130 
131     public static void init() {
132         Messages.setPrimaryResource("net.sf.statsvn.statcvs"); // primary is
133         // statcvs.properties in net.sf.statsvn
134 
135         SvnConfigurationOptions.getTaskLogger().info(Messages.getString("PROJECT_NAME") + Messages.NL);
136     }
137 
138     private static void initLogManager(final String loggingProperties) {
139         InputStream stream = null;
140         try {
141             stream = Main.class.getResourceAsStream(loggingProperties);
142             LM.readConfiguration(stream);
143         } catch (final IOException e) {
144             SvnConfigurationOptions.getTaskLogger().error("ERROR: Logging could not be initialized!");
145         } finally {
146             if (stream != null) {
147                 try {
148                     stream.close();
149                 } catch (final IOException e) {
150                     SvnConfigurationOptions.getTaskLogger().error("ERROR: could not close stream!");
151                 }
152             }
153         }
154     }
155 
156     private static void printProperUsageAndExit() {
157         final String cr = System.getProperty("line.separator");
158         SvnConfigurationOptions.getTaskLogger().error(
159         // max. 80 chars
160                 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
161                 "Usage: java -jar statsvn.jar [options] <logfile> <directory>" + cr + cr + "Required parameters:" + cr
162                         + "  <logfile>          path to the svn logfile of the module" + cr
163                         + "  <directory>        path to the directory of the checked out module" + cr + cr + "Some options:" + cr
164                         + "  -version           print the version information and exit" + cr + "  -output-dir <dir>  directory where HTML suite will be saved"
165                         + cr + "  -include <pattern> include only files matching pattern, e.g. **/*.c;**/*.h" + cr
166                         + "  -exclude <pattern> exclude matching files, e.g. tests/**;docs/**" + cr
167                         + "  -tags <regexp>     show matching tags in lines of code chart, e.g. version-.*" + cr
168                         + "  -title <title>     Project title to be used in reports" + cr + "  -viewvc <url>      integrate with ViewVC installation at <url>"
169                         + cr + "  -trac <url>        integrate with Trac at <url>" + cr + "  -bugzilla <url>    integrate with Bugzilla installation at <url>"
170                         + cr + "  -username <svnusername> username to pass to svn" + cr + "  -password <svnpassword> password to pass to svn" + cr
171                         + "  -verbose           print extra progress information" + cr + "  -xdoc                 optional switch output to xdoc" + cr
172                         + "  -xml                  optional switch output to xml" + cr + "  -threads <int>        how many threads for svn diff (default: 25)"
173                         + cr + "  -concurrency-threshold <millisec> switch to concurrent svn diff if 1st call>threshold (default: 4000)" + cr
174                         + "  -dump                 dump the Repository content on console" + cr
175                         + "  -charset <charset> specify the charset to use for html/xdoc\n"
176                         + "  -tags-dir <directory> optional, specifies the director for tags (default '/tags/')" + cr + cr
177                         + "Full options list: http://www.statsvn.org");
178         System.exit(1);
179     }
180 
181     private static void printVersionAndExit() {
182         SvnConfigurationOptions.getTaskLogger().error("Version " + Messages.getString("PROJECT_VERSION"));
183         System.exit(1);
184     }
185 
186     private static void printOutOfMemMessageAndExit() {
187         SvnConfigurationOptions.getTaskLogger().error("OutOfMemoryError.");
188         SvnConfigurationOptions.getTaskLogger().error("Try running java with the -mx option (e.g. -mx128m for 128Mb).");
189         System.exit(1);
190     }
191 
192     private static void printLogErrorMessageAndExit(final String message) {
193         SvnConfigurationOptions.getTaskLogger().error("Logfile parsing failed.");
194         SvnConfigurationOptions.getTaskLogger().error(message);
195         System.exit(1);
196     }
197 
198     private static void printIoErrorMessageAndExit(final String message) {
199         SvnConfigurationOptions.getTaskLogger().error(message);
200         System.exit(1);
201     }
202 
203     public static String printStackTrace(final Exception e) {
204         try {
205             final StringWriter sw = new StringWriter();
206             final PrintWriter pw = new PrintWriter(sw);
207             e.printStackTrace(pw);
208             return sw.toString();
209         } catch (final Exception e2) {
210             if (e != null) {
211                 return e.getMessage();
212             } else {
213                 return "";
214             }
215         }
216     }
217 
218     private static void printErrorMessageAndExit(final String message) {
219         SvnConfigurationOptions.getTaskLogger().error(message);
220         System.exit(1);
221     }
222 
223     /**
224      * Generates HTML report. {@link net.sf.statsvn.output.ConfigurationOptions}
225      * must be initialized before calling this method.
226      * 
227      * @throws LogSyntaxException
228      *             if the logfile contains unexpected syntax
229      * @throws IOException
230      *             if some file can't be read or written
231      * @throws ConfigurationException
232      *             if a required ConfigurationOption was not set
233      */
234     public static void generateDefaultHTMLSuite() throws LogSyntaxException, IOException, ConfigurationException {
235         generateDefaultHTMLSuite(createRepoManager());
236     }
237 
238     private static RepositoryFileManager createRepoManager() {
239         return new RepositoryFileManager(ConfigurationOptions.getCheckedOutDirectory());
240     }
241 
242     /**
243      * Generates HTML report. {@link net.sf.statsvn.output.ConfigurationOptions}
244      * must be initialized before calling this method.
245      * 
246      * @param externalRepositoryFileManager
247      *            RepositoryFileManager which is used to access the files in the
248      *            repository.
249      * 
250      * @throws LogSyntaxException
251      *             if the logfile contains unexpected syntax
252      * @throws IOException
253      *             if some file can't be read or written
254      * @throws ConfigurationException
255      *             if a required ConfigurationOption was not set
256      */
257     public static void generateDefaultHTMLSuite(final RepositoryFileManager repFileMan) throws LogSyntaxException, IOException, ConfigurationException {
258 
259         if (ConfigurationOptions.getLogFileName() == null) {
260             throw new ConfigurationException("Missing logfile name");
261         }
262         if (ConfigurationOptions.getCheckedOutDirectory() == null) {
263             throw new ConfigurationException("Missing checked out directory");
264         }
265 
266         final long memoryUsedOnStart = Runtime.getRuntime().totalMemory();
267         final long startTime = System.currentTimeMillis();
268 
269         initLogManager(ConfigurationOptions.getLoggingProperties());
270 
271         SvnConfigurationOptions.getTaskLogger().info(
272                 "Parsing SVN log '"
273                         + ConfigurationOptions.getLogFileName()
274                         + "'"
275                         + (ConfigurationOptions.getExcludePattern() != null ? " exclude pattern '" + ConfigurationOptions.getExcludePattern() + "'"
276                                 : "No exclude pattern"));
277 
278         FileInputStream logFile = null;
279         Builder builder = null;
280         try {
281             logFile = new FileInputStream(ConfigurationOptions.getLogFileName());
282             builder = new Builder(repFileMan, ConfigurationOptions.getIncludePattern(), ConfigurationOptions.getExcludePattern(), ConfigurationOptions
283                     .getSymbolicNamesPattern());
284             new SvnLogfileParser(repFileMan, logFile, builder).parse();
285         } finally {
286             if (logFile != null) {
287                 logFile.close();
288             }
289         }
290 
291         if (ConfigurationOptions.getProjectName() == null) {
292             ConfigurationOptions.setProjectName(builder.getProjectName());
293         }
294         if (ConfigurationOptions.getWebRepository() != null) {
295             ConfigurationOptions.getWebRepository().setAtticFileNames(builder.getAtticFileNames());
296         }
297 
298         SvnConfigurationOptions.getTaskLogger().info(
299                 "Generating report for " + ConfigurationOptions.getProjectName() + " into " + ConfigurationOptions.getOutputDir());
300         SvnConfigurationOptions.getTaskLogger().info("Using " + ConfigurationOptions.getCssHandler());
301         final Repository content = builder.createRepository();
302 
303         long memoryUsedOnEnd = Runtime.getRuntime().totalMemory();
304         SvnConfigurationOptions.getTaskLogger().info("memory usage After Build: " + (((double) memoryUsedOnEnd - memoryUsedOnStart) / KB_IN_ONE_MB) + " kb");
305 
306         builder.clean();
307         builder = null;
308 
309         // make JFreeChart work on systems without GUI
310         System.setProperty("java.awt.headless", "true");
311 
312         final ReportConfig config = new ReportConfig(content, ConfigurationOptions.getProjectName(), ConfigurationOptions.getOutputDir(), ConfigurationOptions
313                 .getMarkupSyntax(), ConfigurationOptions.getCssHandler(), ConfigurationOptions.getCharSet());
314         config.setWebRepository(ConfigurationOptions.getWebRepository());
315         config.setWebBugtracker(ConfigurationOptions.getWebBugtracker());
316         config.setNonDeveloperLogins(ConfigurationOptions.getNonDeveloperLogins());
317 
318         validate(config);
319 
320         if (SvnConfigurationOptions.isDumpContent()) {
321             new RepoDump(content).dump();
322         } else {
323             // add new reports
324             final List extraReports = new ArrayList();
325 
326             if ("xml".equalsIgnoreCase(ConfigurationOptions.getOutputFormat())) {
327                 new ReportSuiteMaker(config, ConfigurationOptions.getNotes(), extraReports).toXml();
328             } else {
329                 new ReportSuiteMaker(config, ConfigurationOptions.getNotes(), extraReports).toFile().write();
330             }
331         }
332         final long endTime = System.currentTimeMillis();
333         memoryUsedOnEnd = Runtime.getRuntime().totalMemory();
334 
335         SvnConfigurationOptions.getTaskLogger().info("runtime: " + (((double) endTime - startTime) / NUMBER_OF_MS_IN_ONE_SEC) + " seconds");
336         SvnConfigurationOptions.getTaskLogger().info("memory usage: " + (((double) memoryUsedOnEnd - memoryUsedOnStart) / KB_IN_ONE_MB) + " kb");
337     }
338 
339     private static void validate(final ReportConfig config) {
340         if (config.getRepository() == null || config.getRepository().getRoot() == null || config.getRepository().getDirectories() == null) {
341             String cr = System.getProperty("line.separator");
342             printErrorMessageAndExit("The repository object is not valid. Please check your settings." + cr + "Possible reasons:" + cr
343                     + "1/ Did you use the option -v to create the SVN log" + cr + "2/ Is the log file empty?" + cr
344                     + "3/ Do you run from a checked out directory (you should)?" + cr + "4/ Do you have non-committed items?");
345         }
346     }
347 }