changeset 605:c56edf42be64

Commit: update active bookmark with new revision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 06 May 2013 20:28:21 +0200
parents c3505001a42a
children 5daa42067e7c
files src/org/tmatesoft/hg/internal/CommitFacility.java src/org/tmatesoft/hg/repo/HgBookmarks.java src/org/tmatesoft/hg/repo/HgRepositoryLock.java test/org/tmatesoft/hg/test/TestCommit.java
diffstat 4 files changed, 106 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/CommitFacility.java	Mon May 06 18:53:04 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/CommitFacility.java	Mon May 06 20:28:21 2013 +0200
@@ -180,7 +180,7 @@
 		byte[] clogContent = changelogBuilder.build(manifestRev, message);
 		RevlogStreamWriter changelogWriter = new RevlogStreamWriter(repo, repo.getImplAccess().getChangelogStream());
 		Nodeid changesetRev = changelogWriter.addRevision(clogContent, clogRevisionIndex, p1Commit, p2Commit);
-		// FIXME move fncache update to an external facility, along with dirstate update
+		// FIXME move fncache update to an external facility, along with dirstate and bookmark update
 		if (!newlyAddedFiles.isEmpty() && repo.fncacheInUse()) {
 			FNCacheFile fncache = new FNCacheFile(repo);
 			for (Path p : newlyAddedFiles) {
@@ -204,6 +204,12 @@
 		}
 		dirstateBuilder.parents(changesetRev, Nodeid.NULL);
 		dirstateBuilder.serialize();
+		// update bookmarks
+		Nodeid p1Cset = p1Commit == NO_REVISION ? null : clog.getRevision(p1Commit);
+		Nodeid p2Cset = p2Commit == NO_REVISION ? null : clog.getRevision(p2Commit);
+		if (p1Commit != NO_REVISION || p2Commit != NO_REVISION) {
+			repo.getRepo().getBookmarks().updateActive(p1Cset, p2Cset, changesetRev);
+		}
 		return changesetRev;
 	}
 /*
--- a/src/org/tmatesoft/hg/repo/HgBookmarks.java	Mon May 06 18:53:04 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgBookmarks.java	Mon May 06 20:28:21 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 TMate Software Ltd
+ * Copyright (c) 2012-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,20 +16,28 @@
  */
 package org.tmatesoft.hg.repo;
 
+import static org.tmatesoft.hg.util.LogFacility.Severity.Error;
+
 import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+import org.tmatesoft.hg.core.HgIOException;
+import org.tmatesoft.hg.core.HgRepositoryLockException;
 import org.tmatesoft.hg.core.Nodeid;
+import org.tmatesoft.hg.internal.Experimental;
 import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.internal.LineReader;
 import org.tmatesoft.hg.util.LogFacility;
 
 /**
  * 
+ * @see http://mercurial.selenic.com/wiki/Bookmarks
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
@@ -114,4 +122,61 @@
 		// hence can use view (not a synchronized copy) here
 		return Collections.unmodifiableSet(bookmarks.keySet());
 	}
+
+	/**
+	 * Update currently bookmark with new commit.
+	 * Note, child has to be descendant of a p1 or p2
+	 * 
+	 * @param p1 first parent, or <code>null</code>
+	 * @param p2 second parent, or <code>null</code>
+	 * @param child new commit, descendant of one of the parents, not <code>null</code>
+	 * @throws HgIOException if failed to write updated bookmark information 
+	 * @throws HgRepositoryLockException  if failed to lock repository for modifications
+	 */
+	@Experimental(reason="Provisional API")
+	public void updateActive(Nodeid p1, Nodeid p2, Nodeid child) throws HgIOException, HgRepositoryLockException {
+		if (activeBookmark == null) {
+			return;
+		}
+		Nodeid activeRev = getRevision(activeBookmark);
+		if (!activeRev.equals(p1) && !activeRev.equals(p2)) {
+			// from the wiki:
+			// "active bookmarks are automatically updated when committing to the changeset they are pointing to"
+			// FIXME: test ci 1, hg bookmark active, ci 2, hg bookmark -f -r 0 active, ci 3, check active still points to r0 
+			return;
+		}
+		if (child.equals(activeRev)) {
+			return;
+		}
+		LinkedHashMap<String, Nodeid> copy = new LinkedHashMap<String, Nodeid>(bookmarks);
+		copy.put(activeBookmark, child);
+		bookmarks = copy;
+		write();
+	}
+	
+	private void write() throws HgIOException, HgRepositoryLockException {
+		File bookmarksFile = internalRepo.getRepositoryFile(HgRepositoryFiles.Bookmarks);
+		HgRepositoryLock workingDirLock = internalRepo.getRepo().getWorkingDirLock();
+		FileWriter fileWriter = null;
+		workingDirLock.acquire();
+		try {
+			fileWriter = new FileWriter(bookmarksFile);
+			for (String bm : bookmarks.keySet()) {
+				Nodeid nid = bookmarks.get(bm);
+				fileWriter.write(String.format("%s %s\n", nid.toString(), bm));
+			}
+			fileWriter.flush();
+		} catch (IOException ex) {
+			throw new HgIOException("Failed to serialize bookmarks", ex, bookmarksFile);
+		} finally {
+			try {
+				if (fileWriter != null) {
+					fileWriter.close();
+				}
+			} catch (IOException ex) {
+				internalRepo.getSessionContext().getLog().dump(getClass(), Error, ex, null);
+			}
+			workingDirLock.release();
+		}
+	}
 }
--- a/src/org/tmatesoft/hg/repo/HgRepositoryLock.java	Mon May 06 18:53:04 2013 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRepositoryLock.java	Mon May 06 20:28:21 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 TMate Software Ltd
+ * Copyright (c) 2012-2013 TMate Software Ltd
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -99,7 +99,7 @@
 
 	/**
 	 * Perform actual locking. Waits for timeout (if specified at construction time)
-	 * before throwing {@link HgInvalidStateException} in case lock is not available 
+	 * before throwing {@link HgRepositoryLockException} in case lock is not available 
 	 * immediately.
 	 * 
 	 * <p>Multiple calls are possible, but corresponding number of {@link #release()} 
--- a/test/org/tmatesoft/hg/test/TestCommit.java	Mon May 06 18:53:04 2013 +0200
+++ b/test/org/tmatesoft/hg/test/TestCommit.java	Mon May 06 20:28:21 2013 +0200
@@ -277,6 +277,37 @@
 		assertHgVerifyOk(repoLoc);
 	}
 	
+	@Test
+	public void testUpdateActiveBookmark() throws Exception {
+		File repoLoc = RepoUtils.cloneRepoToTempLocation("log-1", "test-commit-cmd", false);
+		ExecHelper eh = new ExecHelper(new OutputParser.Stub(), repoLoc);
+		String activeBookmark = "bm1";
+		eh.run("hg", "bookmarks", activeBookmark);
+
+		HgRepository hgRepo = new HgLookup().detect(repoLoc);
+		assertEquals("[sanity]", activeBookmark, hgRepo.getBookmarks().getActiveBookmarkName());
+		Nodeid activeBookmarkRevision = hgRepo.getBookmarks().getRevision(activeBookmark);
+		assertEquals("[sanity]", activeBookmarkRevision, hgRepo.getWorkingCopyParents().first());
+		
+		HgDataFile dfD = hgRepo.getFileNode("d");
+		File fileD = new File(repoLoc, "d");
+		assertTrue("[sanity]", dfD.exists());
+		assertTrue("[sanity]", fileD.canRead());
+
+		RepoUtils.modifyFileAppend(fileD, " 1 \n");
+		HgCommitCommand cmd = new HgCommitCommand(hgRepo).message("FIRST");
+		Outcome r = cmd.execute();
+		errorCollector.assertTrue(r.isOk());
+		Nodeid c = cmd.getCommittedRevision();
+		
+		errorCollector.assertEquals(activeBookmark, hgRepo.getBookmarks().getActiveBookmarkName());
+		errorCollector.assertEquals(c, hgRepo.getBookmarks().getRevision(activeBookmark));
+		// reload repo, and repeat the check
+		hgRepo = new HgLookup().detect(repoLoc);
+		errorCollector.assertEquals(activeBookmark, hgRepo.getBookmarks().getActiveBookmarkName());
+		errorCollector.assertEquals(c, hgRepo.getBookmarks().getRevision(activeBookmark));
+	}
+	
 	private void assertHgVerifyOk(File repoLoc) throws InterruptedException, IOException {
 		ExecHelper verifyRun = new ExecHelper(new OutputParser.Stub(), repoLoc);
 		verifyRun.run("hg", "verify");