3 // Comparative FindBugs
5 // Tool to compare successive runs of FindBugs,
6 // flagging the change from one run to the next.
8 // Copyright (C) 2015 Christian Jaekl
11 import java.io.IOException;
12 import java.io.PrintWriter;
13 import java.sql.Connection;
14 import java.sql.SQLException;
15 import java.text.MessageFormat;
16 import java.util.Locale;
17 import java.util.Locale.Category;
19 import net.jaekl.cfb.analyze.Analysis;
20 import net.jaekl.cfb.analyze.Analyzer;
21 import net.jaekl.cfb.analyze.MessageMap;
22 import net.jaekl.cfb.db.CfbSchema;
23 import net.jaekl.cfb.db.driver.DbDriver;
24 import net.jaekl.cfb.db.driver.PostgresqlDriver;
25 import net.jaekl.cfb.store.DbStore;
26 import net.jaekl.qd.xml.XmlParseException;
28 import org.apache.commons.cli.CommandLine;
29 import org.apache.commons.cli.GnuParser;
30 import org.apache.commons.cli.HelpFormatter;
31 import org.apache.commons.cli.Options;
32 import org.apache.commons.cli.ParseException;
33 import org.xml.sax.SAXException;
41 // Command-line parameters
42 String m_dbName; // db name
43 File m_fbp; // FindBugsProject file
44 File m_fbDir; // Directory where FindBugs is installed
45 String m_host; // db host
46 int m_port; // db port
47 String m_user; // db user
48 String m_pass; // db password
49 String m_buildNum; // build number (version)
50 boolean m_removeSchema; // purge DB schema
53 m_driver = new PostgresqlDriver();
54 m_schema = new CfbSchema(m_driver);
56 m_bundle = CfbBundle.getInst(m_locale);
66 m_removeSchema = false;
69 Options createOptions() {
70 Options opt = new Options();
72 opt.addOption("d", "dbname", true, "DB name");
73 opt.addOption("f", "fbp", true, "FindBugsProject file");
74 opt.addOption("h", "host", true, "DB hostname");
75 opt.addOption("n", "number", true, "Build number (version)");
76 opt.addOption("p", "pass", true, "DB password");
77 opt.addOption("r", "remove", false, "Remove database schema (drop all data)");
78 opt.addOption("t", "port", true, "DB port");
79 opt.addOption("u", "user", true, "DB username");
84 boolean parseArgs(PrintWriter pw, String[] args) {
85 Options opt = createOptions();
88 CommandLine line = new GnuParser().parse(opt, args);
89 if (line.hasOption("d")) {
90 m_dbName = line.getOptionValue("d");
92 if (line.hasOption("f")) {
93 m_fbp = new File(line.getOptionValue("f"));
95 if (line.hasOption("h")) {
96 m_host = line.getOptionValue("h");
98 if (line.hasOption("n")) {
99 m_buildNum = line.getOptionValue("n");
101 if (line.hasOption("p")) {
102 m_pass = line.getOptionValue("p");
104 m_removeSchema = line.hasOption("r");
105 if (line.hasOption("t")) {
106 m_port = Integer.parseInt(line.getOptionValue("t"));
108 if (line.hasOption("u")) {
109 m_user = line.getOptionValue("u");
112 catch (ParseException exc) {
120 void usage(PrintWriter pw, Options opt) {
121 HelpFormatter help = new HelpFormatter();
122 help.printHelp(pw, 80, getClass().getName(), "", opt, 0, 0, "", true);
125 String trans(String key) {
126 return m_bundle.get(key);
129 String getenv(String varName) {
130 // This is a separate function so that we can override it at unit test time
131 return System.getenv(varName);
134 String getProperty(String propName) {
135 // This is a separate function so that we can override it at unit test time
136 return System.getProperty(propName);
139 File getFindBugsDir() {
140 return (null != m_fbDir) ? m_fbDir : new File(".");
144 String findBugsDir = getenv("FINDBUGS_HOME");
145 if (null != findBugsDir) {
146 m_fbDir = new File(findBugsDir);
148 findBugsDir = getProperty("findbugs.home");
149 if (null != findBugsDir) {
150 m_fbDir = new File(findBugsDir);
154 void doMain(PrintWriter pw, String[] args) throws SQLException, IOException, XmlParseException, SAXException {
155 initArgs(); // read environment and system properties
156 if ( ! parseArgs(pw, args) ) {
160 File findBugsDir = getFindBugsDir();
161 File workDir = new File(".");
162 MessageMap messageMap = new MessageMap();
163 messageMap.load(findBugsDir, Locale.getDefault(Category.DISPLAY));
165 try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) {
166 m_schema.setMessageMap(messageMap);
168 if (m_removeSchema) {
172 m_schema.ensureDbInitialized(con);
174 catch (SQLException exc) {
175 reportUnableToConnect(pw, exc);
179 Analyzer analyzer = new Analyzer(messageMap);
180 Analysis analysis = analyzer.analyze(pw, workDir, m_fbp, m_buildNum);
181 if (null == analysis) {
182 pw.println(trans(CfbBundle.ANALYSIS_FAILED));
186 try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) {
187 DbStore store = new DbStore(con);
191 catch (SQLException exc) {
192 reportUnableToConnect(pw, exc);
197 private void reportUnableToConnect(PrintWriter pw, SQLException exc) {
198 String cannotConnectFormat = trans(CfbBundle.CANNOT_CONNECT);
199 String cannotConnect = MessageFormat.format(cannotConnectFormat, m_host, ""+m_port, m_dbName, m_user);
200 exc.printStackTrace(pw);
201 pw.println(cannotConnect);
204 public static void main(String[] args) {
205 CFB cfb = new CFB(Locale.getDefault());
207 try (PrintWriter pw = new PrintWriter(System.out)){
208 cfb.doMain(pw, args);
210 } catch (SQLException | IOException | XmlParseException | SAXException exc) {
211 exc.printStackTrace();