1 19 20 package org.netbeans.modules.subversion.ui.update; 21 22 import java.io.*; 23 import java.util.*; 24 import java.awt.*; 25 import javax.swing.*; 26 import org.netbeans.modules.subversion.ui.commit.ConflictResolvedAction; 27 import org.netbeans.spi.diff.*; 28 29 import org.openide.DialogDisplayer; 30 import org.openide.ErrorManager; 31 import org.openide.util.*; 32 import org.openide.windows.TopComponent; 33 import org.openide.filesystems.*; 34 35 import org.netbeans.api.diff.*; 36 import org.netbeans.modules.diff.EncodedReaderFactory; 37 import org.netbeans.modules.subversion.*; 38 import org.netbeans.modules.subversion.client.*; 39 40 import org.tigris.subversion.svnclientadapter.*; 41 42 49 public class ResolveConflictsExecutor extends SvnProgressSupport { 50 51 private static final String TMP_PREFIX = "merge"; 53 static final String CHANGE_LEFT = "<<<<<<< "; static final String CHANGE_RIGHT = ">>>>>>> "; static final String CHANGE_DELIMETER = "======="; 57 private String leftFileRevision = null; 58 private String rightFileRevision = null; 59 60 private final File file; 61 62 public ResolveConflictsExecutor(File file) { 63 super(); 64 this.file = file; 65 } 66 67 public void exec() { 68 assert SwingUtilities.isEventDispatchThread(); 69 MergeVisualizer merge = (MergeVisualizer) Lookup.getDefault().lookup(MergeVisualizer.class); 70 if (merge == null) { 71 throw new IllegalStateException ("No Merge engine found."); } 73 74 try { 75 FileObject fo = FileUtil.toFileObject(file); 76 handleMergeFor(file, fo, fo.lock(), merge); 77 } catch (FileAlreadyLockedException e) { 78 Set components = TopComponent.getRegistry().getOpened(); 79 for (Iterator i = components.iterator(); i.hasNext();) { 80 TopComponent tc = (TopComponent) i.next(); 81 if (tc.getClientProperty(ResolveConflictsExecutor.class.getName()) != null) { 82 tc.requestActive(); 83 } 84 } 85 } catch (IOException ioex) { 86 org.openide.ErrorManager.getDefault().notify(ioex); 87 } 88 } 89 90 private void handleMergeFor(final File file, FileObject fo, FileLock lock, 91 final MergeVisualizer merge) throws IOException { 92 String mimeType = (fo == null) ? "text/plain" : fo.getMIMEType(); String ext = "."+fo.getExt(); File f1 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext)); 95 File f2 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext)); 96 File f3 = FileUtil.normalizeFile(File.createTempFile(TMP_PREFIX, ext)); 97 f1.deleteOnExit(); 98 f2.deleteOnExit(); 99 f3.deleteOnExit(); 100 101 final Difference[] diffs = copyParts(true, file, f1, true); 102 if (diffs.length == 0) { 103 ConflictResolvedAction.perform(file); return; 105 } 106 107 copyParts(false, file, f2, false); 108 String originalLeftFileRevision = leftFileRevision; 110 String originalRightFileRevision = rightFileRevision; 111 if (leftFileRevision != null) leftFileRevision.trim(); 112 if (rightFileRevision != null) rightFileRevision.trim(); 113 if (leftFileRevision == null || leftFileRevision.equals(file.getName())) { 114 leftFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleWorkingFile"); } else { 116 leftFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleRevision", leftFileRevision); } 118 if (rightFileRevision == null || rightFileRevision.equals(file.getName())) { 119 rightFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleWorkingFile"); } else { 121 rightFileRevision = org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Diff.titleRevision", rightFileRevision); } 123 124 final StreamSource s1; 125 final StreamSource s2; 126 String encoding = EncodedReaderFactory.getDefault().getEncoding(fo); 127 if (encoding != null) { 128 s1 = StreamSource.createSource(file.getName(), leftFileRevision, mimeType, new InputStreamReader(new FileInputStream(f1), encoding)); 129 s2 = StreamSource.createSource(file.getName(), rightFileRevision, mimeType, new InputStreamReader(new FileInputStream(f2), encoding)); 130 } else { 131 s1 = StreamSource.createSource(file.getName(), leftFileRevision, mimeType, f1); 132 s2 = StreamSource.createSource(file.getName(), rightFileRevision, mimeType, f2); 133 } 134 final StreamSource result = new MergeResultWriterInfo(f1, f2, f3, file, mimeType, 135 originalLeftFileRevision, 136 originalRightFileRevision, 137 fo, lock, encoding); 138 139 try { 140 Component c = merge.createView(diffs, s1, s2, result); 141 if (c instanceof TopComponent) { 142 ((TopComponent) c).putClientProperty(ResolveConflictsExecutor.class.getName(), Boolean.TRUE); 143 } 144 } catch (IOException ioex) { 145 org.openide.ErrorManager.getDefault().notify(ioex); 146 } 147 } 148 149 152 private Difference[] copyParts(boolean generateDiffs, File source, 153 File dest, boolean leftPart) throws IOException { 154 BufferedReader r = new BufferedReader(new FileReader(source)); 156 BufferedWriter w = new BufferedWriter(new FileWriter(dest)); 157 ArrayList<Difference> diffList = null; 158 if (generateDiffs) { 159 diffList = new ArrayList<Difference>(); 160 } 161 try { 162 String line; 163 boolean isChangeLeft = false; 164 boolean isChangeRight = false; 165 int f1l1 = 0, f1l2 = 0, f2l1 = 0, f2l2 = 0; 166 StringBuffer text1 = new StringBuffer (); 167 StringBuffer text2 = new StringBuffer (); 168 int i = 1, j = 1; 169 while ((line = r.readLine()) != null) { 170 if (line.startsWith(CHANGE_LEFT)) { 171 if (generateDiffs) { 172 if (leftFileRevision == null) { 173 leftFileRevision = line.substring(CHANGE_LEFT.length()); 174 } 175 if (isChangeLeft) { 176 f1l2 = i - 1; 177 diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD, 178 f1l1 - 1, 0, f2l1, f2l2, 179 text1.toString(), 180 text2.toString()) : 181 (f2l1 > f2l2) ? new Difference(Difference.DELETE, 182 f1l1, f1l2, f2l1 - 1, 0, 183 text1.toString(), 184 text2.toString()) 185 : new Difference(Difference.CHANGE, 186 f1l1, f1l2, f2l1, f2l2, 187 text1.toString(), 188 text2.toString())); 189 f1l1 = f1l2 = f2l1 = f2l2 = 0; 190 text1.delete(0, text1.length()); 191 text2.delete(0, text2.length()); 192 } else { 193 f1l1 = i; 194 } 195 } 196 isChangeLeft = !isChangeLeft; 197 continue; 198 } else if (line.startsWith(CHANGE_RIGHT)) { 199 if (generateDiffs) { 200 if (rightFileRevision == null) { 201 rightFileRevision = line.substring(CHANGE_RIGHT.length()); 202 } 203 if (isChangeRight) { 204 f2l2 = j - 1; 205 diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD, 206 f1l1 - 1, 0, f2l1, f2l2, 207 text1.toString(), 208 text2.toString()) : 209 (f2l1 > f2l2) ? new Difference(Difference.DELETE, 210 f1l1, f1l2, f2l1 - 1, 0, 211 text1.toString(), 212 text2.toString()) 213 : new Difference(Difference.CHANGE, 214 f1l1, f1l2, f2l1, f2l2, 215 text1.toString(), 216 text2.toString())); 217 223 f1l1 = f1l2 = f2l1 = f2l2 = 0; 224 text1.delete(0, text1.length()); 225 text2.delete(0, text2.length()); 226 } else { 227 f2l1 = j; 228 } 229 } 230 isChangeRight = !isChangeRight; 231 continue; 232 } else if (isChangeRight && line.indexOf(CHANGE_RIGHT) != -1) { 233 String lineText = line.substring(0, line.lastIndexOf(CHANGE_RIGHT)); 234 if (generateDiffs) { 235 if (rightFileRevision == null) { 236 rightFileRevision = line.substring(line.lastIndexOf(CHANGE_RIGHT) + CHANGE_RIGHT.length()); 237 } 238 text2.append(lineText); 239 f2l2 = j; 240 diffList.add((f1l1 > f1l2) ? new Difference(Difference.ADD, 241 f1l1 - 1, 0, f2l1, f2l2, 242 text1.toString(), 243 text2.toString()) : 244 (f2l1 > f2l2) ? new Difference(Difference.DELETE, 245 f1l1, f1l2, f2l1 - 1, 0, 246 text1.toString(), 247 text2.toString()) 248 : new Difference(Difference.CHANGE, 249 f1l1, f1l2, f2l1, f2l2, 250 text1.toString(), 251 text2.toString())); 252 f1l1 = f1l2 = f2l1 = f2l2 = 0; 253 text1.delete(0, text1.length()); 254 text2.delete(0, text2.length()); 255 } 256 if (!leftPart) { 257 w.write(lineText); 258 w.newLine(); 259 } 260 isChangeRight = !isChangeRight; 261 continue; 262 } else if (line.equals(CHANGE_DELIMETER)) { 263 if (isChangeLeft) { 264 isChangeLeft = false; 265 isChangeRight = true; 266 f1l2 = i - 1; 267 f2l1 = j; 268 continue; 269 } else if (isChangeRight) { 270 isChangeRight = false; 271 isChangeLeft = true; 272 f2l2 = j - 1; 273 f1l1 = i; 274 continue; 275 } 276 } else if (line.endsWith(CHANGE_DELIMETER)) { 277 String lineText = line.substring(0, line.length() - CHANGE_DELIMETER.length()) + "\n"; if (isChangeLeft) { 279 text1.append(lineText); 280 if (leftPart) { 281 w.write(lineText); 282 w.newLine(); 283 } 284 isChangeLeft = false; 285 isChangeRight = true; 286 f1l2 = i; 287 f2l1 = j; 288 } else if (isChangeRight) { 289 text2.append(lineText); 290 if (!leftPart) { 291 w.write(lineText); 292 w.newLine(); 293 } 294 isChangeRight = false; 295 isChangeLeft = true; 296 f2l2 = j; 297 f1l1 = i; 298 } 299 continue; 300 } 301 if (!isChangeLeft && !isChangeRight || leftPart == isChangeLeft) { 302 w.write(line); 303 w.newLine(); 304 } 305 if (isChangeLeft) text1.append(line + "\n"); if (isChangeRight) text2.append(line + "\n"); if (generateDiffs) { 308 if (isChangeLeft) i++; 309 else if (isChangeRight) j++; 310 else { 311 i++; 312 j++; 313 } 314 } 315 } 316 } finally { 317 try { 318 r.close(); 319 } finally { 320 w.close(); 321 } 322 } 323 if (generateDiffs) { 324 return diffList.toArray(new Difference[diffList.size()]); 325 } else { 326 return null; 327 } 328 } 329 330 public void perform() { 331 exec(); 332 } 333 334 public void run() { 335 throw new RuntimeException ("Not implemented"); } 337 338 339 private static class MergeResultWriterInfo extends StreamSource { 340 341 private File tempf1, tempf2, tempf3, outputFile; 342 private File fileToRepairEntriesOf; 343 private String mimeType; 344 private String leftFileRevision; 345 private String rightFileRevision; 346 private FileObject fo; 347 private FileLock lock; 348 private String encoding; 349 350 public MergeResultWriterInfo(File tempf1, File tempf2, File tempf3, 351 File outputFile, String mimeType, 352 String leftFileRevision, String rightFileRevision, 353 FileObject fo, FileLock lock, String encoding) { 354 this.tempf1 = tempf1; 355 this.tempf2 = tempf2; 356 this.tempf3 = tempf3; 357 this.outputFile = outputFile; 358 this.mimeType = mimeType; 359 this.leftFileRevision = leftFileRevision; 360 this.rightFileRevision = rightFileRevision; 361 this.fo = fo; 362 this.lock = lock; 363 if (encoding == null) { 364 encoding = EncodedReaderFactory.getDefault().getEncoding(tempf1); 365 } 366 this.encoding = encoding; 367 } 368 369 public String getName() { 370 return outputFile.getName(); 371 } 372 373 public String getTitle() { 374 return org.openide.util.NbBundle.getMessage(ResolveConflictsExecutor.class, "Merge.titleResult"); } 376 377 public String getMIMEType() { 378 return mimeType; 379 } 380 381 public Reader createReader() throws IOException { 382 throw new IOException("No reader of merge result"); } 384 385 391 public Writer createWriter(Difference[] conflicts) throws IOException { 392 Writer w; 393 if (fo != null) { 394 w = EncodedReaderFactory.getDefault().getWriter(fo, lock, encoding); 395 } else { 396 w = EncodedReaderFactory.getDefault().getWriter(outputFile, mimeType, encoding); 397 } 398 if (conflicts == null || conflicts.length == 0) { 399 fileToRepairEntriesOf = outputFile; 400 return w; 401 } else { 402 return new MergeConflictFileWriter(w, fo, conflicts, 403 leftFileRevision, rightFileRevision); 404 } 405 } 406 407 411 public void close() { 412 tempf1.delete(); 413 tempf2.delete(); 414 tempf3.delete(); 415 if (lock != null) { 416 lock.releaseLock(); 417 lock = null; 418 } 419 fo = null; 420 if (fileToRepairEntriesOf != null) { 421 repairEntries(fileToRepairEntriesOf); 422 fileToRepairEntriesOf = null; 423 } 424 } 425 426 private void repairEntries(File file) { 427 ConflictResolvedAction.perform(file); 428 } 429 430 } 431 432 private static class MergeConflictFileWriter extends FilterWriter { 433 434 private Difference[] conflicts; 435 private int lineNumber; 436 private int currentConflict; 437 private String leftName; 438 private String rightName; 439 private FileObject fo; 440 441 public MergeConflictFileWriter(Writer delegate, FileObject fo, 442 Difference[] conflicts, String leftName, 443 String rightName) throws IOException { 444 super(delegate); 445 this.conflicts = conflicts; 446 this.leftName = leftName; 447 this.rightName = rightName; 448 this.lineNumber = 1; 449 this.currentConflict = 0; 450 if (lineNumber == conflicts[currentConflict].getFirstStart()) { 451 writeConflict(conflicts[currentConflict]); 452 currentConflict++; 453 } 454 this.fo = fo; 455 } 456 457 public void write(String str) throws IOException { 458 super.write(str); 460 lineNumber += numChars('\n', str); 461 if (currentConflict < conflicts.length && lineNumber >= conflicts[currentConflict].getFirstStart()) { 463 writeConflict(conflicts[currentConflict]); 464 currentConflict++; 465 } 466 } 467 468 private void writeConflict(Difference conflict) throws IOException { 469 super.write(CHANGE_LEFT + leftName + "\n"); super.write(conflict.getFirstText()); 472 super.write(CHANGE_DELIMETER + "\n"); super.write(conflict.getSecondText()); 474 super.write(CHANGE_RIGHT + rightName + "\n"); } 476 477 private static int numChars(char c, String str) { 478 int n = 0; 479 for (int pos = str.indexOf(c); pos >= 0 && pos < str.length(); pos = str.indexOf(c, pos + 1)) { 480 n++; 481 } 482 return n; 483 } 484 485 public void close() throws IOException { 486 super.close(); 487 if (fo != null) fo.refresh(true); 488 } 489 } 490 } 491 492 | Popular Tags |