* @param hgRepo repository that shall possess base revision for this bundle
* @param inspector callback to get each changeset found
*/
public void changes(final HgRepository hgRepo, final HgChangelog.Inspector inspector) throws HgIOException, HgRuntimeException {
Inspector bundleInsp = new Inspector() {
DigestHelper dh = new DigestHelper();
boolean emptyChangelog = true;
private DataAccess prevRevContent;
private int revisionIndex;
private ChangesetParser csetBuilder;
public void changelogStart() {
emptyChangelog = true;
revisionIndex = 0;
csetBuilder = new ChangesetParser(hgRepo, new HgChangelog.RawCsetFactory(true));
}
public void changelogEnd() {
if (emptyChangelog) {
throw new IllegalStateException("No changelog group in the bundle"); // XXX perhaps, just be silent and/or log?
}
}
/*
* Despite that BundleFormat wiki says: "Each Changelog entry patches the result of all previous patches
* (the previous, or parent patch of a given patch p is the patch that has a node equal to p's p1 field)",
* it seems not to hold true. Instead, each entry patches previous one, regardless of whether the one
* before is its parent (i.e. ge.firstParent()) or not.
*
Actual state in the changelog.i
Index Offset Flags Packed Actual Base Rev Link Rev Parent1 Parent2 nodeid
50: 9212 0 209 329 48 50 49 -1 f1db8610da62a3e0beb8d360556ee1fd6eb9885e
51: 9421 0 278 688 48 51 50 -1 9429c7bd1920fab164a9d2b621d38d57bcb49ae0
52: 9699 0 154 179 52 52 50 -1 30bd389788464287cee22ccff54c330a4b715de5
53: 9853 0 133 204 52 53 51 52 a6f39e595b2b54f56304470269a936ead77f5725
54: 9986 0 156 182 54 54 52 -1 fd4f2c98995beb051070630c272a9be87bef617d
Excerpt from bundle (nodeid, p1, p2, cs):
f1db8610da62a3e0beb8d360556ee1fd6eb9885e 26e3eeaa39623de552b45ee1f55c14f36460f220 0000000000000000000000000000000000000000 f1db8610da62a3e0beb8d360556ee1fd6eb9885e; patches:4
9429c7bd1920fab164a9d2b621d38d57bcb49ae0 f1db8610da62a3e0beb8d360556ee1fd6eb9885e 0000000000000000000000000000000000000000 9429c7bd1920fab164a9d2b621d38d57bcb49ae0; patches:3
> 30bd389788464287cee22ccff54c330a4b715de5 f1db8610da62a3e0beb8d360556ee1fd6eb9885e 0000000000000000000000000000000000000000 30bd389788464287cee22ccff54c330a4b715de5; patches:3
a6f39e595b2b54f56304470269a936ead77f5725 9429c7bd1920fab164a9d2b621d38d57bcb49ae0 30bd389788464287cee22ccff54c330a4b715de5 a6f39e595b2b54f56304470269a936ead77f5725; patches:3
fd4f2c98995beb051070630c272a9be87bef617d 30bd389788464287cee22ccff54c330a4b715de5 0000000000000000000000000000000000000000 fd4f2c98995beb051070630c272a9be87bef617d; patches:3
To recreate 30bd..e5, one have to take content of 9429..e0, not its p1 f1db..5e
*/
public boolean element(GroupElement ge) throws IOException, HgRuntimeException {
emptyChangelog = false;
HgChangelog changelog = hgRepo.getChangelog();
try {
if (prevRevContent == null) {
if (ge.firstParent().isNull() && ge.secondParent().isNull()) {
prevRevContent = new ByteArrayDataAccess(new byte[0]);
} else {
final Nodeid base = ge.firstParent();
if (!changelog.isKnown(base) /*only first parent, that's Bundle contract*/) {
throw new IllegalStateException(String.format("Revision %s needs a parent %s, which is missing in the supplied repo %s", ge.node().shortNotation(), base.shortNotation(), hgRepo.toString()));
}
ByteArrayChannel bac = new ByteArrayChannel();
changelog.rawContent(base, bac); // TODO post-1.0 get DataAccess directly, to avoid
// extra byte[] (inside ByteArrayChannel) duplication just for the sake of subsequent ByteArrayDataChannel wrap.
prevRevContent = new ByteArrayDataAccess(bac.toArray());
}
}
//
byte[] csetContent = ge.patch().apply(prevRevContent, -1);
dh = dh.sha1(ge.firstParent(), ge.secondParent(), csetContent); // XXX ge may give me access to byte[] content of nodeid directly, perhaps, I don't need DH to be friend of Nodeid?
if (!ge.node().equalsTo(dh.asBinary())) {
throw new HgInvalidStateException(String.format("Integrity check failed on %s, node: %s", bundleFile, ge.node().shortNotation()));
}
RawChangeset cs = csetBuilder.parse(csetContent);
inspector.next(revisionIndex++, ge.node(), cs);
prevRevContent.done();