1 12 package org.eclipse.compare.internal.patch; 13 14 import java.io.*; 15 import java.util.*; 16 17 import org.eclipse.compare.internal.CompareUIPlugin; 18 import org.eclipse.compare.internal.Utilities; 19 import org.eclipse.compare.patch.PatchConfiguration; 20 import org.eclipse.compare.structuremergeviewer.Differencer; 21 import org.eclipse.core.resources.*; 22 import org.eclipse.core.runtime.*; 23 import org.eclipse.swt.SWT; 24 import org.eclipse.swt.widgets.Shell; 25 26 32 public class Patcher { 33 34 static protected final String REJECT_FILE_EXTENSION= ".rej"; 36 static protected final String MARKER_TYPE= "org.eclipse.compare.rejectedPatchMarker"; 38 41 public static final String PROP_PATCHER = "org.eclipse.compare.patcher"; 43 49 private FileDiff[] fDiffs; 50 private IResource fTarget; 51 private Set disabledElements = new HashSet(); 53 private Map diffResults = new HashMap(); 54 private final Map contentCache = new HashMap(); 55 private Set mergedHunks = new HashSet(); 56 57 private final PatchConfiguration configuration; 58 private boolean fGenerateRejectFile = false; 59 60 public Patcher() { 61 configuration = new PatchConfiguration(); 62 configuration.setProperty(PROP_PATCHER, this); 63 } 64 65 69 public FileDiff[] getDiffs() { 70 if (fDiffs == null) 71 return new FileDiff[0]; 72 return fDiffs; 73 } 74 75 public IPath getPath(FileDiff diff) { 76 return diff.getStrippedPath(getStripPrefixSegments(), isReversed()); 77 } 78 79 82 boolean setStripPrefixSegments(int strip) { 83 if (strip != getConfiguration().getPrefixSegmentStripCount()) { 84 getConfiguration().setPrefixSegmentStripCount(strip); 85 return true; 86 } 87 return false; 88 } 89 90 int getStripPrefixSegments() { 91 return getConfiguration().getPrefixSegmentStripCount(); 92 } 93 94 97 boolean setFuzz(int fuzz) { 98 if (fuzz != getConfiguration().getFuzz()) { 99 getConfiguration().setFuzz(fuzz); 100 return true; 101 } 102 return false; 103 } 104 105 int getFuzz(){ 106 return getConfiguration().getFuzz(); 107 } 108 109 112 boolean setIgnoreWhitespace(boolean ignoreWhitespace) { 113 if (ignoreWhitespace != getConfiguration().isIgnoreWhitespace()) { 114 getConfiguration().setIgnoreWhitespace(ignoreWhitespace); 115 return true; 116 } 117 return false; 118 } 119 120 boolean isIgnoreWhitespace() { 121 return getConfiguration().isIgnoreWhitespace(); 122 } 123 124 public boolean isGenerateRejectFile() { 125 return fGenerateRejectFile; 126 } 127 128 public void setGenerateRejectFile(boolean generateRejectFile) { 129 fGenerateRejectFile = generateRejectFile; 130 } 131 132 134 public void parse(IStorage storage) throws IOException, CoreException { 135 BufferedReader reader = createReader(storage); 136 try { 137 parse(reader); 138 } finally { 139 try { 140 reader.close(); 141 } catch (IOException e) { } 143 } 144 } 145 146 public static BufferedReader createReader(IStorage storage) throws CoreException { 147 return new BufferedReader(new InputStreamReader(storage.getContents())); 148 } 149 150 public void parse(BufferedReader reader) throws IOException { 151 PatchReader patchReader= new PatchReader(); 152 patchReader.parse(reader); 153 patchParsed(patchReader); 154 } 155 156 protected void patchParsed(PatchReader patchReader) { 157 fDiffs = patchReader.getDiffs(); 158 } 159 160 162 public void applyAll(IProgressMonitor pm, Shell shell, String title) throws CoreException { 163 164 final int WORK_UNIT= 10; 165 166 int i; 167 168 IFile singleFile= null; IContainer container= null; 170 if (fTarget instanceof IContainer) 171 container= (IContainer) fTarget; 172 else if (fTarget instanceof IFile) { 173 singleFile= (IFile) fTarget; 174 container= singleFile.getParent(); 175 } else { 176 Assert.isTrue(false); 177 } 178 179 List list= new ArrayList(); 181 if (singleFile != null) 182 list.add(singleFile); 183 else { 184 for (i= 0; i < fDiffs.length; i++) { 185 FileDiff diff= fDiffs[i]; 186 if (isEnabled(diff)) { 187 switch (diff.getDiffType(isReversed())) { 188 case Differencer.CHANGE: 189 list.add(createPath(container, getPath(diff))); 190 break; 191 } 192 } 193 } 194 } 195 if (! Utilities.validateResources(list, shell, title)) 196 return; 197 198 if (pm != null) { 199 String message= PatchMessages.Patcher_Task_message; 200 pm.beginTask(message, fDiffs.length*WORK_UNIT); 201 } 202 203 for (i= 0; i < fDiffs.length; i++) { 204 205 int workTicks= WORK_UNIT; 206 207 FileDiff diff= fDiffs[i]; 208 if (isEnabled(diff)) { 209 210 IPath path= getPath(diff); 211 if (pm != null) 212 pm.subTask(path.toString()); 213 214 IFile file= singleFile != null 215 ? singleFile 216 : createPath(container, path); 217 218 List failed= new ArrayList(); 219 220 int type= diff.getDiffType(isReversed()); 221 switch (type) { 222 case Differencer.ADDITION: 223 List result= apply(diff, file, true, failed); 225 if (result != null) 226 store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); 227 workTicks-= WORK_UNIT; 228 break; 229 case Differencer.DELETION: 230 file.delete(true, true, new SubProgressMonitor(pm, workTicks)); 231 workTicks-= WORK_UNIT; 232 break; 233 case Differencer.CHANGE: 234 result= apply(diff, file, false, failed); 236 if (result != null) 237 store(createString(isPreserveLineDelimeters(), result), file, new SubProgressMonitor(pm, workTicks)); 238 workTicks-= WORK_UNIT; 239 break; 240 } 241 242 if (isGenerateRejectFile() && failed.size() > 0) { 243 IPath pp = getRejectFilePath(path); 244 file= createPath(container, pp); 245 if (file != null) { 246 store(getRejected(failed), file, pm); 247 try { 248 IMarker marker= file.createMarker(MARKER_TYPE); 249 marker.setAttribute(IMarker.MESSAGE, PatchMessages.Patcher_Marker_message); 250 marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); 251 } catch (CoreException ex) { 252 } 254 } 255 } 256 } 257 258 if (pm != null) { 259 if (pm.isCanceled()) 260 break; 261 if (workTicks > 0) 262 pm.worked(workTicks); 263 } 264 } 265 } 266 267 private IPath getRejectFilePath(IPath path) { 268 IPath pp= null; 269 if (path.segmentCount() > 1) { 270 pp= path.removeLastSegments(1); 271 pp= pp.append(path.lastSegment() + REJECT_FILE_EXTENSION); 272 } else 273 pp= new Path(path.lastSegment() + REJECT_FILE_EXTENSION); 274 return pp; 275 } 276 277 281 public static List load(IStorage file, boolean create) { 282 List lines= null; 283 if (!create && file != null && exists(file)) { 284 String charset = Utilities.getCharset(file); 286 InputStream is= null; 287 try { 288 is= file.getContents(); 289 290 Reader streamReader= null; 291 try { 292 streamReader= new InputStreamReader(is, charset); 293 } catch (UnsupportedEncodingException x) { 294 streamReader= new InputStreamReader(is); 296 } 297 298 BufferedReader reader= new BufferedReader(streamReader); 299 lines = readLines(reader); 300 } catch(CoreException ex) { 301 CompareUIPlugin.log(ex); 303 } finally { 304 if (is != null) 305 try { 306 is.close(); 307 } catch(IOException ex) { 308 } 310 } 311 } 312 313 if (lines == null) 314 lines= new ArrayList(); 315 return lines; 316 } 317 318 private static boolean exists(IStorage file) { 319 if (file instanceof IFile) { 320 return ((IFile) file).exists(); 321 } 322 return true; 323 } 324 325 private static List readLines(BufferedReader reader) { 326 List lines; 327 LineReader lr= new LineReader(reader); 328 if (!"carbon".equals(SWT.getPlatform())) lr.ignoreSingleCR(); 330 lines= lr.readLines(); 331 return lines; 332 } 333 334 List apply(FileDiff diff, IFile file, boolean create, List failedHunks) { 335 FileDiffResult result = getDiffResult(diff); 336 List lines = Patcher.load(file, create); 337 result.patch(lines, null); 338 failedHunks.addAll(result.getFailedHunks()); 339 if (hasCachedContents(diff)) { 340 return getCachedLines(diff); 342 } else if (!result.hasMatches()) { 343 return null; 345 } 346 return result.getLines(); 347 } 348 349 352 protected void store(String contents, IFile file, IProgressMonitor pm) throws CoreException { 353 354 byte[] bytes; 355 try { 356 bytes= contents.getBytes(Utilities.getCharset(file)); 357 } catch (UnsupportedEncodingException x) { 358 bytes= contents.getBytes(); 360 } 361 362 store(bytes,file, pm); 363 } 364 365 protected void store(byte[] bytes, IFile file, IProgressMonitor pm) throws CoreException { 366 InputStream is= new ByteArrayInputStream(bytes); 367 try { 368 if (file.exists()) { 369 file.setContents(is, false, true, pm); 370 } else { 371 file.create(is, false, pm); 372 } 373 } finally { 374 if (is != null) 375 try { 376 is.close(); 377 } catch(IOException ex) { 378 } 380 } 381 } 382 383 384 385 388 public static String createString(boolean preserveLineDelimeters, List lines) { 389 StringBuffer sb= new StringBuffer (); 390 Iterator iter= lines.iterator(); 391 if (preserveLineDelimeters) { 392 while (iter.hasNext()) 393 sb.append((String )iter.next()); 394 } else { 395 String lineSeparator= System.getProperty("line.separator"); while (iter.hasNext()) { 397 String line= (String )iter.next(); 398 int l= length(line); 399 if (l < line.length()) { sb.append(line.substring(0, l)); 401 sb.append(lineSeparator); 402 } else { 403 sb.append(line); 404 } 405 } 406 } 407 return sb.toString(); 408 } 409 410 protected boolean isPreserveLineDelimeters() { 411 return false; 412 } 413 414 public static String getRejected(List failedHunks) { 415 if (failedHunks.size() <= 0) 416 return null; 417 418 String lineSeparator= System.getProperty("line.separator"); StringBuffer sb= new StringBuffer (); 420 Iterator iter= failedHunks.iterator(); 421 while (iter.hasNext()) { 422 Hunk hunk= (Hunk) iter.next(); 423 sb.append(hunk.getRejectedDescription()); 424 sb.append(lineSeparator); 425 sb.append(hunk.getContent()); 426 } 427 return sb.toString(); 428 } 429 430 434 protected IFile createPath(IContainer container, IPath path) throws CoreException { 435 if (path.segmentCount() > 1) { 436 IContainer childContainer; 437 if (container instanceof IWorkspaceRoot) { 438 IProject project = ((IWorkspaceRoot)container).getProject(path.segment(0)); 439 if (!project.exists()) 440 project.create(null); 441 if (!project.isOpen()) 442 project.open(null); 443 childContainer = project; 444 } else { 445 IFolder f= container.getFolder(path.uptoSegment(1)); 446 if (!f.exists()) 447 f.create(false, true, null); 448 childContainer = f; 449 } 450 return createPath(childContainer, path.removeFirstSegments(1)); 451 } 452 return container.getFile(path); 454 } 455 456 460 static int length(String s) { 461 int l= s.length(); 462 if (l > 0) { 463 char c= s.charAt(l-1); 464 if (c == '\r') 465 return l-1; 466 if (c == '\n') { 467 if (l > 1 && s.charAt(l-2) == '\r') 468 return l-2; 469 return l-1; 470 } 471 } 472 return l; 473 } 474 475 public IResource getTarget() { 476 return fTarget; 477 } 478 479 public void setTarget(IResource target) { 480 fTarget= target; 481 } 482 483 484 protected IFile getTargetFile(FileDiff diff) { 485 IPath path = diff.getStrippedPath(getStripPrefixSegments(), isReversed()); 486 return existsInTarget(path); 487 } 488 489 495 public IFile existsInTarget(IPath path) { 496 if (fTarget instanceof IFile) { IFile file= (IFile) fTarget; 498 if (matches(file.getFullPath(), path)) 499 return file; 500 } else if (fTarget instanceof IContainer) { 501 IContainer c= (IContainer) fTarget; 502 if (c.exists(path)) 503 return c.getFile(path); 504 } 505 return null; 506 } 507 508 514 private boolean matches(IPath fullpath, IPath path) { 515 for (IPath p= fullpath; path.segmentCount()<=p.segmentCount(); p= p.removeFirstSegments(1)) { 516 if (p.equals(path)) 517 return true; 518 } 519 return false; 520 } 521 522 public int calculatePrefixSegmentCount() { 523 int length= 99; 526 if (fDiffs!=null) 527 for (int i= 0; i<fDiffs.length; i++) { 528 FileDiff diff= fDiffs[i]; 529 length= Math.min(length, diff.segmentCount()); 530 } 531 return length; 532 } 533 534 public void addDiff(FileDiff newDiff){ 535 FileDiff[] temp = new FileDiff[fDiffs.length + 1]; 536 System.arraycopy(fDiffs,0, temp, 0, fDiffs.length); 537 temp[fDiffs.length] = newDiff; 538 fDiffs = temp; 539 } 540 541 public void removeDiff(FileDiff diffToRemove){ 542 FileDiff[] temp = new FileDiff[fDiffs.length - 1]; 543 int counter = 0; 544 for (int i = 0; i < fDiffs.length; i++) { 545 if (fDiffs[i] != diffToRemove){ 546 temp[counter++] = fDiffs[i]; 547 } 548 } 549 fDiffs = temp; 550 } 551 552 public void setEnabled(Object element, boolean enabled) { 553 if (element instanceof DiffProject) 554 setEnabledProject((DiffProject) element, enabled); 555 if (element instanceof FileDiff) 556 setEnabledFile((FileDiff)element, enabled); 557 if (element instanceof Hunk) 558 setEnabledHunk((Hunk) element, enabled); 559 } 560 561 private void setEnabledProject(DiffProject projectDiff, boolean enabled) { 562 FileDiff[] diffFiles = projectDiff.getFileDiffs(); 563 for (int i = 0; i < diffFiles.length; i++) { 564 setEnabledFile(diffFiles[i], enabled); 565 } 566 } 567 568 private void setEnabledFile(FileDiff fileDiff, boolean enabled) { 569 Hunk[] hunks = fileDiff.getHunks(); 570 for (int i = 0; i < hunks.length; i++) { 571 setEnabledHunk(hunks[i], enabled); 572 } 573 } 574 575 private void setEnabledHunk(Hunk hunk, boolean enabled) { 576 if (enabled) { 577 disabledElements.remove(hunk); 578 FileDiff file = hunk.getParent(); 579 disabledElements.remove(file); 580 DiffProject project = file.getProject(); 581 if (project != null) 582 disabledElements.remove(project); 583 } else { 584 disabledElements.add(hunk); 585 FileDiff file = hunk.getParent(); 586 if (disabledElements.containsAll(Arrays.asList(file.getHunks()))) { 587 disabledElements.add(file); 588 DiffProject project = file.getProject(); 589 if (project != null 590 && disabledElements.containsAll(Arrays.asList(project 591 .getFileDiffs()))) 592 disabledElements.add(project); 593 } 594 } 595 } 596 597 public boolean isEnabled(Object element) { 598 if (disabledElements.contains(element)) 599 return false; 600 Object parent = getElementParent(element); 601 if (parent == null) 602 return true; 603 return isEnabled(parent); 604 } 605 606 protected Object getElementParent(Object element) { 607 if (element instanceof Hunk) { 608 Hunk hunk = (Hunk) element; 609 return hunk.getParent(); 610 } 611 return null; 612 } 613 614 619 public int guessFuzzFactor(IProgressMonitor monitor) { 620 try { 621 monitor.beginTask(PatchMessages.PreviewPatchPage_GuessFuzzProgress_text, IProgressMonitor.UNKNOWN); 622 FileDiff[] diffs= getDiffs(); 623 if (diffs==null||diffs.length<=0) 624 return -1; 625 int fuzz= -1; 626 for (int i= 0; i<diffs.length; i++) { 627 FileDiff d= diffs[i]; 628 IFile file= getTargetFile(d); 629 if (file != null && file.exists()) { 630 List lines= load(file, false); 631 FileDiffResult result = getDiffResult(d); 632 int f = result.calculateFuzz(lines, monitor); 633 if (f > fuzz) 634 fuzz = f; 635 } 636 } 637 return fuzz; 638 } finally { 639 monitor.done(); 640 } 641 } 642 643 public void refresh() { 644 diffResults.clear(); 645 refresh(getDiffs()); 646 } 647 648 protected void refresh(FileDiff[] diffs) { 649 for (int i = 0; i < diffs.length; i++) { 650 FileDiff diff = diffs[i]; 651 FileDiffResult result = getDiffResult(diff); 652 ((WorkspaceFileDiffResult)result).refresh(); 653 } 654 } 655 656 public FileDiffResult getDiffResult(FileDiff diff) { 657 FileDiffResult result = (FileDiffResult)diffResults.get(diff); 658 if (result == null) { 659 result = new WorkspaceFileDiffResult(diff, getConfiguration()); 660 diffResults.put(diff, result); 661 } 662 return result; 663 } 664 665 public PatchConfiguration getConfiguration() { 666 return configuration; 667 } 668 669 675 public DiffProject getProject(FileDiff diff) { 676 return diff.getProject(); 677 } 678 679 682 public boolean setReversed(boolean reverse) { 683 if (getConfiguration().isReversed() != reverse) { 684 getConfiguration().setReversed(reverse); 685 refresh(); 686 return true; 687 } 688 return false; 689 } 690 691 public boolean isReversed() { 692 return getConfiguration().isReversed(); 693 } 694 695 703 public void cacheContents(FileDiff diff, byte[] contents) { 704 contentCache.put(diff, contents); 705 } 706 707 714 public boolean hasCachedContents(FileDiff diff) { 715 return contentCache.containsKey(diff); 716 } 717 718 724 public List getCachedLines(FileDiff diff) { 725 byte[] contents = (byte[])contentCache.get(diff); 726 if (contents != null) { 727 BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(contents))); 728 return readLines(reader); 729 } 730 return null; 731 } 732 733 740 public byte[] getCachedContents(FileDiff diff) { 741 return (byte[])contentCache.get(diff); 742 } 743 744 748 public boolean hasCachedContents() { 749 return !contentCache.isEmpty(); 750 } 751 752 755 public void clearCachedContents() { 756 contentCache.clear(); 757 mergedHunks.clear(); 758 } 759 760 public void setProperty(String key, Object value) { 761 getConfiguration().setProperty(key, value); 762 } 763 764 public Object getProperty(String key) { 765 return getConfiguration().getProperty(key); 766 } 767 768 public boolean isManuallyMerged(Hunk hunk) { 769 return mergedHunks.contains(hunk); 770 } 771 772 public void setManuallyMerged(Hunk hunk, boolean merged) { 773 if (merged) 774 mergedHunks.add(hunk); 775 else 776 mergedHunks.remove(hunk); 777 } 778 779 public IProject getTargetProject(FileDiff diff) { 780 DiffProject dp = getProject(diff); 781 if (dp != null) 782 return dp.getProject(); 783 IResource tr = getTarget(); 784 if (tr instanceof IWorkspaceRoot) { 785 IWorkspaceRoot root = (IWorkspaceRoot) tr; 786 return root.getProject(diff.getPath(isReversed()).segment(0)); 787 } 788 return tr.getProject(); 789 } 790 791 public static Patcher getPatcher(PatchConfiguration configuration) { 792 return (Patcher)configuration.getProperty(PROP_PATCHER); 793 } 794 795 public boolean hasRejects() { 796 for (Iterator iterator = diffResults.values().iterator(); iterator.hasNext();) { 797 FileDiffResult result = (FileDiffResult) iterator.next(); 798 if (result.hasRejects()) 799 return true; 800 } 801 return false; 802 } 803 } 804 | Popular Tags |