tikhomirov@181: /* tikhomirov@181: * Copyright (c) 2011 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@192: import java.io.IOException; tikhomirov@192: import java.util.ArrayList; tikhomirov@192: import java.util.LinkedHashSet; tikhomirov@192: import java.util.LinkedList; tikhomirov@181: import java.util.List; tikhomirov@181: tikhomirov@192: import org.tmatesoft.hg.internal.RepositoryComparator; tikhomirov@192: import org.tmatesoft.hg.internal.RepositoryComparator.BranchChain; tikhomirov@192: import org.tmatesoft.hg.repo.HgBundle; tikhomirov@192: import org.tmatesoft.hg.repo.HgChangelog; tikhomirov@192: import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; tikhomirov@192: import org.tmatesoft.hg.repo.HgRemoteRepository; tikhomirov@181: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@181: import org.tmatesoft.hg.util.CancelledException; tikhomirov@181: tikhomirov@181: /** tikhomirov@192: * Command to find out changes available in a remote repository, missing locally. tikhomirov@192: * tikhomirov@181: * @author Artem Tikhomirov tikhomirov@181: * @author TMate Software Ltd. tikhomirov@181: */ tikhomirov@181: public class HgIncomingCommand { tikhomirov@181: tikhomirov@192: private final HgRepository localRepo; tikhomirov@192: private HgRemoteRepository remoteRepo; tikhomirov@181: private boolean includeSubrepo; tikhomirov@192: private RepositoryComparator comparator; tikhomirov@192: private List missingBranches; tikhomirov@192: private HgChangelog.ParentWalker parentHelper; tikhomirov@181: tikhomirov@181: public HgIncomingCommand(HgRepository hgRepo) { tikhomirov@192: localRepo = hgRepo; tikhomirov@192: } tikhomirov@192: tikhomirov@192: public HgIncomingCommand against(HgRemoteRepository hgRemote) { tikhomirov@192: remoteRepo = hgRemote; tikhomirov@192: comparator = null; tikhomirov@192: missingBranches = null; tikhomirov@192: return this; tikhomirov@181: } tikhomirov@181: tikhomirov@181: /** tikhomirov@192: * PLACEHOLDER, NOT IMPLEMENTED YET. tikhomirov@192: * tikhomirov@181: * Select specific branch to pull tikhomirov@181: * @return this for convenience tikhomirov@181: */ tikhomirov@181: public HgIncomingCommand branch(String branch) { tikhomirov@181: throw HgRepository.notImplemented(); tikhomirov@181: } tikhomirov@181: tikhomirov@181: /** tikhomirov@192: * PLACEHOLDER, NOT IMPLEMENTED YET. tikhomirov@192: * tikhomirov@181: * Whether to include sub-repositories when collecting changes, default is true XXX or false? tikhomirov@181: * @return this for convenience tikhomirov@181: */ tikhomirov@181: public HgIncomingCommand subrepo(boolean include) { tikhomirov@181: includeSubrepo = include; tikhomirov@181: throw HgRepository.notImplemented(); tikhomirov@181: } tikhomirov@181: tikhomirov@181: /** tikhomirov@181: * Lightweight check for incoming changes, gives only list of revisions to pull. tikhomirov@181: * tikhomirov@181: * @param context anything hg4j can use to get progress and/or cancel support tikhomirov@181: * @return list of nodes present at remote and missing locally tikhomirov@181: * @throws HgException tikhomirov@181: * @throws CancelledException tikhomirov@181: */ tikhomirov@181: public List executeLite(Object context) throws HgException, CancelledException { tikhomirov@192: LinkedHashSet result = new LinkedHashSet(); tikhomirov@192: RepositoryComparator repoCompare = getComparator(context); tikhomirov@192: for (BranchChain bc : getMissingBranches(context)) { tikhomirov@192: List missing = repoCompare.visitBranches(bc); tikhomirov@192: assert bc.branchRoot.equals(missing.get(0)); tikhomirov@192: missing.remove(0); tikhomirov@192: result.addAll(missing); tikhomirov@192: } tikhomirov@192: ArrayList rv = new ArrayList(result); tikhomirov@192: return rv; tikhomirov@181: } tikhomirov@181: tikhomirov@181: /** tikhomirov@181: * Full information about incoming changes tikhomirov@181: * tikhomirov@181: * @throws HgException tikhomirov@181: * @throws CancelledException tikhomirov@181: */ tikhomirov@192: public void executeFull(final HgLogCommand.Handler handler) throws HgException, CancelledException { tikhomirov@192: if (handler == null) { tikhomirov@192: throw new IllegalArgumentException("Delegate can't be null"); tikhomirov@192: } tikhomirov@192: final List common = getCommon(handler); tikhomirov@192: HgBundle changegroup = remoteRepo.getChanges(new LinkedList(common)); tikhomirov@192: try { tikhomirov@192: changegroup.changes(localRepo, new HgChangelog.Inspector() { tikhomirov@192: private int localIndex; tikhomirov@192: private final HgChangelog.ParentWalker parentHelper; tikhomirov@192: private final ChangesetTransformer transformer; tikhomirov@192: private final HgChangelog changelog; tikhomirov@192: tikhomirov@192: { tikhomirov@192: transformer = new ChangesetTransformer(localRepo, handler); tikhomirov@192: parentHelper = getParentHelper(); tikhomirov@192: changelog = localRepo.getChangelog(); tikhomirov@192: } tikhomirov@192: tikhomirov@192: public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { tikhomirov@192: if (parentHelper.knownNode(nodeid)) { tikhomirov@192: if (!common.contains(nodeid)) { tikhomirov@192: throw new HgBadStateException("Bundle shall not report known nodes other than roots we've supplied"); tikhomirov@192: } tikhomirov@192: localIndex = changelog.getLocalRevision(nodeid); tikhomirov@192: return; tikhomirov@192: } tikhomirov@192: transformer.next(++localIndex, nodeid, cset); tikhomirov@192: } tikhomirov@192: }); tikhomirov@192: } catch (IOException ex) { tikhomirov@192: throw new HgException(ex); tikhomirov@192: } tikhomirov@192: } tikhomirov@192: tikhomirov@192: private RepositoryComparator getComparator(Object context) throws HgException, CancelledException { tikhomirov@192: if (remoteRepo == null) { tikhomirov@192: throw new HgBadArgumentException("Shall specify remote repository to compare against", null); tikhomirov@192: } tikhomirov@192: if (comparator == null) { tikhomirov@192: comparator = new RepositoryComparator(getParentHelper(), remoteRepo); tikhomirov@192: comparator.compare(context); tikhomirov@192: } tikhomirov@192: return comparator; tikhomirov@192: } tikhomirov@192: tikhomirov@192: private HgChangelog.ParentWalker getParentHelper() { tikhomirov@192: if (parentHelper == null) { tikhomirov@192: parentHelper = localRepo.getChangelog().new ParentWalker(); tikhomirov@192: parentHelper.init(); tikhomirov@192: } tikhomirov@192: return parentHelper; tikhomirov@192: } tikhomirov@192: tikhomirov@192: private List getMissingBranches(Object context) throws HgException, CancelledException { tikhomirov@192: if (missingBranches == null) { tikhomirov@192: missingBranches = getComparator(context).calculateMissingBranches(); tikhomirov@192: } tikhomirov@192: return missingBranches; tikhomirov@192: } tikhomirov@192: tikhomirov@192: private List getCommon(Object context) throws HgException, CancelledException { tikhomirov@192: final LinkedHashSet common = new LinkedHashSet(); tikhomirov@192: // XXX common can be obtained from repoCompare, but at the moment it would almost duplicate work of calculateMissingBranches tikhomirov@192: // once I refactor latter, common shall be taken from repoCompare. tikhomirov@192: for (BranchChain bc : getMissingBranches(context)) { tikhomirov@192: common.add(bc.branchRoot); tikhomirov@192: } tikhomirov@192: return new LinkedList(common); tikhomirov@181: } tikhomirov@181: }