1 19 20 package org.netbeans.modules.versioning.system.cvss.ui.actions.diff; 21 22 import java.io.BufferedReader ; 23 import java.io.BufferedWriter ; 24 import java.io.File ; 25 import java.io.FileInputStream ; 26 import java.io.FileReader ; 27 import java.io.FileWriter ; 28 import java.io.FilterWriter ; 29 import java.io.IOException ; 30 import java.io.InputStreamReader ; 31 import java.io.Reader ; 32 import java.io.Writer ; 33 import java.util.ArrayList ; 34 import java.util.Set ; 35 import java.util.Iterator ; 36 import java.awt.*; 37 import org.netbeans.lib.cvsclient.file.*; 38 39 import org.openide.DialogDisplayer; 40 import org.openide.ErrorManager; 41 import org.openide.windows.TopComponent; 42 import org.openide.filesystems.FileLock; 43 import org.openide.filesystems.FileObject; 44 import org.openide.filesystems.FileUtil; 45 import org.openide.filesystems.FileAlreadyLockedException; 46 import org.openide.util.Lookup; 47 48 import org.netbeans.api.diff.Difference; 49 import org.netbeans.api.diff.StreamSource; 50 import org.netbeans.spi.diff.MergeVisualizer; 51 import org.netbeans.modules.diff.EncodedReaderFactory; 52 53 import javax.swing.*; 54 55 63 public class ResolveConflictsExecutor { 64 65 private static final String TMP_PREFIX = "merge"; 67 static final String CHANGE_LEFT = "<<<<<<< "; static final String CHANGE_RIGHT = ">>>>>>> "; static final String CHANGE_DELIMETER = "======="; 71 private String leftFileRevision = null; 72 private String rightFileRevision = null; 73 74 public void exec(File file) { 75 assert SwingUtilities.isEventDispatchThread(); 76 MergeVisualizer merge = (MergeVisualizer) Lookup.getDefault().lookup(MergeVisualizer.class); 77 if (merge == null) { 78 throw new IllegalStateException ("No Merge engine found."); } 80 81 try { 82 FileObject fo = FileUtil.toFileObject(file); 83 handleMergeFor(file, fo, fo.lock(), merge); 84 } catch (FileAlreadyLockedException e) { 85 Set components = TopComponent.getRegistry().getOpened(); 86 for (Iterator i = components.iterator(); i.hasNext();) { 87 TopComponent tc = (TopComponent) i.next(); 88 if (tc.getClientProperty(ResolveConflictsExecutor.class.getName()) != null) { 89 tc.requestActive(); 90 } 91 } 92 } catch (IOException ioex) { 93 org.openide.ErrorManager.getDefault().notify(ioex); 94 } 95 } 96 97 private void handleMergeFor(final File file, FileObject fo, FileLock lock, 98 final MergeVisualizer merge) throws IOException { 99 String mimeType = (fo == null) ? "text/plain" : fo.getMIMEType(); String ext = "."+fo.getExt(); File f1 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext)); 102 File f2 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext)); 103 File f3 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext)); 104 f1.deleteOnExit(); 105 f2.deleteOnExit(); 106 f3.deleteOnExit(); 107 108 final Difference[] diffs = copyParts(true, file, f1, true); 109 if (diffs.length == 0) { 110 DialogDisplayer.getDefault ().notify (new org.openide.NotifyDescriptor.Message( 111 org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "NoConflictsInFile", file))); 112 return ; 113 } 114 copyParts(false, file, f2, false); 115 String originalLeftFileRevision = leftFileRevision; 117 String originalRightFileRevision = rightFileRevision; 118 if (leftFileRevision != null) leftFileRevision.trim(); 119 if (rightFileRevision != null) rightFileRevision.trim(); 120 if (leftFileRevision == null || leftFileRevision.equals(file.getName())) { 121 leftFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleWorkingFile"); 122 } else { 123 leftFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleRevision", leftFileRevision); 124 } 125 if (rightFileRevision == null || rightFileRevision.equals(file.getName())) { 126 rightFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleWorkingFile"); 127 } else { 128 rightFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleRevision", rightFileRevision); 129 } 130 131 final StreamSource s1; 132 final StreamSource s2; 133 String encoding = EncodedReaderFactory.getDefault().getEncoding(fo); 134 if (encoding != null) { 135 s1 = StreamSource.createSource(file.getName(), leftFileRevision, mimeType, new InputStreamReader (new FileInputStream (f1), encoding)); 136 s2 = StreamSource.createSource(file.getName(), rightFileRevision, mimeType, new InputStreamReader (new FileInputStream (f2), encoding)); 137 } else { 138 s1 = StreamSource.createSource(file.getName(), leftFileRevision, mimeType, f1); 139 s2 = StreamSource.createSource(file.getName(), rightFileRevision, mimeType, f2); 140 } 141 final StreamSource result = new MergeResultWriterInfo(f1, f2, f3, file, mimeType, 142 originalLeftFileRevision, 143 originalRightFileRevision, 144 fo, lock, encoding); 145 146 try { 147 Component c = merge.createView(diffs, s1, s2, result); 148 if (c instanceof TopComponent) { 149 ((TopComponent) c).putClientProperty(ResolveConflictsExecutor.class.getName(), Boolean.TRUE); 150 } 151 } catch (IOException ioex) { 152 org.openide.ErrorManager.getDefault().notify(ioex); 153 } 154 } 155 156 159 private Difference[] copyParts(boolean generateDiffs, File source, 160 File dest, boolean leftPart) throws IOException { 161 BufferedReader r = new BufferedReader (new FileReader (source)); 163 BufferedWriter w = new BufferedWriter (new FileWriter (dest)); 164 ArrayList diffList = null; 165 if (generateDiffs) { 166 diffList = new ArrayList (); 167 } 168 try { 169 String line; 170 boolean isChangeLeft = false; 171 boolean isChangeRight = false; 172 int f1l1 = 0, f1l2 = 0, f2l1 = 0, f2l2 = 0; 173 StringBuffer text1 = new StringBuffer (); 174 StringBuffer text2 = new StringBuffer (); 175 int i = 1, j = 1; 176 while ((line = r.readLine()) != null) { 177 if (line.startsWith(CHANGE_LEFT)) { 178 if (generateDiffs) { 179 if (leftFileRevision == null) { 180 leftFileRevision = line.substring(CHANGE_LEFT.length()); 181 } 182 if (isChangeLeft) { 183 f1l2 = i - 1; 184 diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD, 185 f1l1 - 1, 0, f2l1, f2l2, 186 text1.toString(), 187 text2.toString()) : 188 (f2l1 > f2l2) ? new Difference(Difference.DELETE, 189 f1l1, f1l2, f2l1 - 1, 0, 190 text1.toString(), 191 text2.toString()) 192 : new Difference(Difference.CHANGE, 193 f1l1, f1l2, f2l1, f2l2, 194 text1.toString(), 195 text2.toString())); 196 f1l1 = f1l2 = f2l1 = f2l2 = 0; 197 text1.delete(0, text1.length()); 198 text2.delete(0, text2.length()); 199 } else { 200 f1l1 = i; 201 } 202 } 203 isChangeLeft = !isChangeLeft; 204 continue; 205 } else if (line.startsWith(CHANGE_RIGHT)) { 206 if (generateDiffs) { 207 if (rightFileRevision == null) { 208 rightFileRevision = line.substring(CHANGE_RIGHT.length()); 209 } 210 if (isChangeRight) { 211 f2l2 = j - 1; 212 diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD, 213 f1l1 - 1, 0, f2l1, f2l2, 214 text1.toString(), 215 text2.toString()) : 216 (f2l1 > f2l2) ? new Difference(Difference.DELETE, 217 f1l1, f1l2, f2l1 - 1, 0, 218 text1.toString(), 219 text2.toString()) 220 : new Difference(Difference.CHANGE, 221 f1l1, f1l2, f2l1, f2l2, 222 text1.toString(), 223 text2.toString())); 224 230 f1l1 = f1l2 = f2l1 = f2l2 = 0; 231 text1.delete(0, text1.length()); 232 text2.delete(0, text2.length()); 233 } else { 234 f2l1 = j; 235 } 236 } 237 isChangeRight = !isChangeRight; 238 continue; 239 } else if (isChangeRight && line.indexOf(CHANGE_RIGHT) != -1) { 240 String lineText = line.substring(0, line.lastIndexOf(CHANGE_RIGHT)); 241 if (generateDiffs) { 242 if (rightFileRevision == null) { 243 rightFileRevision = line.substring(line.lastIndexOf(CHANGE_RIGHT) + CHANGE_RIGHT.length()); 244 } 245 text2.append(lineText); 246 f2l2 = j; 247 diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD, 248 f1l1 - 1, 0, f2l1, f2l2, 249 text1.toString(), 250 text2.toString()) : 251 (f2l1 > f2l2) ? new Difference(Difference.DELETE, 252 f1l1, f1l2, f2l1 - 1, 0, 253 text1.toString(), 254 text2.toString()) 255 : new Difference(Difference.CHANGE, 256 f1l1, f1l2, f2l1, f2l2, 257 text1.toString(), 258 text2.toString())); 259 f1l1 = f1l2 = f2l1 = f2l2 = 0; 260 text1.delete(0, text1.length()); 261 text2.delete(0, text2.length()); 262 } 263 if (!leftPart) { 264 w.write(lineText); 265 w.newLine(); 266 } 267 isChangeRight = !isChangeRight; 268 continue; 269 } else if (line.equals(CHANGE_DELIMETER)) { 270 if (isChangeLeft) { 271 isChangeLeft = false; 272 isChangeRight = true; 273 f1l2 = i - 1; 274 f2l1 = j; 275 continue; 276 } else if (isChangeRight) { 277 isChangeRight = false; 278 isChangeLeft = true; 279 f2l2 = j - 1; 280 f1l1 = i; 281 continue; 282 } 283 } else if (line.endsWith(CHANGE_DELIMETER)) { 284 String lineText = line.substring(0, line.length() - CHANGE_DELIMETER.length()) + "\n"; if (isChangeLeft) { 286 text1.append(lineText); 287 if (leftPart) { 288 w.write(lineText); 289 w.newLine(); 290 } 291 isChangeLeft = false; 292 isChangeRight = true; 293 f1l2 = i; 294 f2l1 = j; 295 } else if (isChangeRight) { 296 text2.append(lineText); 297 if (!leftPart) { 298 w.write(lineText); 299 w.newLine(); 300 } 301 isChangeRight = false; 302 isChangeLeft = true; 303 f2l2 = j; 304 f1l1 = i; 305 } 306 continue; 307 } 308 if (!isChangeLeft && !isChangeRight || leftPart == isChangeLeft) { 309 w.write(line); 310 w.newLine(); 311 } 312 if (isChangeLeft) text1.append(line + "\n"); if (isChangeRight) text2.append(line + "\n"); if (generateDiffs) { 315 if (isChangeLeft) i++; 316 else if (isChangeRight) j++; 317 else { 318 i++; 319 j++; 320 } 321 } 322 } 323 } finally { 324 try { 325 r.close(); 326 } finally { 327 w.close(); 328 } 329 } 330 if (generateDiffs) { 331 return (Difference[]) diffList.toArray(new Difference[diffList.size()]); 332 } else { 333 return null; 334 } 335 } 336 337 341 static void repairEntries(File file) throws IOException { 342 String name = file.getName(); 343 File entries = new File (file.getParentFile(), "CVS"+File.separator+"Entries"); File backup = new File (entries.getAbsolutePath()+".Backup"); int attemps = 100; 346 while (backup.exists() && attemps-- > 0) { 347 try { 349 Thread.sleep(500); 350 } catch (InterruptedException intrex) { 351 attemps = 0; 352 } 353 } 354 if (attemps <= 0) return ; backup.createNewFile(); 356 try { 357 BufferedReader reader = null; 358 BufferedWriter writer = null; 359 try { 360 reader = new BufferedReader (new FileReader (entries)); 361 writer = new BufferedWriter (new FileWriter (backup)); 362 String line; 363 String pattern = "/"+name; while ((line = reader.readLine()) != null) { 365 if (line.startsWith(pattern)) { 366 line = removeConflict(line); 367 } 368 writer.write(line+"\n"); } 370 } finally { 371 if (reader != null) reader.close(); 372 if (writer != null) writer.close(); 373 } 374 FileUtils.renameFile(backup, entries); 375 } finally { 376 if (backup.exists()) backup.delete(); 377 } 378 } 379 380 private static String removeConflict(String line) { 381 StringBuffer result = new StringBuffer (); 382 int n = line.length(); 383 int slashNum = 0; 384 boolean ignoreField = false; 385 for (int i = 0; i < n; i++) { 386 char c = line.charAt(i); 387 if (!ignoreField) result.append(c); 388 if (c == '/') { 389 ignoreField = false; 390 slashNum++; 391 if (slashNum == 3) { 392 result.append("Result of merge/"); ignoreField = true; 394 } 395 } 396 } 397 return result.toString(); 398 } 399 400 private static class MergeResultWriterInfo extends StreamSource { 401 402 private File tempf1, tempf2, tempf3, outputFile; 403 private File fileToRepairEntriesOf; 404 private String mimeType; 405 private String leftFileRevision; 406 private String rightFileRevision; 407 private FileObject fo; 408 private FileLock lock; 409 private String encoding; 410 411 public MergeResultWriterInfo(File tempf1, File tempf2, File tempf3, 412 File outputFile, String mimeType, 413 String leftFileRevision, String rightFileRevision, 414 FileObject fo, FileLock lock, String encoding) { 415 this.tempf1 = tempf1; 416 this.tempf2 = tempf2; 417 this.tempf3 = tempf3; 418 this.outputFile = outputFile; 419 this.mimeType = mimeType; 420 this.leftFileRevision = leftFileRevision; 421 this.rightFileRevision = rightFileRevision; 422 this.fo = fo; 423 this.lock = lock; 424 if (encoding == null) { 425 encoding = EncodedReaderFactory.getDefault().getEncoding(tempf1); 426 } 427 this.encoding = encoding; 428 } 429 430 public String getName() { 431 return outputFile.getName(); 432 } 433 434 public String getTitle() { 435 return org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Merge.titleResult"); 436 } 437 438 public String getMIMEType() { 439 return mimeType; 440 } 441 442 public Reader createReader() throws IOException { 443 throw new IOException ("No reader of merge result"); } 445 446 452 public Writer createWriter(Difference[] conflicts) throws IOException { 453 Writer w; 454 if (fo != null) { 455 w = EncodedReaderFactory.getDefault().getWriter(fo, lock, encoding); 456 } else { 457 w = EncodedReaderFactory.getDefault().getWriter(outputFile, mimeType, encoding); 458 } 459 if (conflicts == null || conflicts.length == 0) { 460 fileToRepairEntriesOf = outputFile; 461 return w; 462 } else { 463 return new MergeConflictFileWriter(w, fo, conflicts, 464 leftFileRevision, rightFileRevision); 465 } 466 } 467 468 472 public void close() { 473 tempf1.delete(); 474 tempf2.delete(); 475 tempf3.delete(); 476 if (lock != null) { 477 lock.releaseLock(); 478 lock = null; 479 } 480 fo = null; 481 if (fileToRepairEntriesOf != null) { 482 try { 483 repairEntries(fileToRepairEntriesOf); 484 } catch (IOException ioex) { 485 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioex); 487 } 488 fileToRepairEntriesOf = null; 489 } 490 } 491 492 } 493 494 private static class MergeConflictFileWriter extends FilterWriter { 495 496 private Difference[] conflicts; 497 private int lineNumber; 498 private int currentConflict; 499 private String leftName; 500 private String rightName; 501 private FileObject fo; 502 503 public MergeConflictFileWriter(Writer delegate, FileObject fo, 504 Difference[] conflicts, String leftName, 505 String rightName) throws IOException { 506 super(delegate); 507 this.conflicts = conflicts; 508 this.leftName = leftName; 509 this.rightName = rightName; 510 this.lineNumber = 1; 511 this.currentConflict = 0; 512 if (lineNumber == conflicts[currentConflict].getFirstStart()) { 513 writeConflict(conflicts[currentConflict]); 514 currentConflict++; 515 } 516 this.fo = fo; 517 } 518 519 public void write(String str) throws IOException { 520 super.write(str); 522 lineNumber += numChars('\n', str); 523 if (currentConflict < conflicts.length && lineNumber >= conflicts[currentConflict].getFirstStart()) { 525 writeConflict(conflicts[currentConflict]); 526 currentConflict++; 527 } 528 } 529 530 private void writeConflict(Difference conflict) throws IOException { 531 super.write(CHANGE_LEFT + leftName + "\n"); super.write(conflict.getFirstText()); 534 super.write(CHANGE_DELIMETER + "\n"); super.write(conflict.getSecondText()); 536 super.write(CHANGE_RIGHT + rightName + "\n"); } 538 539 private static int numChars(char c, String str) { 540 int n = 0; 541 for (int pos = str.indexOf(c); pos >= 0 && pos < str.length(); pos = str.indexOf(c, pos + 1)) { 542 n++; 543 } 544 return n; 545 } 546 547 public void close() throws IOException { 548 super.close(); 549 if (fo != null) fo.refresh(true); 550 } 551 } 552 } 553 554 | Popular Tags |