Mercurial > hg4j
diff src/org/tmatesoft/hg/internal/CommitFacility.java @ 617:65c01508f002
Rollback support for commands that modify repository. Strategy to keep complete copy of a file being changed
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 15 May 2013 20:10:09 +0200 |
parents | 5e0313485eef |
children | 7c0d2ce340b8 |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/CommitFacility.java Tue May 14 17:31:35 2013 +0200 +++ b/src/org/tmatesoft/hg/internal/CommitFacility.java Wed May 15 20:10:09 2013 +0200 @@ -19,6 +19,7 @@ import static org.tmatesoft.hg.repo.HgRepository.DEFAULT_BRANCH_NAME; import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; import static org.tmatesoft.hg.repo.HgRepositoryFiles.Branch; +import static org.tmatesoft.hg.repo.HgRepositoryFiles.UndoBranch; import static org.tmatesoft.hg.util.LogFacility.Severity.Error; import java.io.File; @@ -94,7 +95,9 @@ user = userName; } - public Nodeid commit(String message) throws HgIOException, HgRepositoryLockException { + // this method doesn't roll transaction back in case of failure, caller's responsibility + // this method expects repository to be locked, if needed + public Nodeid commit(String message, Transaction transaction) throws HgIOException, HgRepositoryLockException { final HgChangelog clog = repo.getRepo().getChangelog(); final int clogRevisionIndex = clog.getRevisionCount(); ManifestRevision c1Manifest = new ManifestRevision(null, null); @@ -161,7 +164,7 @@ // that would attempt to access newly added file after commit would fail // (despite the fact the file is in there) } - RevlogStreamWriter fileWriter = new RevlogStreamWriter(repo, contentStream); + RevlogStreamWriter fileWriter = new RevlogStreamWriter(repo, contentStream, transaction); Nodeid fileRev = fileWriter.addRevision(bac.toArray(), clogRevisionIndex, fp.first(), fp.second()); newManifestRevision.put(df.getPath(), fileRev); touchInDirstate.add(df.getPath()); @@ -172,7 +175,7 @@ for (Map.Entry<Path, Nodeid> me : newManifestRevision.entrySet()) { manifestBuilder.add(me.getKey().toString(), me.getValue()); } - RevlogStreamWriter manifestWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getManifestStream()); + RevlogStreamWriter manifestWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getManifestStream(), transaction); Nodeid manifestRev = manifestWriter.addRevision(manifestBuilder.build(), clogRevisionIndex, manifestParents.first(), manifestParents.second()); // // Changelog @@ -181,7 +184,7 @@ changelogBuilder.branch(branch == null ? DEFAULT_BRANCH_NAME : branch); changelogBuilder.user(String.valueOf(user)); byte[] clogContent = changelogBuilder.build(manifestRev, message); - RevlogStreamWriter changelogWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getChangelogStream()); + RevlogStreamWriter changelogWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getChangelogStream(), transaction); Nodeid changesetRev = changelogWriter.addRevision(clogContent, clogRevisionIndex, p1Commit, p2Commit); // TODO move fncache update to an external facility, along with dirstate and bookmark update if (!newlyAddedFiles.isEmpty() && repo.fncacheInUse()) { @@ -201,14 +204,19 @@ } String oldBranchValue = DirstateReader.readBranch(repo); String newBranchValue = branch == null ? DEFAULT_BRANCH_NAME : branch; + // TODO undo.dirstate and undo.branch as described in http://mercurial.selenic.com/wiki/FileFormats#undo..2A if (!oldBranchValue.equals(newBranchValue)) { - File branchFile = repo.getRepositoryFile(Branch); + File branchFile = transaction.prepare(repo.getRepositoryFile(Branch), repo.getRepositoryFile(UndoBranch)); FileOutputStream fos = null; try { fos = new FileOutputStream(branchFile); fos.write(newBranchValue.getBytes(EncodingHelper.getUTF8())); fos.flush(); + fos.close(); + fos = null; + transaction.done(branchFile); } catch (IOException ex) { + transaction.failure(branchFile, ex); repo.getLog().dump(getClass(), Error, ex, "Failed to write branch information, error ignored"); } finally { try { @@ -220,7 +228,7 @@ } } } - // bring dirstate up to commit state + // bring dirstate up to commit state, TODO share this code with HgAddRemoveCommand final DirstateBuilder dirstateBuilder = new DirstateBuilder(repo); dirstateBuilder.fillFrom(new DirstateReader(repo, new Path.SimpleSource())); for (Path p : removals) { @@ -230,12 +238,11 @@ dirstateBuilder.recordUncertain(p); } dirstateBuilder.parents(changesetRev, Nodeid.NULL); - dirstateBuilder.serialize(); + dirstateBuilder.serialize(transaction); // update bookmarks if (p1Commit != NO_REVISION || p2Commit != NO_REVISION) { repo.getRepo().getBookmarks().updateActive(p1Cset, p2Cset, changesetRev); } - // TODO undo.dirstate and undo.branch as described in http://mercurial.selenic.com/wiki/FileFormats#undo..2A // TODO Revisit: might be reasonable to send out a "Repo changed" notification, to clear // e.g. cached branch, tags and so on, not to rely on file change detection methods? // The same notification might come useful once Pull is implemented