changeset 88:61eedab3eb3e

Status between two revisions to recognize copy/rename
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 26 Jan 2011 05:46:47 +0100
parents 25f2e5d1cd8b
children 42bcb4bffd17
files cmdline/org/tmatesoft/hg/console/Log.java cmdline/org/tmatesoft/hg/console/Status.java src/org/tmatesoft/hg/core/LogCommand.java src/org/tmatesoft/hg/internal/RevlogDump.java src/org/tmatesoft/hg/internal/RevlogStream.java src/org/tmatesoft/hg/repo/HgDataFile.java src/org/tmatesoft/hg/repo/Revlog.java src/org/tmatesoft/hg/repo/StatusCollector.java test/org/tmatesoft/hg/test/StatusOutputParser.java test/org/tmatesoft/hg/test/TestStatus.java
diffstat 10 files changed, 113 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/cmdline/org/tmatesoft/hg/console/Log.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/cmdline/org/tmatesoft/hg/console/Log.java	Wed Jan 26 05:46:47 2011 +0100
@@ -182,9 +182,9 @@
 				}
 				Nodeid p1 = changelogWalker.safeFirstParent(csetNodeid);
 				Nodeid p2 = changelogWalker.safeSecondParent(csetNodeid);
-				int p1x = p1 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevisionNumber(p1);
-				int p2x = p2 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevisionNumber(p2);
-				int mx = repo.getManifest().getLocalRevisionNumber(cset.getManifestRevision());
+				int p1x = p1 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevision(p1);
+				int p2x = p2 == Nodeid.NULL ? -1 : repo.getChangelog().getLocalRevision(p2);
+				int mx = repo.getManifest().getLocalRevision(cset.getManifestRevision());
 				f.format("parent:      %d:%s\nparent:      %d:%s\nmanifest:    %d:%s\n", p1x, p1, p2x, p2, mx, cset.getManifestRevision());
 			}
 			f.format("user:        %s\ndate:        %s\n", cset.getUser(), cset.getDate());
--- a/cmdline/org/tmatesoft/hg/console/Status.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/cmdline/org/tmatesoft/hg/console/Status.java	Wed Jan 26 05:46:47 2011 +0100
@@ -29,6 +29,7 @@
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.repo.Internals;
 import org.tmatesoft.hg.repo.StatusCollector;
+import org.tmatesoft.hg.repo.StatusCollector.Record;
 import org.tmatesoft.hg.repo.WorkingCopyStatusCollector;
 
 /**
@@ -51,13 +52,18 @@
 		//
 //		new Internals(hgRepo).dumpDirstate();
 		//
-		mardu(hgRepo);
+		//statusWorkingCopy(hgRepo);
+		statusRevVsWorkingCopy(hgRepo);
 	}
-	
-	private static void mardu(HgRepository hgRepo) {
+
+	private static void statusWorkingCopy(HgRepository hgRepo) {
 		WorkingCopyStatusCollector wcc = new WorkingCopyStatusCollector(hgRepo);
 		StatusCollector.Record r = new StatusCollector.Record();
 		wcc.walk(TIP, r);
+		mardu(r);
+	}
+
+	private static void mardu(Record r) {
 		sortAndPrint('M', r.getModified());
 		sortAndPrint('A', r.getAdded(), r.getCopied());
 		sortAndPrint('R', r.getRemoved());
@@ -66,6 +72,13 @@
 //		sortAndPrint('C', r.getClean());
 		sortAndPrint('!', r.getMissing());
 	}
+	
+	private static void statusRevVsWorkingCopy(HgRepository hgRepo) {
+		WorkingCopyStatusCollector wcc = new WorkingCopyStatusCollector(hgRepo);
+		StatusCollector.Record r = new StatusCollector.Record();
+		wcc.walk(3, r);
+		mardu(r);
+	}
 
 	private static void bunchOfTests(HgRepository hgRepo) throws Exception {
 		Internals debug = new Internals(hgRepo);
--- a/src/org/tmatesoft/hg/core/LogCommand.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/src/org/tmatesoft/hg/core/LogCommand.java	Wed Jan 26 05:46:47 2011 +0100
@@ -179,7 +179,7 @@
 					// even if we do not follow history, report file rename
 					do {
 						FileRevision src = new FileRevision(repo, fileNode.getCopySourceRevision(), fileNode.getCopySourceName());
-						FileRevision dst = new FileRevision(repo, fileNode.getRevisionNumber(0), fileNode.getPath());
+						FileRevision dst = new FileRevision(repo, fileNode.getRevision(0), fileNode.getPath());
 						((FileHistoryHandler) handler).copy(src, dst);
 						if (limit > 0 && count >= limit) {
 							// if limit reach, follow is useless.
--- a/src/org/tmatesoft/hg/internal/RevlogDump.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/src/org/tmatesoft/hg/internal/RevlogDump.java	Wed Jan 26 05:46:47 2011 +0100
@@ -44,10 +44,10 @@
 //		String filename = "store/data/hello.c.i";
 //		String filename = "store/data/docs/readme.i";
 		boolean dumpData = true;
-		if (args.length > 2) {
+		if (args.length > 1) {
 			repo = args[0];
 			filename = args[1];
-			dumpData = "dumpData".equals(args[2]);
+			dumpData = args.length > 2 ? "dumpData".equals(args[2]) : false;
 		}
 		//
 		DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File(repo + filename))));
--- a/src/org/tmatesoft/hg/internal/RevlogStream.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/src/org/tmatesoft/hg/internal/RevlogStream.java	Wed Jan 26 05:46:47 2011 +0100
@@ -110,6 +110,29 @@
 			ex.printStackTrace();
 			throw new IllegalStateException();
 		} finally {
+			daIndex.done();
+		}
+	}
+	
+	public int linkRevision(int revision) {
+		final int last = revisionCount() - 1;
+		if (revision == TIP) {
+			revision = last;
+		}
+		if (revision < 0 || revision > last) {
+			throw new IllegalArgumentException(Integer.toString(revision));
+		}
+		DataAccess daIndex = getIndexStream();
+		try {
+			int recordOffset = inline ? (int) index.get(revision).offset : revision * REVLOGV1_RECORD_SIZE;
+			daIndex.seek(recordOffset + 20);
+			int linkRev = daIndex.readInt();
+			return linkRev;
+		} catch (IOException ex) {
+			ex.printStackTrace();
+			throw new IllegalStateException();
+		} finally {
+			daIndex.done();
 		}
 	}
 	
@@ -189,19 +212,19 @@
 			
 			daIndex.seek(inline ? (int) index.get(i).offset : i * REVLOGV1_RECORD_SIZE);
 			for (; i <= end; i++ ) {
-				long l = daIndex.readLong();
+				long l = daIndex.readLong();  // 0
 				@SuppressWarnings("unused")
 				long offset = l >>> 16;
 				@SuppressWarnings("unused")
 				int flags = (int) (l & 0X0FFFF);
-				int compressedLen = daIndex.readInt();
-				int actualLen = daIndex.readInt();
-				int baseRevision = daIndex.readInt();
-				int linkRevision = daIndex.readInt();
+				int compressedLen = daIndex.readInt(); // +8
+				int actualLen = daIndex.readInt(); // +12
+				int baseRevision = daIndex.readInt(); // +16
+				int linkRevision = daIndex.readInt(); // +20
 				int parent1Revision = daIndex.readInt();
 				int parent2Revision = daIndex.readInt();
 				// Hg has 32 bytes here, uses 20 for nodeid, and keeps 12 last bytes empty
-				daIndex.readBytes(nodeidBuf, 0, 20);
+				daIndex.readBytes(nodeidBuf, 0, 20); // +32
 				daIndex.skip(12);
 				byte[] data = null;
 				if (needData) {
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/src/org/tmatesoft/hg/repo/HgDataFile.java	Wed Jan 26 05:46:47 2011 +0100
@@ -57,7 +57,7 @@
 	}
 
 	public int length(Nodeid nodeid) {
-		return content.dataLength(getLocalRevisionNumber(nodeid));
+		return content.dataLength(getLocalRevision(nodeid));
 	}
 
 	public byte[] content() {
@@ -147,6 +147,16 @@
 		content.iterate(start, end, false, insp);
 		getRepo().getChangelog().range(inspector, commitRevisions);
 	}
+	
+	// for a given local revision of the file, find out local revision in the changelog
+	public int getChangesetLocalRevision(int revision) {
+		return content.linkRevision(revision);
+	}
+
+	public Nodeid getChangesetRevision(Nodeid nid) {
+		int changelogRevision = getChangesetLocalRevision(getLocalRevision(nid));
+		return getRepo().getChangelog().getRevision(changelogRevision);
+	}
 
 	public boolean isCopy() {
 		if (metadata == null) {
@@ -171,8 +181,17 @@
 		}
 		throw new UnsupportedOperationException();
 	}
+	
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+		sb.append('(');
+		sb.append(getPath());
+		sb.append(')');
+		return sb.toString();
+	}
 
-	public static final class MetadataEntry {
+	private static final class MetadataEntry {
 		private final String entry;
 		private final int valueStart;
 		/*package-local*/MetadataEntry(String key, String value) {
--- a/src/org/tmatesoft/hg/repo/Revlog.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/src/org/tmatesoft/hg/repo/Revlog.java	Wed Jan 26 05:46:47 2011 +0100
@@ -60,12 +60,12 @@
 		return content.revisionCount();
 	}
 	
-	public Nodeid getRevisionNumber(int revision) {
+	public Nodeid getRevision(int revision) {
 		// XXX cache nodeids?
 		return Nodeid.fromBinary(content.nodeid(revision), 0);
 	}
 
-	public int getLocalRevisionNumber(Nodeid nid) {
+	public int getLocalRevision(Nodeid nid) {
 		int revision = content.findLocalRevisionNumber(nid);
 		if (revision == BAD_REVISION) {
 			throw new IllegalArgumentException(String.format("%s doesn't represent a revision of %s", nid.toString(), this /*XXX HgDataFile.getPath might be more suitable here*/));
@@ -91,7 +91,7 @@
 	 * @param nodeid
 	 */
 	public byte[] content(Nodeid nodeid) {
-		return content(getLocalRevisionNumber(nodeid));
+		return content(getLocalRevision(nodeid));
 	}
 	
 	/**
--- a/src/org/tmatesoft/hg/repo/StatusCollector.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/src/org/tmatesoft/hg/repo/StatusCollector.java	Wed Jan 26 05:46:47 2011 +0100
@@ -29,6 +29,7 @@
 import java.util.TreeSet;
 
 import org.tmatesoft.hg.core.Nodeid;
+import org.tmatesoft.hg.core.Path;
 
 
 /**
@@ -124,7 +125,28 @@
 					inspector.modified(fname);
 				}
 			} else {
-				inspector.added(fname);
+				HgDataFile df = repo.getFileNode(fname);
+				boolean isCopy = false;
+				while (df.isCopy()) {
+					Path original = df.getCopySourceName();
+					if (r1Files.contains(original.toString())) {
+						df = repo.getFileNode(original);
+						int changelogRevision = df.getChangesetLocalRevision(0);
+						if (changelogRevision <= rev1) {
+							// copy/rename source was known prior to rev1 
+							// (both r1Files.contains is true and original was created earlier than rev1)
+							// without r1Files.contains changelogRevision <= rev1 won't suffice as the file
+							// might get removed somewhere in between (changelogRevision < R < rev1)
+							inspector.copied(original.toString(), fname);
+							isCopy = true;
+						}
+						break;
+					} 
+					df = repo.getFileNode(original); // try more steps away
+				}
+				if (!isCopy) {
+					inspector.added(fname);
+				}
 			}
 		}
 		for (String left : r1Files) {
--- a/test/org/tmatesoft/hg/test/StatusOutputParser.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/test/org/tmatesoft/hg/test/StatusOutputParser.java	Wed Jan 26 05:46:47 2011 +0100
@@ -87,7 +87,7 @@
 				}
 				// last added is copy destination
 				// to get or to remove it - depends on what StatusCollector does in this case
-				copied.put(added.get(added.size() - 1), fname);
+				copied.put(added.get(added.size() - 1), toJavaImplConvention(fname));
 				break;
 			}
 			}
@@ -141,11 +141,15 @@
 		if (l == null) {
 			l = new LinkedList<String>();
 		}
+		l.add(toJavaImplConvention(s));
+		return l;
+	}
+
+	private String toJavaImplConvention(String s) {
 		if (winPathSeparator) {
 			// Java impl always give slashed path, while Hg uses local, os-specific convention
 			s = s.replace('\\', '/'); 
 		}
-		l.add(s);
-		return l;
+		return s;
 	}
 }
--- a/test/org/tmatesoft/hg/test/TestStatus.java	Wed Jan 26 01:07:26 2011 +0100
+++ b/test/org/tmatesoft/hg/test/TestStatus.java	Wed Jan 26 05:46:47 2011 +0100
@@ -46,7 +46,7 @@
 		HgRepository repo = new Lookup().detectFromWorkingDir();
 		TestStatus test = new TestStatus(repo);
 		test.testLowLevel();
-		test.testStatusCommand();
+//		test.testStatusCommand();
 	}
 	
 	public TestStatus(HgRepository hgRepo) {
@@ -73,6 +73,13 @@
 		r = new StatusCollector.Record();
 		new StatusCollector(repo).change(revision, r);
 		report("status -A --change " + revision, r, statusParser);
+		//
+		statusParser.reset();
+		int rev2 = 80;
+		final String range = String.valueOf(revision) + ":" + String.valueOf(rev2);
+		eh.run("hg", "status", "-A", "--rev", range);
+		r = new StatusCollector(repo).status(revision, rev2);
+		report("Status -A -rev " + range, r, statusParser);
 	}
 	
 	public void testStatusCommand() throws Exception {