changeset 563:ca56a36c2eea

HgCheckoutCommand: clean parameter, discard changes in WD, test for clean checkout
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 28 Feb 2013 16:34:33 +0100
parents 6fbca6506bb5
children e6407313bab7
files src/org/tmatesoft/hg/core/HgCheckoutCommand.java src/org/tmatesoft/hg/repo/CommitFacility.java test/org/tmatesoft/hg/test/TestCheckout.java
diffstat 3 files changed, 66 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgCheckoutCommand.java	Thu Feb 28 15:57:04 2013 +0100
+++ b/src/org/tmatesoft/hg/core/HgCheckoutCommand.java	Thu Feb 28 16:34:33 2013 +0100
@@ -31,8 +31,12 @@
 import org.tmatesoft.hg.internal.Internals;
 import org.tmatesoft.hg.internal.WorkingDirFileWriter;
 import org.tmatesoft.hg.repo.HgDataFile;
+import org.tmatesoft.hg.repo.HgDirstate;
+import org.tmatesoft.hg.repo.HgInternals;
 import org.tmatesoft.hg.repo.HgInvalidRevisionException;
 import org.tmatesoft.hg.repo.HgManifest;
+import org.tmatesoft.hg.repo.HgDirstate.EntryKind;
+import org.tmatesoft.hg.repo.HgDirstate.Record;
 import org.tmatesoft.hg.repo.HgManifest.Flags;
 import org.tmatesoft.hg.repo.HgRepository;
 import org.tmatesoft.hg.repo.HgRuntimeException;
@@ -54,12 +58,26 @@
 
 	private final HgRepository repo;
 	private int revisionToCheckout = HgRepository.BAD_REVISION;
+	private boolean cleanCheckout;
 
 	public HgCheckoutCommand(HgRepository hgRepo) {
 		repo = hgRepo;
 	}
 	
 	/**
+	 * Whether to discard all uncommited changes prior to check-out.
+	 * 
+	 * NOTE, at the moment, only clean checkout is supported!
+	 *  
+	 * @param clean <code>true</code> to discard any change
+	 * @return <code>this</code> for convenience
+	 */
+	public HgCheckoutCommand clean(boolean clean) {
+		cleanCheckout = clean;
+		return this;
+	}
+	
+	/**
 	 * Select revision to check out
 	 * 
 	 * @param nodeid revision
@@ -77,12 +95,15 @@
 	/**
 	 * Select revision to check out using local revision index
 	 * 
-	 * @param changesetIndex local revision index
+	 * @param changesetIndex local revision index, or {@link HgRepository#TIP}
 	 * @return <code>this</code> for convenience
 	 * @throws HgBadArgumentException if failed to find supplied changeset 
 	 */
 	public HgCheckoutCommand changeset(int changesetIndex) throws HgBadArgumentException {
 		int lastCsetIndex = repo.getChangelog().getLastRevision();
+		if (changesetIndex == HgRepository.TIP) {
+			changesetIndex = lastCsetIndex;
+		}
 		if (changesetIndex < 0 || changesetIndex > lastCsetIndex) {
 			throw new HgBadArgumentException(String.format("Bad revision index %d, value from [0..%d] expected", changesetIndex, lastCsetIndex), null).setRevisionIndex(changesetIndex);
 		}
@@ -99,8 +120,24 @@
 	public void execute() throws HgException, CancelledException {
 		try {
 			Internals internalRepo = Internals.getInstance(repo);
-			// FIXME remove tracked files from wd (perhaps, just forget 'Added'?)
-			// TODO
+			if (cleanCheckout) {
+				// remove tracked files from wd (perhaps, just forget 'Added'?)
+				// for now, just delete each and every tracked file
+				// TODO WorkingCopy container with getFile(HgDataFile/Path) to access files in WD
+				HgDirstate dirstate = new HgInternals(repo).getDirstate();
+				dirstate.walk(new HgDirstate.Inspector() {
+					
+					public boolean next(EntryKind kind, Record entry) {
+						File f = new File(repo.getWorkingDir(), entry.name().toString());
+						if (f.exists()) {
+							f.delete();
+						}
+						return true;
+					}
+				});
+			} else {
+				throw new HgBadArgumentException("Sorry, only clean checkout is supported now, use #clean(true)", null);
+			}
 			final DirstateBuilder dirstateBuilder = new DirstateBuilder(internalRepo);
 			final CheckoutWorker worker = new CheckoutWorker(internalRepo);
 			HgManifest.Inspector insp = new HgManifest.Inspector() {
@@ -127,9 +164,9 @@
 			worker.checkFailed();
 			File dirstateFile = internalRepo.getRepositoryFile(Dirstate);
 			try {
-				FileChannel dirstate = new FileOutputStream(dirstateFile).getChannel();
-				dirstateBuilder.serialize(dirstate);
-				dirstate.close();
+				FileChannel dirstateFileChannel = new FileOutputStream(dirstateFile).getChannel();
+				dirstateBuilder.serialize(dirstateFileChannel);
+				dirstateFileChannel.close();
 			} catch (IOException ex) {
 				throw new HgIOException("Can't write down new directory state", ex, dirstateFile);
 			}
--- a/src/org/tmatesoft/hg/repo/CommitFacility.java	Thu Feb 28 15:57:04 2013 +0100
+++ b/src/org/tmatesoft/hg/repo/CommitFacility.java	Thu Feb 28 16:34:33 2013 +0100
@@ -36,7 +36,6 @@
 import org.tmatesoft.hg.internal.FNCacheFile;
 import org.tmatesoft.hg.internal.ManifestEntryBuilder;
 import org.tmatesoft.hg.internal.ManifestRevision;
-import org.tmatesoft.hg.internal.RequiresFile;
 import org.tmatesoft.hg.internal.RevlogStream;
 import org.tmatesoft.hg.internal.RevlogStreamWriter;
 import org.tmatesoft.hg.util.Pair;
--- a/test/org/tmatesoft/hg/test/TestCheckout.java	Thu Feb 28 15:57:04 2013 +0100
+++ b/test/org/tmatesoft/hg/test/TestCheckout.java	Thu Feb 28 16:34:33 2013 +0100
@@ -17,12 +17,13 @@
 package org.tmatesoft.hg.test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.tmatesoft.hg.repo.HgRepository.TIP;
 import static org.tmatesoft.hg.test.RepoUtils.cloneRepoToTempLocation;
 
 import java.io.File;
 import java.io.FileFilter;
 
-import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.tmatesoft.hg.core.HgCheckoutCommand;
@@ -48,12 +49,12 @@
 
 	@Test
 	public void testCleanCheckoutInEmptyDir() throws Exception {
-		File testRepoLoc = cloneRepoToTempLocation("log-1", "test-checkoutClean", true);
+		File testRepoLoc = cloneRepoToTempLocation("log-1", "test-checkout-clean", true);
 		repo = new HgLookup().detect(testRepoLoc);
 		// nothing but .hg dir
 		assertEquals("[sanity]", 0, testRepoLoc.listFiles(new FilesOnlyFilter()).length);
 		
-		new HgCheckoutCommand(repo).changeset(1).execute();
+		new HgCheckoutCommand(repo).clean(true).changeset(1).execute();
 		errorCollector.assertEquals(2, testRepoLoc.listFiles(new FilesOnlyFilter()).length);
 
 		Pair<Nodeid, Nodeid> workingCopyParents = repo.getWorkingCopyParents();
@@ -68,7 +69,7 @@
 		errorCollector.assertTrue(statusOutputParser.getClean().contains(Path.create("a")));
 		errorCollector.assertTrue(statusOutputParser.getClean().contains(Path.create("b")));
 		
-		new HgCheckoutCommand(repo).changeset(3).execute();
+		new HgCheckoutCommand(repo).clean(true).changeset(3).execute();
 		statusOutputParser.reset();
 		eh.run("hg", "status", "-A");
 		errorCollector.assertEquals(3, statusOutputParser.getClean().size());
@@ -77,9 +78,24 @@
 		errorCollector.assertTrue(statusOutputParser.getClean().contains(Path.create("dir/b")));
 	}
 
+	/**
+	 * Make sure WC is cleared prior to clean checkout
+	 */
 	@Test
-	public void testCleanCheckoutInDirtyDir() {
-		Assert.fail("Make sure WC is cleared prior to clean checkout");
+	public void testCleanCheckoutInDirtyDir() throws Exception {
+		File repoLoc = cloneRepoToTempLocation("log-1", "test-checkout-dirty", false);
+		File untrackedFile = new File(repoLoc, "aaa");
+		RepoUtils.createFile(untrackedFile, "shall survive hg co --clean");
+		File modifiedFile = new File(repoLoc, "b");
+		assertTrue("[sanity]", modifiedFile.canRead());
+		final long modifiedFileInitialLen = modifiedFile.length();
+		RepoUtils.modifyFileAppend(modifiedFile, "the change shall not survive");
+		assertTrue("[sanity]", modifiedFile.length() > modifiedFileInitialLen);
+		//
+		repo = new HgLookup().detect(repoLoc);
+		new HgCheckoutCommand(repo).clean(true).changeset(TIP).execute();
+		errorCollector.assertTrue(untrackedFile.canRead());
+		errorCollector.assertEquals(modifiedFileInitialLen, modifiedFile.length());
 	}
 
 	@Test
@@ -87,7 +103,7 @@
 		File testRepoLoc = cloneRepoToTempLocation("log-branches", "test-checkoutBranch", true);
 		repo = new HgLookup().detect(testRepoLoc);
 		
-		new HgCheckoutCommand(repo).changeset(3 /*branch test*/).execute();
+		new HgCheckoutCommand(repo).clean(true).changeset(3 /*branch test*/).execute();
 
 		StatusOutputParser statusOutputParser = new StatusOutputParser();
 		eh = new ExecHelper(statusOutputParser, testRepoLoc);