1 package net.sf.statsvn.util;
2 
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.util.Arrays;
7 import java.util.Collections;
8 import java.util.Iterator;
9 import java.util.Properties;
10 import java.util.Vector;
11 
12 import net.sf.statcvs.Messages;
13 
14 /**
15  * This class provides a report to standard output of relevant JRE properties
16  * and svn executable information. This output is intended to be included with
17  * bug reports to help the StatSVN team diagnose common issues with wrong SVN
18  * version, wrong JRE version, and locale settings.
19  *
20  * @author jpdaigle jpdaigle@softwareengineering.ca
21  *
22  */
23 public final class EnvReport {
24 	private static String[] envPropKeys = { "file.encoding", "java.home", "java.runtime.version", "os.arch", "os.name", "os.version", "user.country",
25 	        "user.language" };
26 
27 	static final String SVN_VERSION_COMMAND = "svn --version";
28 
29 	static final String SVN_VERSION_LINE_PATTERN = ".* [0-9]+\\.[0-9]+\\.[0-9]+.*";
30 
31 	static final String KEY_SVN_ABLE_TO_RUN = "svn.able.to.run";
32 
33 	static final String KEY_SVN_VERSION = "svn.reportedversion";
34 
35 	static final String KEY_STATSVN_VERSION = "statsvn.reportedversion";
36 
EnvReport()37 	private EnvReport() {
38 		// no public ctor
39 	}
40 
main(final String[] args)41 	public static void main(final String[] args) {
42 		System.out.println(getEnvReport());
43 	}
44 
getEnvReport()45 	public static String getEnvReport() {
46 		final StringBuffer buf = new StringBuffer();
47 		buf.append("\nWhen reporting a StatSVN bug or requesting assistance,\n");
48 		buf.append("please include the entirety of the output below.\n");
49 		buf.append("No personally-identifiable information is included.\n\n");
50 
51 		buf.append("=== Java Runtime Properties ===\n");
52 		buf.append(fmtPropertiesForScreen(System.getProperties(), envPropKeys));
53 
54 		buf.append("\n");
55 		buf.append("=== Subversion Properties ===\n");
56 		buf.append(fmtPropertiesForScreen(getSvnVersionInfo(), null));
57 
58 		buf.append("\n");
59 		buf.append("=== StatSVN Properties ===\n");
60 		buf.append(fmtPropertiesForScreen(getStatSVNInfo(), null));
61 
62 		return buf.toString();
63 	}
64 
65 	/**
66 	 * Format a set of key/value Properties for the screen, by right-aligning
67 	 * the key column. Each key/value pair is printed and followed by a newline.
68 	 *
69 	 * @author jpdaigle
70 	 * @param props
71 	 *            Property set to format for printout.
72 	 * @param keySet
73 	 *            The keys of interest to use. If null, use all keys defined in
74 	 *            props.
75 	 * @return Formatted text block with property keys and values, with a
76 	 *         newline after every set.
77 	 */
fmtPropertiesForScreen(final Properties props, String[] keySet)78 	public static String fmtPropertiesForScreen(final Properties props, String[] keySet) {
79 		int maxWidth = 0;
80 		final StringBuffer buf = new StringBuffer();
81 		if (keySet == null) {
82 			keySet = (String[]) props.keySet().toArray(new String[props.keySet().size()]);
83 		}
84 		final Vector vKeys = new Vector(Arrays.asList(keySet));
85 		Collections.sort(vKeys);
86 
87 		// First pass: find length of longest key
88 		for (final Iterator ite = vKeys.iterator(); ite.hasNext();) {
89 			final String key = ((String) ite.next()).trim();
90 			maxWidth = (key.length() > maxWidth) ? key.length() : maxWidth;
91 		}
92 
93 		// Second pass: output formatted keys / values
94 		for (final Iterator ite = vKeys.iterator(); ite.hasNext();) {
95 			final String key = ((String) ite.next()).trim();
96 			for (int i = maxWidth - key.length(); i > 0; i--) {
97 				buf.append(" ");
98 			}
99 			buf.append(key).append(":[").append(props.getProperty(key).trim()).append("]\n");
100 		}
101 
102 		return buf.toString();
103 	}
104 
105 	/**
106 	 * Get svn executable version info. We cannot use the excellent
107 	 * "ProcessUtils" because we are not running in the context of a StatSVN
108 	 * invocation. We use a plain old exec().
109 	 *
110 	 * @return Property set
111 	 */
getSvnVersionInfo()112 	public static Properties getSvnVersionInfo() {
113 
114 		String versionLine = "";
115 		String line;
116 		final Properties svnProps = new Properties();
117 		BufferedReader input = null;
118 
119 		try {
120 			svnProps.setProperty(KEY_SVN_ABLE_TO_RUN, "YES");
121 			final Process proc = Runtime.getRuntime().exec(SVN_VERSION_COMMAND);
122 
123 			input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
124 			while ((line = input.readLine()) != null) {
125 				if (line.matches(SVN_VERSION_LINE_PATTERN)) {
126 					// We have our version line
127 					versionLine = line.trim();
128 					break;
129 				}
130 			}
131 		} catch (final Exception e) {
132 			svnProps.setProperty(KEY_SVN_ABLE_TO_RUN, "NO: " + e.getMessage().trim());
133 		} finally {
134 			svnProps.setProperty(KEY_SVN_VERSION, versionLine);
135 			if (input != null) {
136 				try {
137 					input.close();
138 				} catch (final IOException ex) {
139 					// swallow it
140 					ex.printStackTrace();
141 				}
142 			}
143 		}
144 		return svnProps;
145 	}
146 
147 	/**
148 	 * Get information about the current version of StatSVN.
149 	 * @return Property set
150 	 */
getStatSVNInfo()151 	public static Properties getStatSVNInfo() {
152 		final Properties statsvnProps = new Properties();
153 		statsvnProps.setProperty(KEY_STATSVN_VERSION, Messages.getString("PROJECT_VERSION"));
154 		return statsvnProps;
155 	}
156 
157 }
158