1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
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");
133
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
160
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
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
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 }