Mercurial > jhg
diff src/org/tmatesoft/hg/core/HgRevertCommand.java @ 526:2f9ed6bcefa2
Initial support for Revert command with accompanying minor refactoring
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 15 Jan 2013 17:07:19 +0100 |
parents | |
children | 78a9e26e670d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/core/HgRevertCommand.java Tue Jan 15 17:07:19 2013 +0100 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.core; + +import java.io.File; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.tmatesoft.hg.internal.DirstateBuilder; +import org.tmatesoft.hg.internal.DirstateReader; +import org.tmatesoft.hg.internal.Experimental; +import org.tmatesoft.hg.internal.Internals; +import org.tmatesoft.hg.repo.HgInvalidRevisionException; +import org.tmatesoft.hg.repo.HgManifest; +import org.tmatesoft.hg.repo.HgRepository; +import org.tmatesoft.hg.repo.HgRuntimeException; +import org.tmatesoft.hg.repo.HgManifest.Flags; +import org.tmatesoft.hg.util.CancelledException; +import org.tmatesoft.hg.util.Path; + +/** + * WORK IN PROGRESS. + * + * Restore files to their checkout state, 'hg revert' counterpart. + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +@Experimental(reason="Work in progress") +public class HgRevertCommand extends HgAbstractCommand<HgRevertCommand> { + + private final HgRepository repo; + private final Set<Path> files = new LinkedHashSet<Path>(); + private int changesetToCheckout = HgRepository.WORKING_COPY; // XXX WORKING_COPY_PARENT, in fact + private boolean keepOriginal = true; + + public HgRevertCommand(HgRepository hgRepo) { + repo = hgRepo; + } + + /** + * Additive + * + * @param paths files to revert + * @return <code>this</code> for convenience + */ + public HgRevertCommand file(Path... paths) { + files.addAll(Arrays.asList(paths)); + return this; + } + + /** + * Revert the given files to their states as of a specific revision + * + * @param changesetRevIndex + * @return <code>this</code> for convenience + * @throws HgBadArgumentException + */ + public HgRevertCommand changeset(int changesetRevIndex) throws HgBadArgumentException { + int lastCsetIndex = repo.getChangelog().getLastRevision(); + if (changesetRevIndex < 0 || changesetRevIndex > lastCsetIndex) { + throw new HgBadArgumentException(String.format("Bad revision index %d, value from [0..%d] expected", changesetRevIndex, lastCsetIndex), null).setRevisionIndex(changesetRevIndex); + } + changesetToCheckout = changesetRevIndex; + return this; + } + + /** + * Handy supplement to {@link #changeset(int)} + * + * @param revision + * @return <code>this</code> for convenience + * @throws HgBadArgumentException + */ + public HgRevertCommand changeset(Nodeid revision) throws HgBadArgumentException { + try { + return changeset(repo.getChangelog().getRevisionIndex(revision)); + } catch (HgInvalidRevisionException ex) { + throw new HgBadArgumentException("Can't find revision", ex).setRevision(revision); + } + } + + // TODO keepOriginal() to save .orig + + /** + * Perform the back out for the given files + * + * @throws HgIOException + * @throws HgException + * @throws CancelledException + */ + public void execute() throws HgException, CancelledException { + try { + final int csetRevision; + if (changesetToCheckout == HgRepository.WORKING_COPY) { + csetRevision = repo.getChangelog().getRevisionIndex(repo.getWorkingCopyParents().first()); + } else { + csetRevision = changesetToCheckout; + } + Internals implRepo = Internals.getInstance(repo); + final DirstateBuilder dirstateBuilder = new DirstateBuilder(implRepo); + dirstateBuilder.fillFrom(new DirstateReader(implRepo, new Path.SimpleSource())); + final HgCheckoutCommand.CheckoutWorker worker = new HgCheckoutCommand.CheckoutWorker(implRepo); + + HgManifest.Inspector insp = new HgManifest.Inspector() { + + public boolean next(Nodeid nid, Path fname, Flags flags) { + if (worker.next(nid, fname, flags)) { + dirstateBuilder.recordUncertain(fname); + return true; + } + return false; + } + + public boolean end(int manifestRevision) { + return false; + } + + public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) { + return true; + } + }; + + for (Path file : files) { + File f = new File(repo.getWorkingDir(), file.toString()); + if (f.isFile()) { + if (keepOriginal) { + File copy = new File(f.getParentFile(), f.getName() + ".orig"); + if (copy.exists()) { + copy.delete(); + } + f.renameTo(copy); + } else { + f.delete(); + } + } + repo.getManifest().walkFileRevisions(file, insp, csetRevision); + worker.checkFailed(); + } + dirstateBuilder.serialize(); + } catch (HgRuntimeException ex) { + throw new HgLibraryFailureException(ex); + } + } +}