# HG changeset patch # User Artem Tikhomirov # Date 1294962598 -3600 # Node ID e45e75e22523aedf3c99fd792e9962d2b97b6100 # Parent 205f9b59b4009c612fe61ccdb85a4a880234efbc Parse changesets from bundle's changelog group. Refactor Revlog to provide access to revision's raw content diff -r 205f9b59b400 -r e45e75e22523 src/com/tmate/hgkit/console/Bundle.java --- 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); } } diff -r 205f9b59b400 -r e45e75e22523 src/com/tmate/hgkit/ll/HgBundle.java --- 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 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 names = new LinkedList(); @@ -34,12 +56,12 @@ System.out.println("Changelog group"); List 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 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 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); } - } } diff -r 205f9b59b400 -r e45e75e22523 src/com/tmate/hgkit/ll/HgDataFile.java --- 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"); diff -r 205f9b59b400 -r e45e75e22523 src/com/tmate/hgkit/ll/Revlog.java --- 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. diff -r 205f9b59b400 -r e45e75e22523 src/com/tmate/hgkit/ll/RevlogStream.java --- 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 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 patch) { byte[] tempBuf = new byte[outcomeLen]; // XXX int last = 0, destIndex = 0; for (PatchRecord pr : patch) {