tikhomirov@181: /* tikhomirov@419: * Copyright (c) 2011-2012 TMate Software Ltd tikhomirov@181: * tikhomirov@181: * This program is free software; you can redistribute it and/or modify tikhomirov@181: * it under the terms of the GNU General Public License as published by tikhomirov@181: * the Free Software Foundation; version 2 of the License. tikhomirov@181: * tikhomirov@181: * This program is distributed in the hope that it will be useful, tikhomirov@181: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@181: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@181: * GNU General Public License for more details. tikhomirov@181: * tikhomirov@181: * For information on how to redistribute this software under tikhomirov@181: * the terms of a license other than GNU General Public License tikhomirov@181: * contact TMate Software at support@hg4j.com tikhomirov@181: */ tikhomirov@181: package org.tmatesoft.hg.core; tikhomirov@181: tikhomirov@181: import java.util.List; tikhomirov@194: import java.util.Set; tikhomirov@194: import java.util.TreeSet; tikhomirov@181: tikhomirov@526: import org.tmatesoft.hg.internal.Internals; tikhomirov@192: import org.tmatesoft.hg.internal.RepositoryComparator; tikhomirov@192: import org.tmatesoft.hg.repo.HgChangelog; tikhomirov@423: import org.tmatesoft.hg.repo.HgInvalidControlFileException; tikhomirov@192: import org.tmatesoft.hg.repo.HgRemoteRepository; tikhomirov@181: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@427: import org.tmatesoft.hg.repo.HgRuntimeException; tikhomirov@432: import org.tmatesoft.hg.repo.HgParentChildMap; tikhomirov@215: import org.tmatesoft.hg.util.CancelSupport; tikhomirov@181: import org.tmatesoft.hg.util.CancelledException; tikhomirov@215: import org.tmatesoft.hg.util.ProgressSupport; tikhomirov@181: tikhomirov@181: /** tikhomirov@192: * Command to find out changes made in a local repository and missing at remote repository. tikhomirov@192: * tikhomirov@181: * @author Artem Tikhomirov tikhomirov@181: * @author TMate Software Ltd. tikhomirov@181: */ tikhomirov@215: public class HgOutgoingCommand extends HgAbstractCommand { tikhomirov@192: tikhomirov@192: private final HgRepository localRepo; tikhomirov@192: private HgRemoteRepository remoteRepo; tikhomirov@206: @SuppressWarnings("unused") tikhomirov@181: private boolean includeSubrepo; tikhomirov@192: private RepositoryComparator comparator; tikhomirov@432: private HgParentChildMap parentHelper; tikhomirov@194: private Set branches; tikhomirov@181: tikhomirov@181: public HgOutgoingCommand(HgRepository hgRepo) { tikhomirov@192: localRepo = hgRepo; tikhomirov@181: } tikhomirov@181: tikhomirov@181: /** tikhomirov@192: * @param hgRemote remoteRepository to compare against tikhomirov@192: * @return this for convenience tikhomirov@192: */ tikhomirov@192: public HgOutgoingCommand against(HgRemoteRepository hgRemote) { tikhomirov@192: remoteRepo = hgRemote; tikhomirov@192: comparator = null; tikhomirov@192: return this; tikhomirov@192: } tikhomirov@192: tikhomirov@192: /** tikhomirov@194: * Select specific branch to pull. tikhomirov@194: * Multiple branch specification possible (changeset from any of these would be included in result). tikhomirov@419: * Note, {@link #executeLite()} does not respect this setting. tikhomirov@192: * tikhomirov@194: * @param branch - branch name, case-sensitive, non-null. tikhomirov@181: * @return this for convenience tikhomirov@194: * @throws IllegalArgumentException when branch argument is null tikhomirov@181: */ tikhomirov@181: public HgOutgoingCommand branch(String branch) { tikhomirov@194: if (branch == null) { tikhomirov@194: throw new IllegalArgumentException(); tikhomirov@194: } tikhomirov@194: if (branches == null) { tikhomirov@194: branches = new TreeSet(); tikhomirov@194: } tikhomirov@194: branches.add(branch); tikhomirov@194: return this; tikhomirov@181: } tikhomirov@181: tikhomirov@181: /** tikhomirov@192: * PLACEHOLDER, NOT IMPLEMENTED YET. tikhomirov@181: * tikhomirov@181: * @return this for convenience tikhomirov@181: */ tikhomirov@181: public HgOutgoingCommand subrepo(boolean include) { tikhomirov@181: includeSubrepo = include; tikhomirov@526: throw Internals.notImplemented(); tikhomirov@181: } tikhomirov@181: tikhomirov@192: /** tikhomirov@194: * Lightweight check for outgoing changes. tikhomirov@194: * Reported changes are from any branch (limits set by {@link #branch(String)} are not taken into account. tikhomirov@192: * tikhomirov@192: * @return list on local nodes known to be missing at remote server tikhomirov@380: * @throws HgRemoteConnectionException when failed to communicate with remote repository tikhomirov@427: * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state tikhomirov@380: * @throws CancelledException if execution of the command was cancelled tikhomirov@192: */ tikhomirov@427: public List executeLite() throws HgRemoteConnectionException, HgException, CancelledException { tikhomirov@215: final ProgressSupport ps = getProgressSupport(null); tikhomirov@215: try { tikhomirov@215: ps.start(10); tikhomirov@322: return getComparator(new ProgressSupport.Sub(ps, 5), getCancelSupport(null, true)).getLocalOnlyRevisions(); tikhomirov@427: } catch (HgRuntimeException ex) { tikhomirov@427: throw new HgLibraryFailureException(ex); tikhomirov@215: } finally { tikhomirov@215: ps.done(); tikhomirov@215: } tikhomirov@181: } tikhomirov@181: tikhomirov@192: /** tikhomirov@192: * Complete information about outgoing changes tikhomirov@192: * tikhomirov@192: * @param handler delegate to process changes tikhomirov@427: * @throws HgCallbackTargetException propagated exception from the handler tikhomirov@380: * @throws HgRemoteConnectionException when failed to communicate with remote repository tikhomirov@427: * @throws HgException subclass thereof to indicate specific issue with the command arguments or repository state tikhomirov@380: * @throws CancelledException if execution of the command was cancelled tikhomirov@192: */ tikhomirov@427: public void executeFull(final HgChangesetHandler handler) throws HgCallbackTargetException, HgException, CancelledException { tikhomirov@192: if (handler == null) { tikhomirov@192: throw new IllegalArgumentException("Delegate can't be null"); tikhomirov@192: } tikhomirov@215: final ProgressSupport ps = getProgressSupport(handler); tikhomirov@322: final CancelSupport cs = getCancelSupport(handler, true); tikhomirov@215: try { tikhomirov@215: ps.start(-1); tikhomirov@215: ChangesetTransformer inspector = new ChangesetTransformer(localRepo, handler, getParentHelper(), ps, cs); tikhomirov@215: inspector.limitBranches(branches); tikhomirov@215: getComparator(new ProgressSupport.Sub(ps, 1), cs).visitLocalOnlyRevisions(inspector); tikhomirov@215: inspector.checkFailure(); tikhomirov@427: } catch (HgRuntimeException ex) { tikhomirov@427: throw new HgLibraryFailureException(ex); tikhomirov@215: } finally { tikhomirov@215: ps.done(); tikhomirov@215: } tikhomirov@192: } tikhomirov@192: tikhomirov@366: private RepositoryComparator getComparator(ProgressSupport ps, CancelSupport cs) throws HgRemoteConnectionException, HgInvalidControlFileException, CancelledException { tikhomirov@192: if (remoteRepo == null) { tikhomirov@192: throw new IllegalArgumentException("Shall specify remote repository to compare against"); tikhomirov@192: } tikhomirov@192: if (comparator == null) { tikhomirov@195: comparator = new RepositoryComparator(getParentHelper(), remoteRepo); tikhomirov@215: comparator.compare(ps, cs); tikhomirov@192: } tikhomirov@192: return comparator; tikhomirov@181: } tikhomirov@195: tikhomirov@432: private HgParentChildMap getParentHelper() throws HgInvalidControlFileException { tikhomirov@195: if (parentHelper == null) { tikhomirov@432: parentHelper = new HgParentChildMap(localRepo.getChangelog()); tikhomirov@195: parentHelper.init(); tikhomirov@195: } tikhomirov@195: return parentHelper; tikhomirov@195: } tikhomirov@195: tikhomirov@181: }