comparison src/org/tmatesoft/hg/repo/HgStatusCollector.java @ 689:5050ee565bd1

Issue 44: Renames/copies other than for the very first revision of a file are not recognized
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Sat, 27 Jul 2013 22:06:14 +0200
parents 6526d8adbc0f
children b286222158be
comparison
equal deleted inserted replaced
688:1499139a600a 689:5050ee565bd1
24 import java.util.LinkedList; 24 import java.util.LinkedList;
25 import java.util.List; 25 import java.util.List;
26 import java.util.Map; 26 import java.util.Map;
27 import java.util.TreeSet; 27 import java.util.TreeSet;
28 28
29 import org.tmatesoft.hg.core.HgFileRevision;
29 import org.tmatesoft.hg.core.Nodeid; 30 import org.tmatesoft.hg.core.Nodeid;
30 import org.tmatesoft.hg.internal.IntMap; 31 import org.tmatesoft.hg.internal.IntMap;
31 import org.tmatesoft.hg.internal.ManifestRevision; 32 import org.tmatesoft.hg.internal.ManifestRevision;
32 import org.tmatesoft.hg.internal.Pool; 33 import org.tmatesoft.hg.internal.Pool;
33 import org.tmatesoft.hg.util.CancelSupport; 34 import org.tmatesoft.hg.util.CancelSupport;
314 } 315 }
315 cs.checkCancelled(); 316 cs.checkCancelled();
316 } else { 317 } else {
317 try { 318 try {
318 Path copyTarget = r2fname; 319 Path copyTarget = r2fname;
319 Path copyOrigin = detectCopies ? getOriginIfCopy(repo, copyTarget, r1Files, rev1) : null; 320 Path copyOrigin = detectCopies ? getOriginIfCopy(repo, copyTarget, r2.nodeid(copyTarget), r1Files, rev1) : null;
320 if (copyOrigin != null) { 321 if (copyOrigin != null) {
321 inspector.copied(getPathPool().mangle(copyOrigin) /*pipe through pool, just in case*/, copyTarget); 322 inspector.copied(getPathPool().mangle(copyOrigin) /*pipe through pool, just in case*/, copyTarget);
322 } else { 323 } else {
323 inspector.added(copyTarget); 324 inspector.added(copyTarget);
324 } 325 }
359 throw t; 360 throw t;
360 } 361 }
361 return rv; 362 return rv;
362 } 363 }
363 364
364 /*package-local*/static Path getOriginIfCopy(HgRepository hgRepo, Path fname, Collection<Path> originals, int originalChangelogRevision) throws HgRuntimeException { 365 /*package-local*/static Path getOriginIfCopy(HgRepository hgRepo, Path fname, Nodeid fnameRev, Collection<Path> originals, int originalChangesetIndex) throws HgRuntimeException {
365 HgDataFile df = hgRepo.getFileNode(fname); 366 HgDataFile df = hgRepo.getFileNode(fname);
366 if (!df.exists()) { 367 if (!df.exists()) {
367 String msg = String.format("Didn't find file '%s' in the repo. Perhaps, bad storage name conversion?", fname); 368 String msg = String.format("Didn't find file '%s' in the repo. Perhaps, bad storage name conversion?", fname);
368 throw new HgInvalidFileException(msg, null).setFileName(fname).setRevisionIndex(originalChangelogRevision); 369 throw new HgInvalidFileException(msg, null).setFileName(fname).setRevisionIndex(originalChangesetIndex);
369 } 370 }
370 while (df.isCopy()) { 371 assert fnameRev != null;
371 Path original = df.getCopySourceName(); 372 assert !Nodeid.NULL.equals(fnameRev);
372 if (originals.contains(original)) { 373 int fileRevIndex = fnameRev == null ? 0 : df.getRevisionIndex(fnameRev);
373 df = hgRepo.getFileNode(original); 374 Path lastOriginFound = null;
374 int changelogRevision = df.getChangesetRevisionIndex(0); 375 while(fileRevIndex >=0) {
375 if (changelogRevision <= originalChangelogRevision) { 376 if (!df.isCopy(fileRevIndex)) {
377 fileRevIndex--;
378 continue;
379 }
380 int csetRevIndex = df.getChangesetRevisionIndex(fileRevIndex);
381 if (csetRevIndex <= originalChangesetIndex) {
382 // we've walked past originalChangelogRevIndex and no chances we'll find origin
383 // if we get here, it means fname's origin is not from the base revision
384 return null;
385 }
386 HgFileRevision origin = df.getCopySource(fileRevIndex);
387 // prepare for the next step, df(copyFromFileRev) would point to copy origin and its revision
388 df = hgRepo.getFileNode(origin.getPath());
389 int copyFromFileRevIndex = df.getRevisionIndex(origin.getRevision());
390 if (originals.contains(origin.getPath())) {
391 int copyFromCsetIndex = df.getChangesetRevisionIndex(copyFromFileRevIndex);
392 if (copyFromCsetIndex <= originalChangesetIndex) {
376 // copy/rename source was known prior to rev1 393 // copy/rename source was known prior to rev1
377 // (both r1Files.contains is true and original was created earlier than rev1) 394 // (both r1Files.contains is true and original was created earlier than rev1)
378 // without r1Files.contains changelogRevision <= rev1 won't suffice as the file 395 // without r1Files.contains changelogRevision <= rev1 won't suffice as the file
379 // might get removed somewhere in between (changelogRevision < R < rev1) 396 // might get removed somewhere in between (changelogRevision < R < rev1)
380 return original; 397 return origin.getPath();
381 } 398 }
382 break; // copy/rename done later 399 // copy/rename happened in [copyFromCsetIndex..target], let's see if
383 } 400 // origin wasn't renamed once more in [originalChangesetIndex..copyFromCsetIndex]
384 df = hgRepo.getFileNode(original); // try more steps away 401 lastOriginFound = origin.getPath();
385 } 402 // FALL-THROUGH
386 return null; 403 }
404 // try more steps away
405 // copyFromFileRev or one of its predecessors might be copies as well
406 fileRevIndex = copyFromFileRevIndex; // df is already origin file
407 }
408 return lastOriginFound;
387 } 409 }
388 410
389 // XXX for r1..r2 status, only modified, added, removed (and perhaps, clean) make sense 411 // XXX for r1..r2 status, only modified, added, removed (and perhaps, clean) make sense
390 // XXX Need to specify whether copy targets are in added or not (@see Inspector#copied above) 412 // XXX Need to specify whether copy targets are in added or not (@see Inspector#copied above)
391 /** 413 /**