Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java @ 397:5e95b0da26f2 smartgit3
Issue 24: IAE, Underflow in FilterDataAccess. Issue 26:UnsupportedOperationException when patching empty base revision. Tests
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 23 Feb 2012 15:31:57 +0100 |
parents | 2fadf8695f8a |
children | 866fc3b597a0 |
comparison
equal
deleted
inserted
replaced
393:728708de3597 | 397:5e95b0da26f2 |
---|---|
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; |