X-Git-Url: http://jaekl.net/gitweb/?p=cfb.git;a=blobdiff_plain;f=prod%2Fnet%2Fjaekl%2Fcfb%2FCFB.java;h=c02aa546aa0f7efe1bd29b36f81703127e3e6497;hp=d864b6dc8681b9ae3de5d32b6603329385cc83ca;hb=2769cf82ccae57ee3716aecc9bd694be1f115d92;hpb=de1f17a1ad8450ab525be1ca696c067c57acaaab diff --git a/prod/net/jaekl/cfb/CFB.java b/prod/net/jaekl/cfb/CFB.java index d864b6d..c02aa54 100644 --- a/prod/net/jaekl/cfb/CFB.java +++ b/prod/net/jaekl/cfb/CFB.java @@ -1,49 +1,100 @@ package net.jaekl.cfb; +// Comparative FindBugs +// +// Tool to compare successive runs of FindBugs, +// flagging the change from one run to the next. +// +// Copyright (C) 2015 Christian Jaekl + +import java.io.File; +import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.nio.charset.Charset; import java.sql.Connection; import java.sql.SQLException; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.Locale.Category; + +import net.jaekl.cfb.analyze.Analysis; +import net.jaekl.cfb.analyze.Analyzer; +import net.jaekl.cfb.analyze.Delta; +import net.jaekl.cfb.analyze.HtmlReport; +import net.jaekl.cfb.analyze.MessageMap; +import net.jaekl.cfb.analyze.Notifier; +import net.jaekl.cfb.db.CfbSchema; +import net.jaekl.cfb.db.TypeMismatchException; +import net.jaekl.cfb.db.driver.DbDriver; +import net.jaekl.cfb.db.driver.PostgresqlDriver; +import net.jaekl.cfb.store.DbStore; +import net.jaekl.qd.xml.XmlParseException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; - -import net.jaekl.cfb.db.CfbSchema; -import net.jaekl.cfb.db.driver.DbDriver; -import net.jaekl.cfb.db.driver.PostgresqlDriver; +import org.xml.sax.SAXException; public class CFB { DbDriver m_driver; CfbSchema m_schema; + CfbBundle m_bundle; + Locale m_locale; + + Config m_config; // Command-line parameters + File m_configFile; String m_dbName; // db name + File m_fbp; // FindBugsProject file + File m_fbDir; // Directory where FindBugs is installed String m_host; // db host int m_port; // db port String m_user; // db user String m_pass; // db password + String m_projName; // project (module) name + String m_buildNum; // build number (version) + boolean m_removeSchema; // purge DB schema + File m_output; // File to which we should write our output (report) - CFB() { + CFB(Locale locale) { m_driver = new PostgresqlDriver(); m_schema = new CfbSchema(m_driver); + m_locale = locale; + m_bundle = CfbBundle.getInst(m_locale); + m_config = new Config(); + m_configFile = new File("config.properties"); m_dbName = "CFB"; + m_fbp = null; + m_fbDir = null; m_host = "localhost"; m_port = 5432; m_pass = ""; m_user = "user"; + m_projName = null; + m_buildNum = null; + m_removeSchema = false; + m_output = null; } Options createOptions() { Options opt = new Options(); - opt.addOption("d", "dbname", true, "DB name"); - opt.addOption("h", "host", true, "DB hostname"); - opt.addOption("p", "pass", true, "DB password"); - opt.addOption("t", "port", true, "DB port"); - opt.addOption("u", "user", true, "DB username"); + opt.addOption("c", "config", true, "Properties configuration file"); + opt.addOption("d", "dbname", true, "DB name"); + opt.addOption(null, "drop-tables", false, "Remove database schema (drop all data)"); + opt.addOption("f", "fbp", true, "FindBugsProject file"); + opt.addOption("h", "host", true, "DB hostname"); + opt.addOption("j", "project", true, "proJect name"); + opt.addOption("n", "number", true, "Build number (version)"); + opt.addOption("o", "outfile", true, "Output report filename"); + opt.addOption("p", "pass", true, "DB password"); + opt.addOption("t", "port", true, "DB port"); + opt.addOption("u", "user", true, "DB username"); return opt; } @@ -53,15 +104,31 @@ public class CFB { try { CommandLine line = new GnuParser().parse(opt, args); + if (line.hasOption("c")) { + m_configFile = new File(line.getOptionValue("c")); + } if (line.hasOption("d")) { m_dbName = line.getOptionValue("d"); } + if (line.hasOption("f")) { + m_fbp = new File(line.getOptionValue("f")); + } if (line.hasOption("h")) { m_host = line.getOptionValue("h"); } + if (line.hasOption("j")) { + m_projName = line.getOptionValue("j"); + } + if (line.hasOption("n")) { + m_buildNum = line.getOptionValue("n"); + } + if (line.hasOption("o")) { + m_output = new File(line.getOptionValue("o")); + } if (line.hasOption("p")) { m_pass = line.getOptionValue("p"); } + m_removeSchema = line.hasOption("drop-tables"); if (line.hasOption("t")) { m_port = Integer.parseInt(line.getOptionValue("t")); } @@ -82,27 +149,115 @@ public class CFB { help.printHelp(pw, 80, getClass().getName(), "", opt, 0, 0, "", true); } - void doMain(PrintWriter pw, String[] args) throws SQLException { + String trans(String key) { + return m_bundle.get(key); + } + + String getenv(String varName) { + // This is a separate function so that we can override it at unit test time + return System.getenv(varName); + } + + String getProperty(String propName) { + // This is a separate function so that we can override it at unit test time + return System.getProperty(propName); + } + + File getFindBugsDir() { + return (null != m_fbDir) ? m_fbDir : new File("."); + } + + void initArgs() { + String findBugsDir = getenv("FINDBUGS_HOME"); + if (null != findBugsDir) { + m_fbDir = new File(findBugsDir); + } + findBugsDir = getProperty("findbugs.home"); + if (null != findBugsDir) { + m_fbDir = new File(findBugsDir); + } + } + + void readConfig() throws IOException { + if (null != m_configFile) { + m_config.readFile(m_configFile); + } + } + + void doMain(PrintWriter pw, String[] args) throws SQLException, IOException, XmlParseException, SAXException, TypeMismatchException { + initArgs(); // read environment and system properties if ( ! parseArgs(pw, args) ) { return; } + readConfig(); + + File findBugsDir = getFindBugsDir(); + File workDir = new File("."); + MessageMap messageMap = new MessageMap(); + messageMap.load(findBugsDir, Locale.getDefault(Category.DISPLAY)); try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) { - if (null == con) { - // TODO: string table - pw.println("FATAL: Cannot connect to db."); + m_schema.setMessageMap(messageMap); + + if (m_removeSchema) { + m_schema.purge(con); return; } - m_schema.ensureDbInitialized(con); + m_schema.ensureDbInitialized(con); + messageMap.loadIds(con, m_driver); + } + catch (SQLException exc) { + reportUnableToConnect(pw, exc); + return; + } + + Analyzer analyzer = new Analyzer(messageMap); + Analysis analysis = analyzer.analyze(pw, workDir, m_fbp, m_projName, m_buildNum); + if (null == analysis) { + pw.println(trans(CfbBundle.ANALYSIS_FAILED)); + return; + } + + try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) { + DbStore store = new DbStore(con, m_driver, messageMap.getColl()); + + store.put(analysis); + Analysis prior = store.getPrior(analysis); + Delta delta = new Delta(prior, analysis); + + HtmlReport report = new HtmlReport(m_bundle, messageMap.getColl(), delta); + if (null != m_output) { + report.write(m_output); + } + + Notifier notifier = new Notifier(m_bundle, m_config); + notifier.sendEmailIfNeeded(pw, report); + } + catch (SQLException exc) { + reportUnableToConnect(pw, exc); + return; + } + } + + private void reportUnableToConnect(PrintWriter pw, SQLException exc) { + String cannotConnectFormat = trans(CfbBundle.CANNOT_CONNECT); + String cannotConnect = MessageFormat.format(cannotConnectFormat, m_host, ""+m_port, m_dbName, m_user); + exc.printStackTrace(pw); + SQLException next = exc.getNextException(); + while (null != next) { + next.printStackTrace(pw); + next = next.getNextException(); } + pw.println(cannotConnect); } public static void main(String[] args) { - CFB cfb = new CFB(); + CFB cfb = new CFB(Locale.getDefault()); - try (PrintWriter pw = new PrintWriter(System.out)){ + try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out, Charset.defaultCharset()))) { cfb.doMain(pw, args); - } catch (SQLException exc) { + pw.flush(); + } catch (SQLException | IOException | XmlParseException | SAXException | TypeMismatchException exc) { exc.printStackTrace(); } }