1 19 20 package edu.umd.cs.findbugs.workflow; 21 22 import java.io.FileOutputStream ; 23 import java.io.PrintStream ; 24 import java.text.SimpleDateFormat ; 25 import java.util.Date ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.Map ; 29 30 import edu.umd.cs.findbugs.AppVersion; 31 import edu.umd.cs.findbugs.BugCollection; 32 import edu.umd.cs.findbugs.BugInstance; 33 import edu.umd.cs.findbugs.DetectorFactoryCollection; 34 import edu.umd.cs.findbugs.Project; 35 import edu.umd.cs.findbugs.SortedBugCollection; 36 import edu.umd.cs.findbugs.TigerSubstitutes; 37 import edu.umd.cs.findbugs.config.CommandLine; 38 39 47 public class MineBugHistory { 48 static final int ADDED = 0; 49 static final int NEWCODE = 1; 50 static final int REMOVED = 2; 51 static final int REMOVEDCODE= 3; 52 static final int RETAINED = 4; 53 static final int DEAD = 5; 54 static final int ACTIVE_NOW = 6; 55 static final int TUPLE_SIZE = 7; 56 57 static final SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy.MM.dd-HH:mm"); 58 59 static class Version { 60 long sequence; 61 int tuple[] = new int[TUPLE_SIZE]; 62 63 Version(long sequence) { 64 this.sequence = sequence; 65 } 66 67 70 public long getSequence() { 71 return sequence; 72 } 73 74 void increment(int key) { 75 tuple[key]++; 76 if (key == ADDED || key == RETAINED || key == NEWCODE) 77 tuple[ACTIVE_NOW]++; 78 } 79 80 int get(int key) { 81 return tuple[key]; 82 } 83 } 84 85 BugCollection bugCollection; 86 Version[] versionList; 87 Map <Long , AppVersion> sequenceToAppVersionMap = new HashMap <Long , AppVersion>(); 88 boolean formatDates = false; 89 boolean noTabs = false; 90 boolean summary = false; 91 92 public MineBugHistory() { 93 } 94 public MineBugHistory(BugCollection bugCollection) { 95 this.bugCollection = bugCollection; 96 } 97 98 public void setBugCollection(BugCollection bugCollection) { 99 this.bugCollection = bugCollection; 100 } 101 102 public void setFormatDates(boolean value) { 103 this.formatDates = value; 104 } 105 106 public void setNoTabs() { 107 this.noTabs = true; 108 this.summary = false; 109 } 110 public void setSummary() { 111 this.summary = true; 112 this.noTabs = false; 113 } 114 115 116 117 public MineBugHistory execute() { 118 long sequenceNumber = bugCollection.getSequenceNumber(); 119 int maxSequence = (int)sequenceNumber; 120 versionList = new Version[maxSequence + 1]; 121 for (int i = 0; i <= maxSequence; ++i) { 122 versionList[i] = new Version(i); 123 } 124 125 for (Iterator <AppVersion> i = bugCollection.appVersionIterator(); i.hasNext();) { 126 AppVersion appVersion = i.next(); 127 long versionSequenceNumber = appVersion.getSequenceNumber(); 128 sequenceToAppVersionMap.put(TigerSubstitutes.valueOf(versionSequenceNumber), appVersion); 129 } 130 131 AppVersion currentAppVersion = bugCollection.getCurrentAppVersion(); 132 sequenceToAppVersionMap.put( 133 TigerSubstitutes.valueOf(sequenceNumber), 134 currentAppVersion); 135 136 for (Iterator <BugInstance> j = bugCollection.iterator(); j.hasNext();) { 137 BugInstance bugInstance = j.next(); 138 139 for (int i = 0; i <= maxSequence; ++i) { 140 if (bugInstance.getFirstVersion() > i) continue; 141 boolean activePrevious = bugInstance.getFirstVersion() < i 142 && (bugInstance.getLastVersion() == -1 || bugInstance.getLastVersion() >= i-1 ); 143 boolean activeCurrent = bugInstance.getLastVersion() == -1 || bugInstance.getLastVersion() >= i ; 144 145 int key = getKey(activePrevious, activeCurrent); 146 if (key == REMOVED && !bugInstance.isRemovedByChangeOfPersistingClass()) key = REMOVEDCODE; 147 else if (key == ADDED && !bugInstance.isIntroducedByChangeOfExistingClass()) key = NEWCODE; 148 versionList[i].increment(key); 149 } 150 } 151 152 return this; 153 } 154 155 156 157 158 public void dump(PrintStream out) { 159 if (noTabs) dumpNoTabs(out); 160 else if (summary) dumpSummary(out); 161 else dumpOriginal(out); 162 } 163 164 public void dumpSummary(PrintStream out) { 165 166 StringBuffer b = new StringBuffer (); 167 168 for (int i = Math.max(0,versionList.length - 10); i < versionList.length; ++i) { 169 Version version = versionList[i]; 170 int added = version.get(ADDED) + version.get(NEWCODE); 171 int removed = version.get(REMOVED) + version.get(REMOVEDCODE); 172 b.append(" "); 173 if (added > 0) { 174 b.append('+'); b.append(added); 175 } 176 if (removed > 0) { 177 b.append('-'); b.append(removed); 178 } 179 if (added == 0 && removed == 0) b.append('0'); 180 181 int paddingNeeded = 8 - b.length() % 8; 182 if (paddingNeeded > 0) b.append(" ".substring(0,paddingNeeded)); 183 } 184 185 out.println(b.toString()); 186 } 187 188 189 public void dumpOriginal(PrintStream out) { 190 out.println("seq version time classes NCSS added newCode fixed removed retained dead active"); 191 for (int i = 0; i < versionList.length; ++i) { 192 Version version = versionList[i]; 193 AppVersion appVersion = sequenceToAppVersionMap.get(version.getSequence()); 194 out.print(i); 195 out.print('\t'); 196 out.print(appVersion != null ? appVersion.getReleaseName() : ""); 197 out.print('\t'); 198 if (formatDates) 199 out.print("\"" + (appVersion != null ? new Date (appVersion.getTimestamp()).toString() : "") + "\""); 200 else out.print(appVersion != null ? appVersion.getTimestamp() : 0L); 201 out.print('\t'); 202 if (appVersion != null) { 203 out.print(appVersion.getNumClasses()); 204 out.print('\t'); 205 out.print(appVersion.getCodeSize()); 206 207 } else out.print("\t0\t0"); 208 209 for (int j = 0; j < TUPLE_SIZE; ++j) { 210 out.print('\t'); 211 out.print(version.get(j)); 212 } 213 out.println(); 214 } 215 } 216 217 218 private static void pad(int width, PrintStream out) { 219 while (width-- > 0) out.print(' '); 220 } 221 222 227 private static void print(int width, boolean alignRight, PrintStream out, Object obj) { 228 String s = String.valueOf(obj); 229 int padLen = width - s.length(); 230 if (alignRight) pad(padLen, out); 231 out.print(s); if (!alignRight) pad(padLen, out); 233 } 234 235 240 public void dumpNoTabs(PrintStream out) { 241 print(3, true, out, "seq"); 243 out.print(' '); 244 print(19, false, out, "version"); 245 out.print(' '); 246 print(16, false, out, "time"); 247 print(1+7, true, out, "classes"); 248 print(1+7, true, out, "NCSS"); 249 print(1+7, true, out, "added"); 250 print(1+7, true, out, "newCode"); 251 print(1+7, true, out, "fixed"); 252 print(1+7, true, out, "removed"); 253 print(1+8, true, out, "retained"); 254 print(1+6, true, out, "dead"); 255 print(1+7, true, out, "active"); 256 out.println(); 257 for (int i = 0; i < versionList.length; ++i) { 261 Version version = versionList[i]; 262 AppVersion appVersion = sequenceToAppVersionMap.get(version.getSequence()); 263 print(3, true, out, i); out.print(' '); print(19, false, out, appVersion != null ? appVersion.getReleaseName() : ""); 266 out.print(' '); 267 268 long ts = (appVersion != null ? appVersion.getTimestamp(): 0L); 269 if (formatDates) 270 print(16, false, out, dateFormat.format(ts)); 271 else print(16, false, out, ts); 272 out.print(' '); 273 274 print(7, true, out, appVersion != null ? appVersion.getNumClasses() : 0); 275 out.print(' '); 276 print(7, true, out, appVersion != null ? appVersion.getCodeSize() : 0); 277 278 for (int j = 0; j < TUPLE_SIZE; ++j) { 279 out.print(' '); 280 print(7, true, out, version.get(j)); 281 } 282 out.println(); 283 } 284 } 285 286 294 private int getKey(boolean activePrevious, boolean activeCurrent) { 295 if (activePrevious) 296 return activeCurrent ? RETAINED : REMOVED; 297 else return activeCurrent ? ADDED : DEAD; 299 } 300 301 class MineBugHistoryCommandLine extends CommandLine { 302 303 MineBugHistoryCommandLine() { 304 addSwitch("-formatDates", "render dates in textual form"); 305 addSwitch("-noTabs", "delimit columns with groups of spaces for better alignment"); 306 addSwitch("-summary", "just summarize changes over the last ten entries"); 307 } 308 309 @Override 310 public void handleOption(String option, String optionalExtraPart) { 311 if (option.equals("-formatDates")) 312 setFormatDates(true); 313 else if (option.equals("-noTabs")) setNoTabs(); 314 else if (option.equals("-summary")) setSummary(); 315 else 316 throw new IllegalArgumentException ("unknown option: " + option); 317 } 318 319 @Override 320 public void handleOptionWithArgument(String option, String argument) { 321 322 throw new IllegalArgumentException ("unknown option: " + option); 323 } 324 } 325 326 public static void main(String [] args) throws Exception { 327 DetectorFactoryCollection.instance(); 329 MineBugHistory mineBugHistory = new MineBugHistory(); 330 MineBugHistoryCommandLine commandLine = mineBugHistory.new MineBugHistoryCommandLine(); 331 int argCount = commandLine.parse(args, 0, 2, "Usage: " + MineBugHistory.class.getName() 332 + " [options] [<xml results> [<history]] "); 333 334 SortedBugCollection bugCollection = new SortedBugCollection(); 335 if (argCount < args.length) 336 bugCollection.readXML(args[argCount++], new Project()); 337 else bugCollection.readXML(System.in, new Project()); 338 mineBugHistory.setBugCollection(bugCollection); 339 340 mineBugHistory.execute(); 341 PrintStream out = System.out; 342 343 try { 344 if (argCount < args.length) { 345 out = new PrintStream (new FileOutputStream (args[argCount++]), true); 346 } 347 mineBugHistory.dump(out); 348 } finally { 349 out.close(); 350 } 351 352 } 353 } 354 | Popular Tags |