1 19 20 package edu.umd.cs.findbugs.workflow; 21 22 import java.io.BufferedOutputStream ; 23 import java.io.BufferedReader ; 24 import java.io.File ; 25 import java.io.FileNotFoundException ; 26 import java.io.FileOutputStream ; 27 import java.io.FileReader ; 28 import java.io.IOException ; 29 import java.io.InputStreamReader ; 30 import java.io.OutputStream ; 31 import java.util.Collection ; 32 import java.util.Iterator ; 33 import java.util.LinkedHashMap ; 34 import java.util.LinkedList ; 35 import java.util.List ; 36 import java.util.Set ; 37 import java.util.TreeSet ; 38 import java.util.Map.Entry; 39 40 import org.dom4j.DocumentException; 41 42 import edu.umd.cs.findbugs.BugInstance; 43 import edu.umd.cs.findbugs.FuzzyBugComparator; 44 import edu.umd.cs.findbugs.Project; 45 import edu.umd.cs.findbugs.SloppyBugComparator; 46 import edu.umd.cs.findbugs.SortedBugCollection; 47 import edu.umd.cs.findbugs.VersionInsensitiveBugComparator; 48 import edu.umd.cs.findbugs.WarningComparator; 49 import edu.umd.cs.findbugs.config.CommandLine; 50 import edu.umd.cs.findbugs.model.MovedClassMap; 51 52 63 @Deprecated 64 public class BugHistory { 65 private static final boolean DEBUG = false; 66 67 private static class BugCollectionAndProject { 68 SortedBugCollection bugCollection; 69 Project project; 70 71 public BugCollectionAndProject(SortedBugCollection bugCollection, Project project) { 72 this.bugCollection = bugCollection; 73 this.project = project; 74 } 75 76 79 public SortedBugCollection getBugCollection() { 80 return bugCollection; 81 } 82 83 86 public Project getProject() { 87 return project; 88 } 89 } 90 91 96 private static class BugCollectionAndProjectCache extends LinkedHashMap <String ,BugCollectionAndProject> { 97 private static final long serialVersionUID = 1L; 98 99 private static final int CACHE_SIZE = 5; 101 102 105 @Override 107 protected boolean removeEldestEntry(Entry<String , BugCollectionAndProject> eldest) { 108 return size() > CACHE_SIZE; 109 } 110 111 119 public BugCollectionAndProject fetch(String fileName) throws IOException , DocumentException { 120 BugCollectionAndProject result = get(fileName); 121 if (result == null) { 122 Project project = new Project(); 123 SortedBugCollection bugCollection = readCollection(fileName, project); 124 result = new BugCollectionAndProject(bugCollection, project); 125 put(fileName, result); 126 } 127 return result; 128 } 129 } 130 131 134 public interface SetOperation { 135 143 public SortedBugCollection perform(Set <BugInstance> result, 144 SortedBugCollection origCollection, SortedBugCollection newCollection); 145 } 146 147 152 public static final SetOperation ADDED_WARNINGS = new SetOperation(){ 153 public SortedBugCollection perform(Set <BugInstance> result, 154 SortedBugCollection origCollection, SortedBugCollection newCollection) { 155 result.addAll(newCollection.getCollection()); 156 157 List <BugInstance> inBoth = getSharedInstances(result, origCollection); 159 160 removeBugInstances(result, inBoth); 162 163 return newCollection; 164 } 165 }; 166 167 172 public static final SetOperation RETAINED_WARNINGS = new SetOperation(){ 173 public SortedBugCollection perform(Set <BugInstance> result, 174 SortedBugCollection origCollection, SortedBugCollection newCollection) { 175 result.addAll(newCollection.getCollection()); 176 if (DEBUG) System.out.println(result.size() + " instances initially"); 177 178 List <BugInstance> inBoth = getSharedInstances(result, origCollection); 180 181 replaceBugInstances(result, inBoth); 183 184 if (DEBUG) System.out.println(result.size() + " after retaining new instances"); 185 return newCollection; 186 } 187 }; 188 189 195 public static final SetOperation REMOVED_WARNINGS = new SetOperation(){ 196 public SortedBugCollection perform(Set <BugInstance> result, 197 SortedBugCollection origCollection, SortedBugCollection newCollection) { 198 result.addAll(origCollection.getCollection()); 199 200 List <BugInstance> inBoth = getSharedInstances(result, newCollection); 202 203 removeBugInstances(result, inBoth); 205 206 return origCollection; 207 } 208 }; 209 210 private SortedBugCollection origCollection, newCollection; 211 private SortedBugCollection resultCollection; 212 private SortedBugCollection originator; 213 private WarningComparator comparator; 214 215 221 public BugHistory(SortedBugCollection origCollection, SortedBugCollection newCollection) { 222 this.origCollection = origCollection; 223 this.newCollection = newCollection; 224 } 225 226 229 public WarningComparator getComparator() { 230 return comparator; 231 } 232 233 236 public void setComparator(WarningComparator comparator) { 237 this.comparator = comparator; 238 } 239 240 246 public SortedBugCollection performSetOperation(SetOperation operation) { 247 TreeSet <BugInstance> result = new TreeSet <BugInstance>(getComparator()); 251 252 originator = operation.perform(result, origCollection, newCollection); 255 256 Collection <BugInstance> selected = new LinkedList <BugInstance>(); 258 SortedBugCollection.cloneAll(selected, result); 259 260 SortedBugCollection resultCollection = originator.duplicate(); 264 265 resultCollection.clearBugInstances(); 267 resultCollection.addAll(selected); 268 269 this.resultCollection = resultCollection; 270 271 return resultCollection; 272 } 273 274 277 public SortedBugCollection getOriginator() { 278 return originator; 279 } 280 281 284 public SortedBugCollection getOrigCollection() { 285 return origCollection; 286 } 287 288 291 public SortedBugCollection getNewCollection() { 292 return newCollection; 293 } 294 295 298 public SortedBugCollection getResultCollection() { 299 return resultCollection; 300 } 301 302 public void writeResultCollection(Project origProject, Project newProject, OutputStream outputStream) throws IOException { 303 getResultCollection().writeXML( 304 outputStream, getOriginator() == getOrigCollection() ? origProject : newProject); 305 } 306 307 316 private static List <BugInstance> getSharedInstances(Set <BugInstance> result, SortedBugCollection collection) { 317 List <BugInstance> inBoth = new LinkedList <BugInstance>(); 318 for (Iterator <BugInstance> i = collection.iterator(); i.hasNext();) { 319 BugInstance origBugInstance = i.next(); 320 if (result.contains(origBugInstance)) { 321 inBoth.add(origBugInstance); 322 } 323 } 324 return inBoth; 325 } 326 327 333 private static void replaceBugInstances(Set <BugInstance> dest, Collection <BugInstance> source) { 334 dest.clear(); 335 dest.addAll(source); 336 } 337 338 344 private static void removeBugInstances(Set <BugInstance> result, Collection <BugInstance> toRemove) { 345 for (BugInstance aToRemove : toRemove) { 346 result.remove(aToRemove); 347 } 348 } 349 350 private static final int VERSION_INSENSITIVE_COMPARATOR = 0; 351 private static final int FUZZY_COMPARATOR = 1; 352 private static final int SLOPPY_COMPARATOR = 2; 353 354 private static class BugHistoryCommandLine extends CommandLine { 355 private int comparatorType = VERSION_INSENSITIVE_COMPARATOR; 356 private boolean count; 357 private String opName; 358 private SetOperation setOp; 359 private String listFile; 360 private String outputDir; 361 private boolean verbose; 362 363 public BugHistoryCommandLine() { 364 addSwitch("-fuzzy", "use fuzzy warning matching"); 365 addSwitch("-sloppy", "use sloppy warning matching"); 366 addSwitch("-added", "compute added warnings"); 367 addSwitch("-new", "same as \"-added\" switch"); 368 addSwitch("-removed", "compute removed warnings"); 369 addSwitch("-fixed", "same as \"-removed\" switch"); 370 addSwitch("-retained", "compute retained warnings"); 371 addSwitch("-count", "just print warning count"); 372 addOption("-bulk", "file of csv xml file pairs", "bulk mode, output written to v2-OP.xml"); 373 addOption("-outputDir", "output dir", "output directory for bulk mode (optional)"); 374 addSwitch("-verbose", "verbose output for bulk mode"); 375 } 376 377 380 @Override 382 protected void handleOption(String option, String optionExtraPart) throws IOException { 383 if (option.equals("-fuzzy")) { 384 comparatorType = FUZZY_COMPARATOR; 385 } else if (option.equals("-sloppy")) { 386 comparatorType = SLOPPY_COMPARATOR; 387 } else if (option.equals("-added") || option.equals("-new")) { 388 opName = option; 389 setOp = ADDED_WARNINGS; 390 } else if (option.equals("-removed") || option.equals("-fixed")) { 391 opName = option; 392 setOp = REMOVED_WARNINGS; 393 } else if (option.equals("-retained")) { 394 opName = option; 395 setOp = RETAINED_WARNINGS; 396 } else if (option.equals("-count")) { 397 count = true; 398 } else if (option.equals("-verbose")) { 399 verbose = true; 400 } else { 401 throw new IllegalArgumentException ("Unknown option: " + option); 402 } 403 } 404 405 408 @Override 410 protected void handleOptionWithArgument(String option, String argument) throws IOException { 411 if (option.equals("-bulk")) { 412 listFile = argument; 413 } else if (option.equals("-outputDir")) { 414 outputDir = argument; 415 } else { 416 throw new IllegalArgumentException ("Unknown option: " + option); 417 } 418 } 419 420 423 public int getComparatorType() { 424 return comparatorType; 425 } 426 427 430 public boolean isCount() { 431 return count; 432 } 433 434 437 public String getOpName() { 438 return opName; 439 } 440 441 444 public SetOperation getSetOp() { 445 return setOp; 446 } 447 448 451 public String getListFile() { 452 return listFile; 453 } 454 455 458 public String getOutputDir() { 459 return outputDir; 460 } 461 462 465 public boolean isVerbose() { 466 return verbose; 467 } 468 469 public void configure(BugHistory bugHistory, SortedBugCollection origCollection, SortedBugCollection newCollection) { 470 WarningComparator comparator; 472 switch (getComparatorType()) { 473 case VERSION_INSENSITIVE_COMPARATOR: 474 comparator = new VersionInsensitiveBugComparator(); 475 break; 476 case FUZZY_COMPARATOR: 477 FuzzyBugComparator fuzzy = new FuzzyBugComparator(); 478 fuzzy.registerBugCollection(origCollection); 479 fuzzy.registerBugCollection(newCollection); 480 comparator = fuzzy; 481 break; 482 case SLOPPY_COMPARATOR: 483 comparator = new SloppyBugComparator(); 484 break; 485 default: 486 throw new IllegalStateException (); 487 } 488 489 MovedClassMap classNameRewriter = new MovedClassMap(origCollection, newCollection).execute(); 491 comparator.setClassNameRewriter(classNameRewriter); 492 493 bugHistory.setComparator(comparator); 494 } 495 496 public BugHistory createAndExecute( 497 String origFile, String newFile, Project origProject, Project newProject) throws IOException , DocumentException { 498 SortedBugCollection origCollection = readCollection(origFile, origProject); 499 SortedBugCollection newCollection = readCollection(newFile, newProject); 500 501 return createAndExecute(origCollection, newCollection, origProject, newProject); 502 } 503 504 public BugHistory createAndExecute( 505 SortedBugCollection origCollection, 506 SortedBugCollection newCollection, 507 Project origProject, 508 Project newProject) { 509 BugHistory bugHistory = new BugHistory(origCollection, newCollection); 510 511 configure(bugHistory, origCollection, newCollection); 512 513 bugHistory.performSetOperation(getSetOp()); 515 516 return bugHistory; 517 } 518 519 public String getBulkOutputFileName(String fileName) { 520 File file = new File (fileName); 521 522 String filePart = file.getName(); 523 int ext = filePart.lastIndexOf('.'); 524 if (ext < 0 ) { 525 filePart = filePart + getOpName(); 526 } else { 527 filePart = filePart.substring(0, ext) + getOpName() + filePart.substring(ext); 528 } 529 530 String dirPart = (getOutputDir() != null) ? getOutputDir() : file.getParent(); 531 532 File outputFile = new File (dirPart, filePart); 533 return outputFile.getPath(); 534 } 535 } 536 537 private static SortedBugCollection readCollection(String fileName, Project project) 538 throws IOException , DocumentException { 539 SortedBugCollection result = new SortedBugCollection(); 540 result.readXML(fileName, project); 541 return result; 542 } 543 544 public static void main(String [] argv) throws Exception { 545 BugHistoryCommandLine commandLine = new BugHistoryCommandLine(); 546 int argCount = commandLine.parse(argv); 547 548 if (commandLine.getSetOp() == null) { 549 System.err.println("No set operation specified"); 550 printUsage(); 551 System.exit(1); 552 } 553 554 if (commandLine.getListFile() != null) { 555 if (argv.length != argCount) { 556 printUsage(); 557 } 558 559 runBulk(commandLine); 560 } else{ 561 if (argv.length - argCount != 2) { 562 printUsage(); 563 } 564 565 String origFile = argv[argCount++]; 566 String newFile = argv[argCount++]; 567 568 runSinglePair(commandLine, origFile, newFile); 569 } 570 } 571 572 private static void runBulk(BugHistoryCommandLine commandLine) throws FileNotFoundException , IOException , DocumentException { 573 BufferedReader reader; 574 if (commandLine.getListFile().equals("-")) { 575 reader = new BufferedReader (new InputStreamReader (System.in)); 576 } else { 577 reader = new BufferedReader (new FileReader (commandLine.getListFile())); 578 } 579 int missing = 0; 580 try { 581 BugCollectionAndProjectCache cache = new BugCollectionAndProjectCache(); 582 583 584 String csvRecord; 585 while ((csvRecord = reader.readLine()) != null) { 586 csvRecord = csvRecord.trim(); 587 String [] tuple = csvRecord.split(","); 588 if (tuple.length < 2) 589 continue; 590 591 String origFile = tuple[0]; 592 String newFile = tuple[1]; 593 594 BugCollectionAndProject orig; 595 BugCollectionAndProject next; 596 597 try { 598 orig = cache.fetch(origFile); 599 next = cache.fetch(newFile); 600 } catch (RuntimeException e) { 601 throw e; 602 } catch (Exception e ) { 603 System.err.println("Warning: error reading bug collection: " + e.toString()); 604 ++missing; 605 continue; 606 } 607 608 if (commandLine.isVerbose()) { 609 System.out.print("Computing delta from " + origFile + " to " + newFile + "..."); 610 System.out.flush(); 611 } 612 613 BugHistory bugHistory = commandLine.createAndExecute( 614 orig.getBugCollection(), next.getBugCollection(), orig.getProject(), next.getProject()); 615 616 String outputFile = commandLine.getBulkOutputFileName(newFile); 617 if (commandLine.isVerbose()) { 618 System.out.print("Writing " + outputFile + "..."); 619 System.out.flush(); 620 } 621 622 623 bugHistory.writeResultCollection(orig.getProject(), next.getProject(), 624 new BufferedOutputStream (new FileOutputStream (outputFile))); 625 if (commandLine.isVerbose()) { 626 System.out.println("done"); 627 } 628 } 629 } finally { 630 reader.close(); 631 } 632 if (missing > 0) { 633 System.err.println(missing + " pairs skipped because of missing files"); 634 } 635 } 636 637 private static void runSinglePair(BugHistoryCommandLine commandLine, String origFile, String newFile) throws IOException , DocumentException { 638 Project origProject = new Project(); 639 Project newProject = new Project(); 640 BugHistory bugHistory = commandLine.createAndExecute(origFile, newFile, origProject, newProject); 641 642 if (commandLine.isCount()) { 643 System.out.println(bugHistory.getResultCollection().getCollection().size()); 644 } else { 645 OutputStream outputStream = System.out; 646 bugHistory.writeResultCollection(origProject, newProject, outputStream); 647 } 648 } 649 650 653 private static void printUsage() { 654 System.err.println("Usage: " + BugHistory.class.getName() + 655 " [options] <operation> <old results> <new results>"); 656 new BugHistoryCommandLine().printUsage(System.err); 657 System.exit(1); 658 } 659 } 660 661 | Popular Tags |