924d33182d28c4824207b6fde0712d4362d6d6b7
[cfb.git] / prod / net / jaekl / cfb / CFB.java
1 package net.jaekl.cfb;
2
3 // Comparative FindBugs
4 // 
5 // Tool to compare successive runs of FindBugs, 
6 // flagging the change from one run to the next.
7 // 
8 // Copyright (C) 2015 Christian Jaekl
9
10 import java.io.File;
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;
18
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;
27
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;
34
35 public class CFB {
36         DbDriver m_driver;
37         CfbSchema m_schema;
38         CfbBundle m_bundle;     
39         Locale m_locale;
40         
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
51         
52         CFB(Locale locale) {
53                 m_driver = new PostgresqlDriver();
54                 m_schema = new CfbSchema(m_driver);
55                 m_locale = locale;
56                 m_bundle = CfbBundle.getInst(m_locale);
57                 
58                 m_dbName = "CFB";
59                 m_fbp    = null;
60                 m_fbDir  = null;
61                 m_host = "localhost";
62                 m_port = 5432;
63                 m_pass = "";
64                 m_user = "user";
65                 m_buildNum = null;
66                 m_removeSchema = false;
67         }
68         
69         Options createOptions() {
70                 Options opt = new Options();
71                 
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");
80                 
81                 return opt;
82         }
83         
84         boolean parseArgs(PrintWriter pw, String[] args) {
85                 Options opt = createOptions();
86                 
87                 try {
88                         CommandLine line = new GnuParser().parse(opt, args);
89                         if (line.hasOption("d")) {
90                                 m_dbName = line.getOptionValue("d");
91                         }
92                         if (line.hasOption("f")) {
93                                 m_fbp = new File(line.getOptionValue("f"));
94                         }
95                         if (line.hasOption("h")) {
96                                 m_host = line.getOptionValue("h");
97                         }
98                         if (line.hasOption("n")) {
99                                 m_buildNum = line.getOptionValue("n");
100                         }
101                         if (line.hasOption("p")) {
102                                 m_pass = line.getOptionValue("p");
103                         }
104                         m_removeSchema = line.hasOption("r");
105                         if (line.hasOption("t")) {
106                                 m_port = Integer.parseInt(line.getOptionValue("t"));
107                         }
108                         if (line.hasOption("u")) {
109                                 m_user = line.getOptionValue("u");
110                         }
111                 } 
112                 catch (ParseException exc) {
113                         usage(pw, opt);
114                         return false;
115                 }
116                 
117                 return true;
118         }
119         
120         void usage(PrintWriter pw, Options opt) {
121                 HelpFormatter help = new HelpFormatter();
122                 help.printHelp(pw, 80, getClass().getName(), "", opt, 0, 0, "", true);
123         }
124         
125         String trans(String key) {
126                 return m_bundle.get(key);
127         }
128         
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);
132         }
133         
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);
137         }
138         
139         File getFindBugsDir() {
140                 return (null != m_fbDir) ? m_fbDir : new File(".");
141         }
142         
143         void initArgs() {
144                 String findBugsDir = getenv("FINDBUGS_HOME");
145                 if (null != findBugsDir) {
146                         m_fbDir = new File(findBugsDir);
147                 }
148                 findBugsDir = getProperty("findbugs.home");
149                 if (null != findBugsDir) {
150                         m_fbDir = new File(findBugsDir);
151                 }
152         } 
153         
154         void doMain(PrintWriter pw, String[] args) throws SQLException, IOException, XmlParseException, SAXException {
155                 initArgs();     // read environment and system properties
156                 if ( ! parseArgs(pw, args) ) {
157                         return;
158                 }
159
160                 File findBugsDir = getFindBugsDir();
161                 File workDir = new File(".");
162                 MessageMap messageMap = new MessageMap();
163                 messageMap.load(findBugsDir, Locale.getDefault(Category.DISPLAY));
164                 
165                 try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) {
166                         m_schema.setMessageMap(messageMap);
167                         
168                         if (m_removeSchema) {
169                                 m_schema.purge(con);
170                                 return;
171                         }
172                         m_schema.ensureDbInitialized(con);      
173                 }
174                 catch (SQLException exc) {
175                         reportUnableToConnect(pw, exc);
176                         return;
177                 }
178                 
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));
183                         return;
184                 }
185                 
186                 try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) {
187                         DbStore store = new DbStore(con);
188                         
189                         store.put(analysis);
190                 }
191                 catch (SQLException exc) {
192                         reportUnableToConnect(pw, exc);
193                         return;
194                 }
195         }
196
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);
202         }
203         
204         public static void main(String[] args) {
205                 CFB cfb = new CFB(Locale.getDefault());
206                 
207                 try (PrintWriter pw = new PrintWriter(System.out)){
208                         cfb.doMain(pw, args);
209                         pw.flush();
210                 } catch (SQLException | IOException | XmlParseException | SAXException exc) {
211                         exc.printStackTrace();
212                 }
213         }
214
215 }