changeset 37:e45e75e22523

Parse changesets from bundle's changelog group. Refactor Revlog to provide access to revision's raw content
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 14 Jan 2011 00:49:58 +0100
parents 205f9b59b400
children 50dfc69c108e
files src/com/tmate/hgkit/console/Bundle.java src/com/tmate/hgkit/ll/HgBundle.java src/com/tmate/hgkit/ll/HgDataFile.java src/com/tmate/hgkit/ll/Revlog.java src/com/tmate/hgkit/ll/RevlogStream.java
diffstat 5 files changed, 63 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/com/tmate/hgkit/console/Bundle.java	Thu Jan 13 23:31:39 2011 +0100
+++ b/src/com/tmate/hgkit/console/Bundle.java	Fri Jan 14 00:49:58 2011 +0100
@@ -6,7 +6,9 @@
 import java.io.File;
 
 import com.tmate.hgkit.fs.DataAccessProvider;
+import com.tmate.hgkit.fs.RepositoryLookup;
 import com.tmate.hgkit.ll.HgBundle;
+import com.tmate.hgkit.ll.HgRepository;
 
 /**
  *
@@ -15,9 +17,17 @@
 public class Bundle {
 
 	public static void main(String[] args) throws Exception {
+		RepositoryLookup repoLookup = new RepositoryLookup();
+		RepositoryLookup.Options cmdLineOpts = RepositoryLookup.Options.parse(args);
+		HgRepository hgRepo = repoLookup.detect(cmdLineOpts);
+		if (hgRepo.isInvalid()) {
+			System.err.printf("Can't find repository in: %s\n", hgRepo.getLocation());
+			return;
+		}
 		File bundleFile = new File("/temp/hg/hg-bundle-a78c980749e3.tmp");
 		DataAccessProvider dap = new DataAccessProvider();
 		HgBundle hgBundle = new HgBundle(dap, bundleFile);
-		hgBundle.read();
+//		hgBundle.dump();
+		hgBundle.changes(hgRepo);
 	}
 }
--- a/src/com/tmate/hgkit/ll/HgBundle.java	Thu Jan 13 23:31:39 2011 +0100
+++ b/src/com/tmate/hgkit/ll/HgBundle.java	Fri Jan 14 00:49:58 2011 +0100
@@ -26,7 +26,29 @@
 		bundleFile = bundle;
 	}
 
-	public void read() throws IOException {
+	public void changes(HgRepository hgRepo) throws IOException {
+		DataAccess da = accessProvider.create(bundleFile);
+		try {
+			List<GroupElement> changelogGroup = readGroup(da);
+			byte[] baseRevContent = null;
+			for (GroupElement ge : changelogGroup) {
+				if (baseRevContent == null) {
+					// first parent is base revision, see bundlerepo.py
+					// if not prev: prev = p1 in bundlerevlog cons
+					baseRevContent = hgRepo.getChangelog().content(ge.firstParent());
+				}
+				int resultLen = 10000; // XXX calculate based on baseRevContent.length and ge.patches
+				byte[] csetContent = RevlogStream.apply(baseRevContent, resultLen, ge.patches);
+				Changeset cs = Changeset.parse(csetContent, 0, csetContent.length);
+				cs.dump();
+				baseRevContent = csetContent;
+			}
+		} finally {
+			da.done();
+		}
+	}
+
+	public void dump() throws IOException {
 		DataAccess da = accessProvider.create(bundleFile);
 		try {
 			LinkedList<String> names = new LinkedList<String>();
@@ -34,12 +56,12 @@
 				System.out.println("Changelog group");
 				List<GroupElement> changelogGroup = readGroup(da);
 				for (GroupElement ge : changelogGroup) {
-					System.out.printf("  %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cs(), ge.patches.size());
+					System.out.printf("  %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cset(), ge.patches.size());
 				}
 				System.out.println("Manifest group");
 				List<GroupElement> manifestGroup = readGroup(da);
 				for (GroupElement ge : manifestGroup) {
-					System.out.printf("  %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cs(), ge.patches.size());
+					System.out.printf("  %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cset(), ge.patches.size());
 				}
 				while (!da.isEmpty()) {
 					int fnameLen = da.readInt();
@@ -52,7 +74,7 @@
 					List<GroupElement> fileGroup = readGroup(da);
 					System.out.println(names.getLast());
 					for (GroupElement ge : fileGroup) {
-						System.out.printf("  %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cs(), ge.patches.size());
+						System.out.printf("  %s %s %s %s; patches:%d\n", ge.node(), ge.firstParent(), ge.secondParent(), ge.cset(), ge.patches.size());
 					}
 				}
 			}
@@ -103,9 +125,8 @@
 		public Nodeid secondParent() {
 			return Nodeid.fromBinary(header, 40);
 		}
-		public Nodeid cs() {
+		public Nodeid cset() { // cs seems to be changeset
 			return Nodeid.fromBinary(header, 60);
 		}
-
 	}
 }
--- a/src/com/tmate/hgkit/ll/HgDataFile.java	Thu Jan 13 23:31:39 2011 +0100
+++ b/src/com/tmate/hgkit/ll/HgDataFile.java	Fri Jan 14 00:49:58 2011 +0100
@@ -41,25 +41,6 @@
 		return content(TIP);
 	}
 
-	public byte[] content(Nodeid nodeid) {
-		int revision = content.findLocalRevisionNumber(nodeid);
-		return content(revision);
-	}
-	
-	/**
-	 * @param revision - repo-local index of this file change (not a changelog revision number!)
-	 */
-	public byte[] content(int revision) {
-		final byte[][] dataPtr = new byte[1][];
-		Revlog.Inspector insp = new Revlog.Inspector() {
-			public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, byte[] data) {
-				dataPtr[0] = data;
-			}
-		};
-		content.iterate(revision, revision, true, insp);
-		return dataPtr[0];
-	}
-
 	public void history(Changeset.Inspector inspector) {
 		if (!exists()) {
 			throw new IllegalStateException("Can't get history of invalid repository file node"); 
--- a/src/com/tmate/hgkit/ll/Revlog.java	Thu Jan 13 23:31:39 2011 +0100
+++ b/src/com/tmate/hgkit/ll/Revlog.java	Fri Jan 14 00:49:58 2011 +0100
@@ -34,7 +34,30 @@
 	public int getRevisionCount() {
 		return content.revisionCount();
 	}
+
+	/**
+	 * Access to revision data as is (decompressed, but otherwise unprocessed, i.e. not parsed for e.g. changeset or manifest entries) 
+	 * @param nodeid
+	 */
+	public byte[] content(Nodeid nodeid) {
+		int revision = content.findLocalRevisionNumber(nodeid);
+		return content(revision);
+	}
 	
+	/**
+	 * @param revision - repo-local index of this file change (not a changelog revision number!)
+	 */
+	public byte[] content(int revision) {
+		final byte[][] dataPtr = new byte[1][];
+		Revlog.Inspector insp = new Revlog.Inspector() {
+			public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, byte[] data) {
+				dataPtr[0] = data;
+			}
+		};
+		content.iterate(revision, revision, true, insp);
+		return dataPtr[0];
+	}
+
 	// FIXME byte[] data might be too expensive, for few usecases it may be better to have intermediate Access object (when we don't need full data 
 	// instantly - e.g. calculate hash, or comparing two revisions
 	// XXX seems that RevlogStream is better place for this class. 
--- a/src/com/tmate/hgkit/ll/RevlogStream.java	Thu Jan 13 23:31:39 2011 +0100
+++ b/src/com/tmate/hgkit/ll/RevlogStream.java	Fri Jan 14 00:49:58 2011 +0100
@@ -284,7 +284,8 @@
 
 	// mpatch.c : apply()
 	// FIXME need to implement patch merge (fold, combine, gather and discard from aforementioned mpatch.[c|py]), also see Revlog and Mercurial PDF
-	private static byte[] apply(byte[] baseRevisionContent, int outcomeLen, List<PatchRecord> patch) {
+	// FIXME why 2 arrays (rv and tempBuf)???. Think over in-place merging (perhaps some sparse byte chunk list?) - to minimize mem use.
+	/*package-local for HgBundle; until moved to better place*/static byte[] apply(byte[] baseRevisionContent, int outcomeLen, List<PatchRecord> patch) {
 		byte[] tempBuf = new byte[outcomeLen]; // XXX
 		int last = 0, destIndex = 0;
 		for (PatchRecord pr : patch) {