tikhomirov@64: /* tikhomirov@64: * Copyright (c) 2011 TMate Software Ltd tikhomirov@64: * tikhomirov@64: * This program is free software; you can redistribute it and/or modify tikhomirov@64: * it under the terms of the GNU General Public License as published by tikhomirov@64: * the Free Software Foundation; version 2 of the License. tikhomirov@64: * tikhomirov@64: * This program is distributed in the hope that it will be useful, tikhomirov@64: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@64: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@64: * GNU General Public License for more details. tikhomirov@64: * tikhomirov@64: * For information on how to redistribute this software under tikhomirov@64: * the terms of a license other than GNU General Public License tikhomirov@102: * contact TMate Software at support@hg4j.com tikhomirov@64: */ tikhomirov@64: package org.tmatesoft.hg.core; tikhomirov@64: tikhomirov@109: import static org.tmatesoft.hg.core.StatusCommand.HgStatus.Kind.*; tikhomirov@109: import static org.tmatesoft.hg.repo.HgRepository.*; tikhomirov@68: tikhomirov@93: import java.util.ConcurrentModificationException; tikhomirov@93: tikhomirov@64: import org.tmatesoft.hg.core.Path.Matcher; tikhomirov@109: import org.tmatesoft.hg.core.StatusCommand.HgStatus.Kind; tikhomirov@74: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@109: import org.tmatesoft.hg.repo.HgStatusCollector; tikhomirov@93: import org.tmatesoft.hg.repo.HgStatusInspector; tikhomirov@94: import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector; tikhomirov@64: tikhomirov@64: /** tikhomirov@64: * tikhomirov@64: * @author Artem Tikhomirov tikhomirov@64: * @author TMate Software Ltd. tikhomirov@64: */ tikhomirov@64: public class StatusCommand { tikhomirov@64: private final HgRepository repo; tikhomirov@64: tikhomirov@68: private int startRevision = TIP; tikhomirov@68: private int endRevision = WORKING_COPY; tikhomirov@64: private boolean visitSubRepo = true; tikhomirov@93: tikhomirov@109: private Handler handler; tikhomirov@93: private final Mediator mediator = new Mediator(); tikhomirov@64: tikhomirov@68: public StatusCommand(HgRepository hgRepo) { tikhomirov@68: repo = hgRepo; tikhomirov@68: defaults(); tikhomirov@64: } tikhomirov@64: tikhomirov@68: public StatusCommand defaults() { tikhomirov@93: final Mediator m = mediator; tikhomirov@93: m.needModified = m.needAdded = m.needRemoved = m.needUnknown = m.needMissing = true; tikhomirov@99: m.needCopies = m.needClean = m.needIgnored = false; tikhomirov@64: return this; tikhomirov@64: } tikhomirov@68: public StatusCommand all() { tikhomirov@93: final Mediator m = mediator; tikhomirov@93: m.needModified = m.needAdded = m.needRemoved = m.needUnknown = m.needMissing = true; tikhomirov@99: m.needCopies = m.needClean = m.needIgnored = true; tikhomirov@68: return this; tikhomirov@68: } tikhomirov@68: tikhomirov@64: tikhomirov@68: public StatusCommand modified(boolean include) { tikhomirov@93: mediator.needModified = include; tikhomirov@68: return this; tikhomirov@68: } tikhomirov@68: public StatusCommand added(boolean include) { tikhomirov@93: mediator.needAdded = include; tikhomirov@68: return this; tikhomirov@68: } tikhomirov@68: public StatusCommand removed(boolean include) { tikhomirov@93: mediator.needRemoved = include; tikhomirov@68: return this; tikhomirov@68: } tikhomirov@68: public StatusCommand deleted(boolean include) { tikhomirov@93: mediator.needMissing = include; tikhomirov@68: return this; tikhomirov@68: } tikhomirov@68: public StatusCommand unknown(boolean include) { tikhomirov@93: mediator.needUnknown = include; tikhomirov@68: return this; tikhomirov@68: } tikhomirov@64: public StatusCommand clean(boolean include) { tikhomirov@93: mediator.needClean = include; tikhomirov@64: return this; tikhomirov@64: } tikhomirov@64: public StatusCommand ignored(boolean include) { tikhomirov@93: mediator.needIgnored = include; tikhomirov@64: return this; tikhomirov@64: } tikhomirov@64: tikhomirov@68: /** tikhomirov@68: * if set, either base:revision or base:workingdir tikhomirov@68: * to unset, pass {@link HgRepository#TIP} or {@link HgRepository#BAD_REVISION} tikhomirov@68: * @param revision tikhomirov@68: * @return tikhomirov@68: */ tikhomirov@68: tikhomirov@64: public StatusCommand base(int revision) { tikhomirov@68: if (revision == WORKING_COPY) { tikhomirov@68: throw new IllegalArgumentException(); tikhomirov@68: } tikhomirov@68: if (revision == BAD_REVISION) { tikhomirov@68: revision = TIP; tikhomirov@68: } tikhomirov@64: startRevision = revision; tikhomirov@64: return this; tikhomirov@64: } tikhomirov@64: tikhomirov@68: /** tikhomirov@68: * Revision without base == --change tikhomirov@68: * Pass {@link HgRepository#WORKING_COPY} or {@link HgRepository#BAD_REVISION} to reset tikhomirov@68: * @param revision tikhomirov@68: * @return tikhomirov@68: */ tikhomirov@64: public StatusCommand revision(int revision) { tikhomirov@68: if (revision == BAD_REVISION) { tikhomirov@68: revision = WORKING_COPY; tikhomirov@68: } tikhomirov@68: // XXX negative values, except for predefined constants, shall throw IAE. tikhomirov@68: endRevision = revision; tikhomirov@64: return this; tikhomirov@64: } tikhomirov@64: tikhomirov@93: // pass null to reset tikhomirov@64: public StatusCommand match(Path.Matcher pathMatcher) { tikhomirov@93: mediator.matcher = pathMatcher; tikhomirov@123: return this; tikhomirov@64: } tikhomirov@64: tikhomirov@64: public StatusCommand subrepo(boolean visit) { tikhomirov@64: visitSubRepo = visit; tikhomirov@64: throw HgRepository.notImplemented(); tikhomirov@64: } tikhomirov@93: tikhomirov@93: /** tikhomirov@93: * Perform status operation according to parameters set. tikhomirov@93: * tikhomirov@93: * @param handler callback to get status information tikhomirov@93: * @throws IllegalArgumentException if handler is null tikhomirov@93: * @throws ConcurrentModificationException if this command already runs (i.e. being used from another thread) tikhomirov@93: */ tikhomirov@109: public void execute(Handler statusHandler) { tikhomirov@109: if (statusHandler == null) { tikhomirov@93: throw new IllegalArgumentException(); tikhomirov@93: } tikhomirov@109: if (handler != null) { tikhomirov@93: throw new ConcurrentModificationException(); tikhomirov@93: } tikhomirov@109: handler = statusHandler; tikhomirov@94: HgStatusCollector sc = new HgStatusCollector(repo); // TODO from CommandContext tikhomirov@93: // PathPool pathHelper = new PathPool(repo.getPathHelper()); // TODO from CommandContext tikhomirov@93: try { tikhomirov@93: // XXX if I need a rough estimation (for ProgressMonitor) of number of work units, tikhomirov@93: // I may use number of files in either rev1 or rev2 manifest edition tikhomirov@93: mediator.start(); tikhomirov@93: if (endRevision == WORKING_COPY) { tikhomirov@94: HgWorkingCopyStatusCollector wcsc = new HgWorkingCopyStatusCollector(repo); tikhomirov@93: wcsc.setBaseRevisionCollector(sc); tikhomirov@93: wcsc.walk(startRevision, mediator); tikhomirov@68: } else { tikhomirov@93: if (startRevision == TIP) { tikhomirov@93: sc.change(endRevision, mediator); tikhomirov@93: } else { tikhomirov@93: sc.walk(startRevision, endRevision, mediator); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } finally { tikhomirov@93: mediator.done(); tikhomirov@109: handler = null; tikhomirov@93: } tikhomirov@93: } tikhomirov@93: tikhomirov@109: public interface Handler { tikhomirov@109: void handleStatus(HgStatus s); tikhomirov@109: } tikhomirov@109: tikhomirov@109: public static class HgStatus { tikhomirov@109: public enum Kind { tikhomirov@109: Modified, Added, Removed, Unknown, Missing, Clean, Ignored tikhomirov@109: }; tikhomirov@109: private final Kind kind; tikhomirov@109: private final Path path; tikhomirov@109: private final Path origin; tikhomirov@109: tikhomirov@109: HgStatus(Kind kind, Path path) { tikhomirov@109: this(kind, path, null); tikhomirov@109: } tikhomirov@109: tikhomirov@109: HgStatus(Kind kind, Path path, Path copyOrigin) { tikhomirov@109: this.kind = kind; tikhomirov@109: this.path = path; tikhomirov@109: origin = copyOrigin; tikhomirov@109: } tikhomirov@109: tikhomirov@109: public Kind getKind() { tikhomirov@109: return kind; tikhomirov@109: } tikhomirov@109: tikhomirov@109: public Path getPath() { tikhomirov@109: return path; tikhomirov@109: } tikhomirov@109: tikhomirov@109: public Path getOriginalPath() { tikhomirov@109: return origin; tikhomirov@109: } tikhomirov@109: tikhomirov@109: public boolean isCopy() { tikhomirov@109: return origin != null; tikhomirov@109: } tikhomirov@109: } tikhomirov@109: tikhomirov@109: tikhomirov@93: private class Mediator implements HgStatusInspector { tikhomirov@93: boolean needModified; tikhomirov@93: boolean needAdded; tikhomirov@93: boolean needRemoved; tikhomirov@93: boolean needUnknown; tikhomirov@93: boolean needMissing; tikhomirov@93: boolean needClean; tikhomirov@93: boolean needIgnored; tikhomirov@99: boolean needCopies; tikhomirov@93: Matcher matcher; tikhomirov@93: tikhomirov@93: Mediator() { tikhomirov@93: } tikhomirov@93: tikhomirov@93: public void start() { tikhomirov@93: tikhomirov@93: } tikhomirov@93: public void done() { tikhomirov@93: } tikhomirov@93: tikhomirov@93: public void modified(Path fname) { tikhomirov@93: if (needModified) { tikhomirov@93: if (matcher == null || matcher.accept(fname)) { tikhomirov@109: handler.handleStatus(new HgStatus(Modified, fname)); tikhomirov@93: } tikhomirov@68: } tikhomirov@68: } tikhomirov@93: public void added(Path fname) { tikhomirov@93: if (needAdded) { tikhomirov@93: if (matcher == null || matcher.accept(fname)) { tikhomirov@109: handler.handleStatus(new HgStatus(Added, fname)); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } tikhomirov@93: public void removed(Path fname) { tikhomirov@93: if (needRemoved) { tikhomirov@93: if (matcher == null || matcher.accept(fname)) { tikhomirov@109: handler.handleStatus(new HgStatus(Removed, fname)); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } tikhomirov@93: public void copied(Path fnameOrigin, Path fnameAdded) { tikhomirov@93: if (needCopies) { tikhomirov@93: if (matcher == null || matcher.accept(fnameAdded)) { tikhomirov@109: handler.handleStatus(new HgStatus(Kind.Added, fnameAdded, fnameOrigin)); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } tikhomirov@93: public void missing(Path fname) { tikhomirov@93: if (needMissing) { tikhomirov@93: if (matcher == null || matcher.accept(fname)) { tikhomirov@109: handler.handleStatus(new HgStatus(Missing, fname)); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } tikhomirov@93: public void unknown(Path fname) { tikhomirov@93: if (needUnknown) { tikhomirov@93: if (matcher == null || matcher.accept(fname)) { tikhomirov@109: handler.handleStatus(new HgStatus(Unknown, fname)); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } tikhomirov@93: public void clean(Path fname) { tikhomirov@93: if (needClean) { tikhomirov@93: if (matcher == null || matcher.accept(fname)) { tikhomirov@109: handler.handleStatus(new HgStatus(Clean, fname)); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } tikhomirov@93: public void ignored(Path fname) { tikhomirov@93: if (needIgnored) { tikhomirov@93: if (matcher == null || matcher.accept(fname)) { tikhomirov@109: handler.handleStatus(new HgStatus(Ignored, fname)); tikhomirov@93: } tikhomirov@93: } tikhomirov@93: } tikhomirov@64: } tikhomirov@64: }