# HG changeset patch # User Artem Tikhomirov # Date 1362065673 -3600 # Node ID ca56a36c2eeaee7559680e187e61f1da4dbef7e8 # Parent 6fbca6506bb50417f4d14c837479b8a9b1b81564 HgCheckoutCommand: clean parameter, discard changes in WD, test for clean checkout diff -r 6fbca6506bb5 -r ca56a36c2eea src/org/tmatesoft/hg/core/HgCheckoutCommand.java --- 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 true to discard any change + * @return this 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 this 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); } diff -r 6fbca6506bb5 -r ca56a36c2eea src/org/tmatesoft/hg/repo/CommitFacility.java --- 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; diff -r 6fbca6506bb5 -r ca56a36c2eea test/org/tmatesoft/hg/test/TestCheckout.java --- 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 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);