tikhomirov@660: /* tikhomirov@660: * Copyright (c) 2013 TMate Software Ltd tikhomirov@660: * tikhomirov@660: * This program is free software; you can redistribute it and/or modify tikhomirov@660: * it under the terms of the GNU General Public License as published by tikhomirov@660: * the Free Software Foundation; version 2 of the License. tikhomirov@660: * tikhomirov@660: * This program is distributed in the hope that it will be useful, tikhomirov@660: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@660: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@660: * GNU General Public License for more details. tikhomirov@660: * tikhomirov@660: * For information on how to redistribute this software under tikhomirov@660: * the terms of a license other than GNU General Public License tikhomirov@660: * contact TMate Software at support@hg4j.com tikhomirov@660: */ tikhomirov@660: package org.tmatesoft.hg.core; tikhomirov@660: tikhomirov@663: import java.util.Collection; tikhomirov@663: import java.util.Collections; tikhomirov@660: import java.util.List; tikhomirov@660: tikhomirov@660: import org.tmatesoft.hg.internal.AddRevInspector; tikhomirov@660: import org.tmatesoft.hg.internal.COWTransaction; tikhomirov@660: import org.tmatesoft.hg.internal.Internals; tikhomirov@660: import org.tmatesoft.hg.internal.PhasesHelper; tikhomirov@660: import org.tmatesoft.hg.internal.RepositoryComparator; tikhomirov@660: import org.tmatesoft.hg.internal.RevisionSet; tikhomirov@660: import org.tmatesoft.hg.internal.Transaction; tikhomirov@660: import org.tmatesoft.hg.repo.HgBundle; tikhomirov@660: import org.tmatesoft.hg.repo.HgChangelog; tikhomirov@660: import org.tmatesoft.hg.repo.HgInternals; tikhomirov@660: import org.tmatesoft.hg.repo.HgParentChildMap; tikhomirov@660: import org.tmatesoft.hg.repo.HgRemoteRepository; tikhomirov@660: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@660: import org.tmatesoft.hg.repo.HgRuntimeException; tikhomirov@660: import org.tmatesoft.hg.util.CancelledException; tikhomirov@660: import org.tmatesoft.hg.util.ProgressSupport; tikhomirov@660: tikhomirov@660: /** tikhomirov@664: * 'hg pull ' counterpart, get remote changes to local repository tikhomirov@660: * tikhomirov@664: * @since 1.2 tikhomirov@660: * @author Artem Tikhomirov tikhomirov@660: * @author TMate Software Ltd. tikhomirov@660: */ tikhomirov@660: public class HgPullCommand extends HgAbstractCommand { tikhomirov@660: tikhomirov@660: private final HgRepository repo; tikhomirov@660: private HgRemoteRepository remote; tikhomirov@663: private RevisionSet added; tikhomirov@660: tikhomirov@660: public HgPullCommand(HgRepository hgRepo) { tikhomirov@660: repo = hgRepo; tikhomirov@660: } tikhomirov@660: tikhomirov@660: public HgPullCommand source(HgRemoteRepository hgRemote) { tikhomirov@660: remote = hgRemote; tikhomirov@660: return this; tikhomirov@660: } tikhomirov@660: tikhomirov@660: public void execute() throws HgRemoteConnectionException, HgIOException, HgLibraryFailureException, CancelledException { tikhomirov@660: final ProgressSupport progress = getProgressSupport(null); tikhomirov@660: try { tikhomirov@660: progress.start(100); tikhomirov@660: // TODO refactor same code in HgIncomingCommand #getComparator and #getParentHelper tikhomirov@660: final HgChangelog clog = repo.getChangelog(); tikhomirov@660: final HgParentChildMap parentHelper = new HgParentChildMap(clog); tikhomirov@660: parentHelper.init(); tikhomirov@660: final RepositoryComparator comparator = new RepositoryComparator(parentHelper, remote); tikhomirov@660: // get incoming revisions tikhomirov@660: comparator.compare(new ProgressSupport.Sub(progress, 50), getCancelSupport(null, true)); tikhomirov@660: final List common = comparator.getCommon(); tikhomirov@660: // get bundle with changes from remote tikhomirov@660: HgBundle incoming = remote.getChanges(common); tikhomirov@660: // tikhomirov@660: // add revisions to changelog, manifest, files tikhomirov@660: final Internals implRepo = HgInternals.getImplementationRepo(repo); tikhomirov@660: final AddRevInspector insp; tikhomirov@660: Transaction.Factory trFactory = new COWTransaction.Factory(); tikhomirov@660: Transaction tr = trFactory.create(repo); tikhomirov@660: try { tikhomirov@660: incoming.inspectAll(insp = new AddRevInspector(implRepo, tr)); tikhomirov@663: insp.done(); tikhomirov@660: tr.commit(); tikhomirov@660: } catch (HgRuntimeException ex) { tikhomirov@660: tr.rollback(); tikhomirov@660: throw ex; tikhomirov@664: } catch (HgIOException ex) { tikhomirov@663: tr.rollback(); tikhomirov@664: throw ex; tikhomirov@660: } catch (RuntimeException ex) { tikhomirov@660: tr.rollback(); tikhomirov@660: throw ex; tikhomirov@660: } tikhomirov@660: progress.worked(45); tikhomirov@663: added = insp.addedChangesets(); tikhomirov@660: tikhomirov@663: if (!added.isEmpty()) { tikhomirov@663: // FIXME refresh parentHelper with newly added revisions in effective way tikhomirov@663: parentHelper.init(); tikhomirov@663: } tikhomirov@660: // get remote phases, update local phases to match that of remote tikhomirov@663: // do not update any remote phase (it's pull, after all) tikhomirov@660: final PhasesHelper phaseHelper = new PhasesHelper(implRepo, parentHelper); tikhomirov@660: if (phaseHelper.isCapableOfPhases()) { tikhomirov@660: RevisionSet rsCommon = new RevisionSet(common); tikhomirov@660: HgRemoteRepository.Phases remotePhases = remote.getPhases(); tikhomirov@663: phaseHelper.synchronizeWithRemote(remotePhases, rsCommon.union(added)); tikhomirov@660: } tikhomirov@660: progress.worked(5); tikhomirov@668: incoming.unlink(); // keep the file only in case of failure tikhomirov@660: } catch (HgRuntimeException ex) { tikhomirov@660: throw new HgLibraryFailureException(ex); tikhomirov@660: } finally { tikhomirov@660: progress.done(); tikhomirov@660: } tikhomirov@660: } tikhomirov@663: tikhomirov@663: public Collection getPulledRevisions() { tikhomirov@663: return added == null ? Collections.emptyList() : added.asList(); tikhomirov@663: } tikhomirov@660: }