1 19 20 package org.netbeans.modules.versioning.system.cvss; 21 22 import org.netbeans.modules.versioning.util.ListenersSupport; 23 import org.netbeans.modules.versioning.util.VersioningListener; 24 import org.netbeans.modules.versioning.util.VersioningEvent; 25 import org.netbeans.lib.cvsclient.admin.AdminHandler; 26 import org.netbeans.lib.cvsclient.admin.Entry; 27 import org.netbeans.lib.cvsclient.command.*; 28 import org.netbeans.lib.cvsclient.command.add.AddCommand; 29 import org.netbeans.lib.cvsclient.connection.AuthenticationException; 30 import org.netbeans.lib.cvsclient.file.FileHandler; 31 import org.netbeans.modules.versioning.system.cvss.util.Utils; 32 import org.netbeans.modules.versioning.system.cvss.util.Context; 33 import org.netbeans.modules.versioning.system.cvss.ui.syncview.CvsSynchronizeTopComponent; 34 import org.netbeans.modules.versioning.spi.VCSAnnotator; 35 import org.netbeans.modules.versioning.spi.VCSInterceptor; 36 import org.netbeans.modules.versioning.spi.OriginalContent; 37 import org.netbeans.modules.versioning.VersioningManager; 38 import org.netbeans.api.queries.SharabilityQuery; 39 import org.openide.ErrorManager; 40 import org.openide.cookies.EditorCookie; 41 import org.openide.loaders.DataObject; 42 import org.openide.loaders.DataObjectNotFoundException; 43 import org.openide.util.RequestProcessor; 44 import org.openide.filesystems.*; 45 46 import javax.swing.*; 47 import java.io.*; 48 import java.util.*; 49 import java.util.regex.Pattern ; 50 import java.util.regex.PatternSyntaxException ; 51 import java.beans.PropertyChangeListener ; 52 53 59 public class CvsVersioningSystem { 60 61 private static CvsVersioningSystem instance; 62 63 public static final String FILENAME_CVSIGNORE = ".cvsignore"; public static final String FILENAME_CVS = "CVS"; 66 public static final Object EVENT_PARAM_CHANGED = new Object (); 67 public static final Object PARAM_BATCH_REFRESH_RUNNING = new Object (); 68 public static final Object EVENT_VERSIONED_FILES_CHANGED = new Object (); 69 70 public static final Object EVENT_REFRESH_ANNOTATIONS = new Object (); 71 72 private static final String FILENAME_CVS_REPOSITORY = FILENAME_CVS + "/Repository"; private static final String FILENAME_CVS_ENTRIES = FILENAME_CVS + "/Entries"; 75 78 private static final Set textExtensions = new HashSet(Arrays.asList(new String [] { "txt", "xml", "html", "properties", "mf", "jhm", "hs", "form" })); 80 private final Map clientsCache = new HashMap(); 81 private final Map params = new HashMap(); 82 83 private GlobalOptions defaultGlobalOptions; 84 private FileStatusCache fileStatusCache; 85 86 private CvsLiteAdminHandler sah; 87 private CvsLiteFileHandler workdirFileHandler; 88 private CvsLiteGzippedFileHandler workdirGzippedFileHandler; 89 private FilesystemHandler filesystemHandler; 90 private VCSAnnotator fileStatusProvider; 91 92 private Annotator annotator; 93 94 private final Set userIgnorePatterns = new HashSet(); 95 private boolean userIgnorePatternsReset; 96 private long userIgnorePatternsTimestamp; 97 98 private final Set<File> alreadyGeneratedFiles = new HashSet<File>(5); 99 100 public static synchronized CvsVersioningSystem getInstance() { 101 if (instance == null) { 102 instance = new CvsVersioningSystem(); 103 instance.init(); 104 } 105 return instance; 106 } 107 108 private void init() { 109 defaultGlobalOptions = CvsVersioningSystem.createGlobalOptions(); 110 sah = new CvsLiteAdminHandler(); 111 workdirFileHandler = new CvsLiteFileHandler(); 112 workdirGzippedFileHandler = new CvsLiteGzippedFileHandler(); 113 fileStatusCache = new FileStatusCache(this); 114 filesystemHandler = new FilesystemHandler(this); 115 annotator = new Annotator(this); 116 fileStatusProvider = new FileStatusProvider(); 117 cleanup(); 118 } 119 120 private void cleanup() { 121 RequestProcessor.getDefault().post(new Runnable () { 122 public void run() { 123 fileStatusCache.cleanUp(); 124 } 125 }, 3000); 126 } 127 128 void shutdown() { 129 SwingUtilities.invokeLater(new Runnable () { 130 public void run() { 131 try { 132 CvsSynchronizeTopComponent.getInstance().close(); 133 } catch (Throwable e) { 134 } 136 } 137 }); 138 } 139 140 private CvsVersioningSystem() { 141 } 142 143 public CvsFileTableModel getFileTableModel(Context context, int displayStatuses) { 144 return new CvsFileTableModel(context, displayStatuses); 145 } 146 147 153 public ClientRuntime getClientRuntime(String cvsRoot) { 154 155 cvsRoot.length(); 157 ClientRuntime clientRuntime; 158 synchronized(clientsCache) { 159 clientRuntime = (ClientRuntime) clientsCache.get(cvsRoot); 160 if (clientRuntime == null) { 161 clientRuntime = new ClientRuntime(cvsRoot); 162 clientsCache.put(cvsRoot, clientRuntime); 163 } 164 } 165 return clientRuntime; 166 } 167 168 175 String detectCvsRoot(Command cmd) throws NotVersionedException { 176 File [] files; 177 178 if (cmd instanceof AddCommand) { 179 AddCommand c = (AddCommand) cmd; 180 files = c.getFiles(); 181 } else if (cmd instanceof BasicCommand) { 182 BasicCommand c = (BasicCommand) cmd; 183 files = c.getFiles(); 184 } else { 185 throw new NotVersionedException("Cannot determine CVSRoot for command: " + cmd); } 187 188 File oneFile = files[0]; 189 try { 190 String cvsRoot = Utils.getCVSRootFor(oneFile); 191 return cvsRoot; 192 } catch (IOException e) { 193 throw new NotVersionedException("Cannot determine CVSRoot for: " + oneFile); } 195 196 } 197 198 208 public RequestProcessor.Task post(Command cmd, ExecutorSupport mgr) throws CommandException, 209 AuthenticationException, NotVersionedException, IllegalCommandException, 210 IOException { 211 return post(cmd, defaultGlobalOptions, mgr); 212 } 213 214 223 public RequestProcessor.Task post(Command cmd, GlobalOptions options, ExecutorSupport mgr) throws IllegalCommandException { 224 ClientRuntime clientRuntime = getClientRuntime(cmd, options); 225 RequestProcessor.Task task = clientRuntime.createTask(cmd, options != null ? options : defaultGlobalOptions, mgr); 226 task.schedule(0); 227 return task; 228 } 229 230 235 public ClientRuntime getClientRuntime(Command cmd, GlobalOptions options) { 236 String root; 237 if (options != null && options.getCVSRoot() != null) { 238 root = options.getCVSRoot(); 239 } else { 240 try { 241 root = detectCvsRoot(cmd); 242 } catch (NotVersionedException e) { 243 if (options == null) return null; 244 root = options.getCVSRoot(); 245 } 246 } 247 return getClientRuntime(root); 248 } 249 250 public FileStatusCache getStatusCache() { 251 return fileStatusCache; 252 } 253 254 ListenersSupport listenerSupport = new ListenersSupport(this); 255 public void addVersioningListener(VersioningListener listener) { 256 listenerSupport.addListener(listener); 257 } 258 259 public void removeVersioningListener(VersioningListener listener) { 260 listenerSupport.removeListener(listener); 261 } 262 263 270 boolean isIgnored(final File file) { 271 if (file.isDirectory()) { 272 File cvsRepository = new File(file, FILENAME_CVS_REPOSITORY); 273 if (cvsRepository.canRead()) return false; 274 } 275 String name = file.getName(); 276 277 if (FILENAME_CVSIGNORE.equals(name)) return false; 279 if (".nbintdb".equals(name)) { return true; 282 } 283 284 Set patterns = new HashSet(Arrays.asList(CvsModuleConfig.getDefault().getIgnoredFilePatterns())); 285 addUserPatterns(patterns); 286 addCvsIgnorePatterns(patterns, file.getParentFile()); 287 288 for (Iterator i = patterns.iterator(); i.hasNext();) { 289 Pattern pattern = (Pattern ) i.next(); 290 if (pattern.matcher(name).matches()) return true; 291 } 292 293 int sharability = SharabilityQuery.getSharability(file); 294 if (sharability == SharabilityQuery.NOT_SHARABLE) { 295 if (CvsVisibilityQuery.isHiddenFolder(file)) { 297 return false; 298 } 299 File cvsIgnoreFile = new File(file.getParentFile(), FILENAME_CVSIGNORE); 302 if (file.exists() && !cvsIgnoreFile.exists()) { 303 if (!alreadyGeneratedFiles.add(cvsIgnoreFile)) return true; 304 } 305 try { 306 setIgnored(file); 307 } catch (IOException e) { 308 } 310 return true; 311 } else { 312 return false; 313 } 314 } 315 316 private void addUserPatterns(Set patterns) { 317 File userIgnores = new File(System.getProperty("user.home"), FILENAME_CVSIGNORE); long lm = userIgnores.lastModified(); 319 if (lm > userIgnorePatternsTimestamp || lm == 0 && userIgnorePatternsTimestamp > 0) { 320 userIgnorePatternsTimestamp = lm; 321 parseUserPatterns(userIgnores); 322 } 323 if (userIgnorePatternsReset) { 324 patterns.clear(); 325 } 326 patterns.addAll(userIgnorePatterns); 327 } 328 329 private void parseUserPatterns(File userIgnores) { 330 userIgnorePatternsReset = false; 331 userIgnorePatterns.clear(); 332 BufferedReader r = null; 333 try { 334 r = new BufferedReader(new FileReader(userIgnores)); 335 String s; 336 while ((s = r.readLine()) != null) { 337 if ("!".equals(s)) { userIgnorePatternsReset = true; 339 userIgnorePatterns.clear(); 340 } else { 341 try { 342 userIgnorePatterns.add(sh2regex(s)); 343 } catch (IOException e) { 344 } 346 } 347 } 348 } catch (IOException e) { 349 } finally { 351 if (r != null) try { r.close(); } catch (IOException e) {} 352 } 353 } 354 355 362 private static Pattern sh2regex(String s) throws IOException { 363 s = s.replaceAll("\\.", "\\\\."); s = s.replaceAll("\\*", ".*"); s = s.replaceAll("\\?", "."); try { 368 return Pattern.compile(s); 369 } catch (PatternSyntaxException e) { 370 throw new IOException(e.getMessage()); 371 } 372 } 373 374 381 boolean isManaged(File file) { 382 return VersioningManager.getInstance().getOwner(file) instanceof CVS && !Utils.isPartOfCVSMetadata(file); 383 } 384 385 public void versionedFilesChanged() { 386 listenerSupport.fireVersioningEvent(EVENT_VERSIONED_FILES_CHANGED); 387 } 388 389 396 File getTopmostManagedParent(File file) { 397 if (Utils.isPartOfCVSMetadata(file)) { 398 for (;file != null; file = file.getParentFile()) { 399 if (file.isDirectory() && file.getName().equals(FILENAME_CVS)) { 400 file = file.getParentFile(); 401 break; 402 } 403 } 404 } 405 File topmost = null; 406 for (; file != null; file = file.getParentFile()) { 407 File repository = new File(file, FILENAME_CVS_REPOSITORY); 408 File entries = new File(file, FILENAME_CVS_ENTRIES); 409 if (repository.canRead() && entries.canRead()) { 410 topmost = file; 411 } 412 } 413 return topmost; 414 } 415 416 private void addCvsIgnorePatterns(Set patterns, File file) { 417 Set shPatterns; 418 try { 419 shPatterns = readCvsIgnoreEntries(file); 420 } catch (IOException e) { 421 return; 423 } 424 for (Iterator i = shPatterns.iterator(); i.hasNext();) { 425 String shPattern = (String ) i.next(); 426 if ("!".equals(shPattern)) { patterns.clear(); 428 } else { 429 try { 430 patterns.add(sh2regex(shPattern)); 431 } catch (IOException e) { 432 } 434 } 435 } 436 } 437 438 public boolean isInCvsIgnore(File file) { 439 try { 440 return readCvsIgnoreEntries(file.getParentFile()).contains(file.getName()); 441 } catch (IOException e) { 442 ErrorManager.getDefault().notify(e); 443 return false; 444 } 445 } 446 447 public boolean isIgnoredFilename(File file) { 448 if (FILENAME_CVS.equals(file.getName())) return true; 449 return false; 450 } 451 452 453 public AdminHandler getAdminHandler() { 454 return sah; 455 } 456 457 public FileHandler getFileHandler() { 458 return workdirFileHandler; 459 } 460 461 public FileHandler getGzippedFileHandler() { 462 return workdirGzippedFileHandler; 463 } 464 465 public Annotator getAnnotator() { 466 return annotator; 467 } 468 469 public Object getParameter(Object key) { 470 synchronized(params) { 471 return params.get(key); 472 } 473 } 474 475 public KeywordSubstitutionOptions getDefaultKeywordSubstitution(File file) { 476 return isText(file) || isBinary(file) == false ? 478 KeywordSubstitutionOptions.DEFAULT : 479 KeywordSubstitutionOptions.BINARY; 480 } 481 482 485 public boolean isText(File file) { 486 if (FILENAME_CVSIGNORE.equals(file.getName())) { 487 return true; 488 } 489 try { 491 Entry entry = sah.getEntry(file); 492 if (entry != null) { 493 return !entry.isBinary(); 494 } 495 } catch (IOException e) { 496 } 498 FileObject fo = FileUtil.toFileObject(file); 499 if (fo == null) return false; 500 try { 501 DataObject dao = DataObject.find(fo); 502 return dao.getCookie(EditorCookie.class) != null; 503 } catch (DataObjectNotFoundException e) { 504 } 506 if (fo.getMIMEType().startsWith("text")) { return true; 508 } 509 return textExtensions.contains(fo.getExt()); 511 } 512 513 517 public boolean isBinary(File file) { 518 InputStream in = null; 519 try { 520 in = new FileInputStream(file); 521 in = new BufferedInputStream(in); 522 for (int i = 0; i<1024; i++) { 523 int ch = in.read(); 524 if (ch == -1) break; 525 if (ch < 32 && ch != '\t' && ch != '\n' && ch != '\r') { 526 return true; 527 } 528 } 529 } catch (IOException e) { 530 ErrorManager err = ErrorManager.getDefault(); 531 err.notify(ErrorManager.INFORMATIONAL, e); 532 } finally { 533 if (in != null) { 534 try { 535 in.close(); 536 } catch (IOException alreadyClosed) { 537 } 538 } 539 } 540 return false; 541 } 542 543 public void setParameter(Object key, Object value) { 544 Object old; 545 synchronized(params) { 546 old = params.put(key, value); 547 } 548 if (old != value) listenerSupport.fireVersioningEvent(EVENT_PARAM_CHANGED, key); 549 } 550 551 556 public void setIgnored(File[] files) { 557 for (int i = 0; i < files.length; i++) { 558 try { 559 setIgnored(files[i]); 560 } catch (IOException e) { 561 ErrorManager.getDefault().notify(e); 562 } 563 } 564 } 565 566 571 private void setIgnored(File file) throws IOException { 572 if (file.exists()) { 573 addToCvsIgnore(file); 574 } 575 } 576 577 public void setNotignored(File[] files) { 578 for (int i = 0; i < files.length; i++) { 579 try { 580 removeFromCvsIgnore(files[i]); 581 } catch (IOException e) { 582 ErrorManager.getDefault().notify(e); 583 } 584 } 585 } 586 587 private void addToCvsIgnore(File file) throws IOException { 588 589 Set entries = readCvsIgnoreEntries(file.getParentFile()); 590 if (entries.add(file.getName())) { 591 writeCvsIgnoreEntries(file.getParentFile(), entries); 592 } 593 } 594 595 private void removeFromCvsIgnore(File file) throws IOException { 596 Set entries = readCvsIgnoreEntries(file.getParentFile()); 597 if (entries.remove(file.getName())) { 598 writeCvsIgnoreEntries(file.getParentFile(), entries); 599 } 600 } 601 602 private Set<String > readCvsIgnoreEntries(File directory) throws IOException { 603 File cvsIgnore = new File(directory, FILENAME_CVSIGNORE); 604 605 Set<String > entries = new HashSet<String >(5); 606 if (!cvsIgnore.canRead()) return entries; 607 608 String s; 609 BufferedReader r = null; 610 try { 611 r = new BufferedReader(new FileReader(cvsIgnore)); 612 while ((s = r.readLine()) != null) { 613 entries.addAll(Arrays.asList(s.trim().split(" "))); 614 } 615 } finally { 616 if (r != null) try { r.close(); } catch (IOException e) {} 617 } 618 return entries; 619 } 620 621 private void writeCvsIgnoreEntries(File directory, Set entries) throws IOException { 622 File cvsIgnore = new File(directory, FILENAME_CVSIGNORE); 623 FileObject fo = FileUtil.toFileObject(cvsIgnore); 624 625 if (entries.size() == 0) { 626 if (fo != null) fo.delete(); 627 return; 628 } 629 630 if (fo == null || !fo.isValid()) { 631 fo = FileUtil.toFileObject(directory); 632 fo = fo.createData(FILENAME_CVSIGNORE); 633 } 634 FileLock lock = fo.lock(); 635 PrintWriter w = null; 636 try { 637 w = new PrintWriter(fo.getOutputStream(lock)); 638 for (Iterator i = entries.iterator(); i.hasNext();) { 639 w.println(i.next()); 640 } 641 } finally { 642 lock.releaseLock(); 643 if (w != null) w.close(); 644 } 645 } 646 647 648 public static void ignoreFilesystemEvents(boolean ignore) { 649 FilesystemHandler.ignoreEvents(ignore); 650 } 651 652 658 public static GlobalOptions createGlobalOptions() { 659 GlobalOptions globalOptions = new GlobalOptions(); 660 if (System.getProperty("cvsClientLog") == null) { int gzipLevel = 4; 662 String level = System.getProperty("netbeans.experimental.cvs.io.compressionLevel"); if (level != null) { 664 try { 665 int candidate = Integer.parseInt(level); 666 if (0 <= candidate && candidate < 10) { 667 gzipLevel = candidate; 668 } 669 } catch (NumberFormatException ex) { 670 } 672 } 673 if (gzipLevel > 0) { 674 globalOptions.setCompressionLevel(gzipLevel); 675 } 676 } 677 return globalOptions; 678 } 679 680 public VCSAnnotator getVCSAnnotator() { 681 return fileStatusProvider; 682 } 683 684 public VCSInterceptor getVCSInterceptor() { 685 return filesystemHandler; 686 } 687 688 private static final int STATUS_DIFFABLE = 689 FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY | 690 FileInformation.STATUS_VERSIONED_ADDEDLOCALLY | 691 FileInformation.STATUS_VERSIONED_UPTODATE | 692 FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY | 693 FileInformation.STATUS_VERSIONED_MODIFIEDINREPOSITORY | 694 FileInformation.STATUS_VERSIONED_CONFLICT | 695 FileInformation.STATUS_VERSIONED_MERGE | 696 FileInformation.STATUS_VERSIONED_REMOVEDINREPOSITORY | 697 FileInformation.STATUS_VERSIONED_MODIFIEDINREPOSITORY | 698 FileInformation.STATUS_VERSIONED_MODIFIEDINREPOSITORY; 699 700 701 public OriginalContent getVCSOriginalContent(File file) { 702 FileInformation info = fileStatusCache.getStatus(file); 703 if ((info.getStatus() & STATUS_DIFFABLE) == 0) return null; 704 return new CvsOriginalContent(file); 705 } 706 707 public void refreshAllAnnotations() { 708 listenerSupport.fireVersioningEvent(EVENT_REFRESH_ANNOTATIONS); 709 } 710 711 private class CvsOriginalContent extends OriginalContent implements VersioningListener { 712 713 public CvsOriginalContent(File working) { 714 super(working); 715 } 716 717 protected void getOriginalFiles(File destination, Set<File> files) throws Exception { 718 for (File file : files) { 719 File original = VersionsCache.getInstance().getRemoteFile(file, VersionsCache.REVISION_BASE, null, true); 721 if (original == null) throw new IOException("Unable to get BASE revision of " + file); 722 723 File daoFile = new File(destination, file.getName()); 724 org.netbeans.modules.versioning.util.Utils.copyStreamsCloseAll(new FileOutputStream(daoFile), new FileInputStream(original)); 725 daoFile.deleteOnExit(); 726 } 727 } 728 729 public void versioningEvent(VersioningEvent event) { 730 if (FileStatusCache.EVENT_FILE_STATUS_CHANGED == event.getId()) { 731 File eventFile = (File) event.getParams()[0]; 732 if (eventFile.equals(workingCopy)) { 733 support.firePropertyChange(PROP_CONTENT_CHANGED, null, null); 734 } 735 } 736 } 737 738 public void addPropertyChangeListener(PropertyChangeListener listener) { 739 if (!support.hasListeners(null)) { 740 fileStatusCache.addVersioningListener(this); 741 } 742 super.addPropertyChangeListener(listener); 743 } 744 745 public void removePropertyChangeListener(PropertyChangeListener listener) { 746 super.removePropertyChangeListener(listener); 747 if (!support.hasListeners(null)) { 748 fileStatusCache.removeVersioningListener(this); 749 } 750 } 751 } 752 } | Popular Tags |