public Nodeid commit(String message, Transaction transaction) throws HgIOException, HgRepositoryLockException, HgRuntimeException {
final HgChangelog clog = repo.getRepo().getChangelog();
final int clogRevisionIndex = clog.getRevisionCount();
ManifestRevision c1Manifest = new ManifestRevision(null, null);
ManifestRevision c2Manifest = new ManifestRevision(null, null);
final Nodeid p1Cset = p1Commit == NO_REVISION ? null : clog.getRevision(p1Commit);
final Nodeid p2Cset = p2Commit == NO_REVISION ? null : clog.getRevision(p2Commit);
if (p1Commit != NO_REVISION) {
repo.getRepo().getManifest().walk(p1Commit, p1Commit, c1Manifest);
}
if (p2Commit != NO_REVISION) {
repo.getRepo().getManifest().walk(p2Commit, p2Commit, c2Manifest);
}
// Pair<Integer, Integer> manifestParents = getManifestParents();
Pair<Integer, Integer> manifestParents = new Pair<Integer, Integer>(c1Manifest.revisionIndex(), c2Manifest.revisionIndex());
TreeMap<Path, Nodeid> newManifestRevision = new TreeMap<Path, Nodeid>();
HashMap<Path, Pair<Integer, Integer>> fileParents = new HashMap<Path, Pair<Integer,Integer>>();
for (Path f : c1Manifest.files()) {
HgDataFile df = repo.getRepo().getFileNode(f);
Nodeid fileKnownRev1 = c1Manifest.nodeid(f), fileKnownRev2;
final int fileRevIndex1 = df.getRevisionIndex(fileKnownRev1);
final int fileRevIndex2;
if ((fileKnownRev2 = c2Manifest.nodeid(f)) != null) {
// merged files
fileRevIndex2 = df.getRevisionIndex(fileKnownRev2);
} else {
fileRevIndex2 = NO_REVISION;
}
fileParents.put(f, new Pair<Integer, Integer>(fileRevIndex1, fileRevIndex2));
newManifestRevision.put(f, fileKnownRev1);
}
//
// Forget removed
for (Path p : removals) {
newManifestRevision.remove(p);
}
//
saveCommitMessage(message);
//
// Register new/changed
FNCacheFile.Mediator fncache = new FNCacheFile.Mediator(repo, transaction);
ArrayList<Path> touchInDirstate = new ArrayList<Path>();
for (Pair<HgDataFile, DataSource> e : files.values()) {
HgDataFile df = e.first();
DataSource bds = e.second();
Pair<Integer, Integer> fp = fileParents.get(df.getPath());
if (fp == null) {
// NEW FILE, either just added or resurrected from p2
Nodeid fileRevInP2;
if ((fileRevInP2 = c2Manifest.nodeid(df.getPath())) != null) {
fp = new Pair<Integer, Integer>(df.getRevisionIndex(fileRevInP2), NO_REVISION);
} else {
// brand new
fp = new Pair<Integer, Integer>(NO_REVISION, NO_REVISION);
}
}
// TODO if fp.first() != NO_REVISION and fp.second() != NO_REVISION check if one
// revision is ancestor of another and use the latest as p1, then
Nodeid fileRev = null;
final boolean isNewFile = !df.exists();
if (fp.first() != NO_REVISION && fp.second() == NO_REVISION && !isNewFile) {
// compare file contents to see if anything has changed, and reuse old revision, if unchanged.
// XXX ineffective, need better access to revision conten
ByteArraySerializer bas = new ByteArraySerializer();
bds.serialize(bas);
final byte[] newContent = bas.toByteArray();
// unless there's a way to reset DataSource, replace it with the content just read
bds = new DataSerializer.ByteArrayDataSource(newContent);
if (new ComparatorChannel(newContent).same(df, fp.first())) {
fileRev = df.getRevision(fp.first());
}
}
if (fileRev == null) {
RevlogStream contentStream = repo.getImplAccess().getStream(df);
RevlogStreamWriter fileWriter = new RevlogStreamWriter(repo, contentStream, transaction);
fileRev = fileWriter.addRevision(bds, clogRevisionIndex, fp.first(), fp.second()).second();
if (isNewFile) {
// registerNew shall go after fileWriter.addRevision as it needs to know if data is inlined or not
fncache.registerNew(df.getPath(), contentStream);
}
}
newManifestRevision.put(df.getPath(), fileRev);
touchInDirstate.add(df.getPath());
}
//
final EncodingHelper encHelper = repo.buildFileNameEncodingHelper();
//
// Manifest
final ManifestEntryBuilder manifestBuilder = new ManifestEntryBuilder(encHelper);
for (Map.Entry<Path, Nodeid> me : newManifestRevision.entrySet()) {
manifestBuilder.add(me.getKey().toString(), me.getValue());
}
RevlogStreamWriter manifestWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getManifestStream(), transaction);
Nodeid manifestRev = manifestWriter.addRevision(manifestBuilder, clogRevisionIndex, manifestParents.first(), manifestParents.second()).second();
//
// Changelog
final ChangelogEntryBuilder changelogBuilder = new ChangelogEntryBuilder(encHelper);
changelogBuilder.setModified(files.keySet());
changelogBuilder.branch(branch == null ? DEFAULT_BRANCH_NAME : branch);
changelogBuilder.user(String.valueOf(user));
changelogBuilder.manifest(manifestRev).comment(message);
RevlogStreamWriter changelogWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getChangelogStream(), transaction);
Nodeid changesetRev = changelogWriter.addRevision(changelogBuilder, clogRevisionIndex, p1Commit, p2Commit).second();
// TODO move dirstate and bookmark update update to an external facility
fncache.complete();
String oldBranchValue = DirstateReader.readBranch(repo);
String newBranchValue = branch == null ? DEFAULT_BRANCH_NAME : branch;
if (!oldBranchValue.equals(newBranchValue)) {