Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java @ 398:c76c57f6b961
Merge fixed for issue 24 and issue 26 from smartgit3 branch
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 23 Feb 2012 21:53:21 +0100 |
| parents | 5e95b0da26f2 |
| children | 866fc3b597a0 |
comparison
equal
deleted
inserted
replaced
| 396:0ae53c32ecef | 398:c76c57f6b961 |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011 TMate Software Ltd | 2 * Copyright (c) 2011-2012 TMate Software Ltd |
| 3 * | 3 * |
| 4 * This program is free software; you can redistribute it and/or modify | 4 * This program is free software; you can redistribute it and/or modify |
| 5 * it under the terms of the GNU General Public License as published by | 5 * it under the terms of the GNU General Public License as published by |
| 6 * the Free Software Foundation; version 2 of the License. | 6 * the Free Software Foundation; version 2 of the License. |
| 7 * | 7 * |
| 28 import java.util.Collections; | 28 import java.util.Collections; |
| 29 import java.util.NoSuchElementException; | 29 import java.util.NoSuchElementException; |
| 30 import java.util.Set; | 30 import java.util.Set; |
| 31 import java.util.TreeSet; | 31 import java.util.TreeSet; |
| 32 | 32 |
| 33 import org.tmatesoft.hg.core.HgBadStateException; | |
| 34 import org.tmatesoft.hg.core.HgException; | 33 import org.tmatesoft.hg.core.HgException; |
| 35 import org.tmatesoft.hg.core.HgInvalidControlFileException; | 34 import org.tmatesoft.hg.core.HgInvalidControlFileException; |
| 35 import org.tmatesoft.hg.core.HgInvalidFileException; | |
| 36 import org.tmatesoft.hg.core.Nodeid; | 36 import org.tmatesoft.hg.core.Nodeid; |
| 37 import org.tmatesoft.hg.internal.ByteArrayChannel; | 37 import org.tmatesoft.hg.internal.ByteArrayChannel; |
| 38 import org.tmatesoft.hg.internal.Experimental; | 38 import org.tmatesoft.hg.internal.Experimental; |
| 39 import org.tmatesoft.hg.internal.FilterByteChannel; | 39 import org.tmatesoft.hg.internal.FilterByteChannel; |
| 40 import org.tmatesoft.hg.internal.ManifestRevision; | 40 import org.tmatesoft.hg.internal.ManifestRevision; |
| 289 if (timestampEqual && sizeEqual) { | 289 if (timestampEqual && sizeEqual) { |
| 290 inspector.clean(fname); | 290 inspector.clean(fname); |
| 291 } else if (!sizeEqual && r.size() >= 0) { | 291 } else if (!sizeEqual && r.size() >= 0) { |
| 292 inspector.modified(fname); | 292 inspector.modified(fname); |
| 293 } else { | 293 } else { |
| 294 // size is the same or unknown, and, perhaps, different timestamp | 294 try { |
| 295 // check actual content to avoid false modified files | 295 // size is the same or unknown, and, perhaps, different timestamp |
| 296 HgDataFile df = repo.getFileNode(fname); | 296 // check actual content to avoid false modified files |
| 297 if (!df.exists()) { | 297 HgDataFile df = repo.getFileNode(fname); |
| 298 String msg = String.format("File %s known as normal in dirstate (%d, %d), doesn't exist at %s", fname, r.modificationTime(), r.size(), repo.getStoragePath(df)); | 298 if (!df.exists()) { |
| 299 throw new HgBadStateException(msg); | 299 String msg = String.format("File %s known as normal in dirstate (%d, %d), doesn't exist at %s", fname, r.modificationTime(), r.size(), repo.getStoragePath(df)); |
| 300 } | 300 throw new HgInvalidFileException(msg, null).setFileName(fname); |
| 301 Nodeid rev = getDirstateParentManifest().nodeid(fname); | 301 } |
| 302 // rev might be null here if fname comes to dirstate as a result of a merge operation | 302 Nodeid rev = getDirstateParentManifest().nodeid(fname); |
| 303 // where one of the parents (first parent) had no fname file, but second parent had. | 303 // rev might be null here if fname comes to dirstate as a result of a merge operation |
| 304 // E.g. fork revision 3, revision 4 gets .hgtags, few modifications and merge(3,12) | 304 // where one of the parents (first parent) had no fname file, but second parent had. |
| 305 // see Issue 14 for details | 305 // E.g. fork revision 3, revision 4 gets .hgtags, few modifications and merge(3,12) |
| 306 if (rev == null || !areTheSame(f, df, rev)) { | 306 // see Issue 14 for details |
| 307 inspector.modified(df.getPath()); | 307 if (rev == null || !areTheSame(f, df, rev)) { |
| 308 } else { | 308 inspector.modified(df.getPath()); |
| 309 inspector.clean(df.getPath()); | 309 } else { |
| 310 inspector.clean(df.getPath()); | |
| 311 } | |
| 312 } catch (HgException ex) { | |
| 313 repo.getContext().getLog().warn(getClass(), ex, null); | |
| 314 inspector.invalid(fname, ex); | |
| 310 } | 315 } |
| 311 } | 316 } |
| 312 } else if ((r = getDirstateImpl().checkAdded(fname)) != null) { | 317 } else if ((r = getDirstateImpl().checkAdded(fname)) != null) { |
| 313 if (r.copySource() == null) { | 318 if (r.copySource() == null) { |
| 314 inspector.added(fname); | 319 inspector.added(fname); |
| 381 // otherwise, shall check actual content (size not the same, or unknown (-1 or -2), or timestamp is different, | 386 // otherwise, shall check actual content (size not the same, or unknown (-1 or -2), or timestamp is different, |
| 382 // or nodeid in dirstate is different, but local change might have brought it back to baseRevision state) | 387 // or nodeid in dirstate is different, but local change might have brought it back to baseRevision state) |
| 383 // FALL THROUGH | 388 // FALL THROUGH |
| 384 } | 389 } |
| 385 if (r != null || (r = getDirstateImpl().checkMerged(fname)) != null || (r = getDirstateImpl().checkAdded(fname)) != null) { | 390 if (r != null || (r = getDirstateImpl().checkMerged(fname)) != null || (r = getDirstateImpl().checkAdded(fname)) != null) { |
| 386 // check actual content to see actual changes | 391 try { |
| 387 // when added - seems to be the case of a file added once again, hence need to check if content is different | 392 // check actual content to see actual changes |
| 388 // either clean or modified | 393 // when added - seems to be the case of a file added once again, hence need to check if content is different |
| 389 HgDataFile fileNode = repo.getFileNode(fname); | 394 // either clean or modified |
| 390 if (areTheSame(f, fileNode, nid1)) { | 395 HgDataFile fileNode = repo.getFileNode(fname); |
| 391 inspector.clean(fname); | 396 if (areTheSame(f, fileNode, nid1)) { |
| 392 } else { | 397 inspector.clean(fname); |
| 393 inspector.modified(fname); | 398 } else { |
| 399 inspector.modified(fname); | |
| 400 } | |
| 401 } catch (HgException ex) { | |
| 402 repo.getContext().getLog().warn(getClass(), ex, null); | |
| 403 inspector.invalid(fname, ex); | |
| 394 } | 404 } |
| 395 baseRevNames.remove(fname); // consumed, processed, handled. | 405 baseRevNames.remove(fname); // consumed, processed, handled. |
| 396 } else if (getDirstateImpl().checkRemoved(fname) != null) { | 406 } else if (getDirstateImpl().checkRemoved(fname) != null) { |
| 397 // was known, and now marked as removed, report it right away, do not rely on baseRevNames processing later | 407 // was known, and now marked as removed, report it right away, do not rely on baseRevNames processing later |
| 398 inspector.removed(fname); | 408 inspector.removed(fname); |
| 407 // changeset nodeid + hash(actual content) => entry (Nodeid) in the next Manifest | 417 // changeset nodeid + hash(actual content) => entry (Nodeid) in the next Manifest |
| 408 // then it's sufficient to check parents from dirstate, and if they do not match parents from file's baseRevision (non matching parents means different nodeids). | 418 // then it's sufficient to check parents from dirstate, and if they do not match parents from file's baseRevision (non matching parents means different nodeids). |
| 409 // The question is whether original Hg treats this case (same content, different parents and hence nodeids) as 'modified' or 'clean' | 419 // The question is whether original Hg treats this case (same content, different parents and hence nodeids) as 'modified' or 'clean' |
| 410 } | 420 } |
| 411 | 421 |
| 412 private boolean areTheSame(FileInfo f, HgDataFile dataFile, Nodeid revision) { | 422 private boolean areTheSame(FileInfo f, HgDataFile dataFile, Nodeid revision) throws HgException { |
| 413 // XXX consider adding HgDataDile.compare(File/byte[]/whatever) operation to optimize comparison | 423 // XXX consider adding HgDataDile.compare(File/byte[]/whatever) operation to optimize comparison |
| 414 ByteArrayChannel bac = new ByteArrayChannel(); | 424 ByteArrayChannel bac = new ByteArrayChannel(); |
| 415 boolean ioFailed = false; | |
| 416 try { | 425 try { |
| 417 int fileRevisionIndex = dataFile.getRevisionIndex(revision); | 426 int fileRevisionIndex = dataFile.getRevisionIndex(revision); |
| 418 // need content with metadata striped off - although theoretically chances are metadata may be different, | 427 // need content with metadata striped off - although theoretically chances are metadata may be different, |
| 419 // WC doesn't have it anyway | 428 // WC doesn't have it anyway |
| 420 dataFile.content(fileRevisionIndex, bac); | 429 dataFile.content(fileRevisionIndex, bac); |
| 421 } catch (CancelledException ex) { | 430 } catch (CancelledException ex) { |
| 422 // silently ignore - can't happen, ByteArrayChannel is not cancellable | 431 // silently ignore - can't happen, ByteArrayChannel is not cancellable |
| 423 } catch (HgException ex) { | 432 } |
| 424 repo.getContext().getLog().warn(getClass(), ex, null); | 433 return areTheSame(f, bac.toArray(), dataFile.getPath()); |
| 425 ioFailed = true; | 434 } |
| 426 } | 435 |
| 427 return !ioFailed && areTheSame(f, bac.toArray(), dataFile.getPath()); | 436 private boolean areTheSame(FileInfo f, final byte[] data, Path p) throws HgException { |
| 428 } | |
| 429 | |
| 430 private boolean areTheSame(FileInfo f, final byte[] data, Path p) { | |
| 431 ReadableByteChannel is = null; | 437 ReadableByteChannel is = null; |
| 432 class Check implements ByteChannel { | 438 class Check implements ByteChannel { |
| 433 final boolean debug = repo.getContext().getLog().isDebug(); | 439 final boolean debug = repo.getContext().getLog().isDebug(); |
| 434 boolean sameSoFar = true; | 440 boolean sameSoFar = true; |
| 435 int x = 0; | 441 int x = 0; |
| 496 return check.ultimatelyTheSame(); | 502 return check.ultimatelyTheSame(); |
| 497 } catch (CancelledException ex) { | 503 } catch (CancelledException ex) { |
| 498 repo.getContext().getLog().warn(getClass(), ex, "Unexpected cancellation"); | 504 repo.getContext().getLog().warn(getClass(), ex, "Unexpected cancellation"); |
| 499 return check.ultimatelyTheSame(); | 505 return check.ultimatelyTheSame(); |
| 500 } catch (IOException ex) { | 506 } catch (IOException ex) { |
| 501 repo.getContext().getLog().warn(getClass(), ex, null); | 507 throw new HgInvalidFileException("File comparison failed", ex).setFileName(p); |
| 502 } finally { | 508 } finally { |
| 503 if (is != null) { | 509 if (is != null) { |
| 504 try { | 510 try { |
| 505 is.close(); | 511 is.close(); |
| 506 } catch (IOException ex) { | 512 } catch (IOException ex) { |
| 507 repo.getContext().getLog().info(getClass(), ex, null); | 513 repo.getContext().getLog().info(getClass(), ex, null); |
| 508 } | 514 } |
| 509 } | 515 } |
| 510 } | 516 } |
| 511 return false; | |
| 512 } | 517 } |
| 513 | 518 |
| 514 private static boolean todoCheckFlagsEqual(FileInfo f, HgManifest.Flags originalManifestFlags) { | 519 private static boolean todoCheckFlagsEqual(FileInfo f, HgManifest.Flags originalManifestFlags) { |
| 515 // FIXME implement | 520 // FIXME implement |
| 516 return true; | 521 return true; |
