tikhomirov@645: /* tikhomirov@645: * Copyright (c) 2013 TMate Software Ltd tikhomirov@645: * tikhomirov@645: * This program is free software; you can redistribute it and/or modify tikhomirov@645: * it under the terms of the GNU General Public License as published by tikhomirov@645: * the Free Software Foundation; version 2 of the License. tikhomirov@645: * tikhomirov@645: * This program is distributed in the hope that it will be useful, tikhomirov@645: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@645: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@645: * GNU General Public License for more details. tikhomirov@645: * tikhomirov@645: * For information on how to redistribute this software under tikhomirov@645: * the terms of a license other than GNU General Public License tikhomirov@645: * contact TMate Software at support@hg4j.com tikhomirov@645: */ tikhomirov@645: package org.tmatesoft.hg.core; tikhomirov@645: tikhomirov@645: import java.io.File; tikhomirov@645: import java.io.IOException; tikhomirov@645: import java.net.URL; tikhomirov@645: import java.util.List; tikhomirov@645: tikhomirov@645: import org.tmatesoft.hg.internal.BundleGenerator; tikhomirov@645: import org.tmatesoft.hg.internal.RepositoryComparator; tikhomirov@646: import org.tmatesoft.hg.repo.HgBookmarks; tikhomirov@645: import org.tmatesoft.hg.repo.HgBundle; tikhomirov@645: import org.tmatesoft.hg.repo.HgChangelog; tikhomirov@645: import org.tmatesoft.hg.repo.HgInternals; tikhomirov@645: import org.tmatesoft.hg.repo.HgInvalidStateException; tikhomirov@645: import org.tmatesoft.hg.repo.HgLookup; tikhomirov@645: import org.tmatesoft.hg.repo.HgParentChildMap; tikhomirov@645: import org.tmatesoft.hg.repo.HgRemoteRepository; tikhomirov@645: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@645: import org.tmatesoft.hg.repo.HgRuntimeException; tikhomirov@645: import org.tmatesoft.hg.util.CancelledException; tikhomirov@646: import org.tmatesoft.hg.util.Pair; tikhomirov@645: import org.tmatesoft.hg.util.ProgressSupport; tikhomirov@645: tikhomirov@645: /** tikhomirov@645: * tikhomirov@645: * @author Artem Tikhomirov tikhomirov@645: * @author TMate Software Ltd. tikhomirov@645: */ tikhomirov@645: public class HgPushCommand extends HgAbstractCommand { tikhomirov@645: tikhomirov@645: private final HgRepository repo; tikhomirov@645: private HgRemoteRepository remoteRepo; tikhomirov@645: tikhomirov@645: public HgPushCommand(HgRepository hgRepo) { tikhomirov@645: repo = hgRepo; tikhomirov@645: } tikhomirov@645: tikhomirov@645: public HgPushCommand destination(HgRemoteRepository hgRemote) { tikhomirov@645: remoteRepo = hgRemote; tikhomirov@645: return this; tikhomirov@645: } tikhomirov@645: tikhomirov@645: public void execute() throws HgRemoteConnectionException, HgIOException, CancelledException, HgLibraryFailureException { tikhomirov@645: final ProgressSupport progress = getProgressSupport(null); tikhomirov@645: try { tikhomirov@645: progress.start(100); tikhomirov@645: // tikhomirov@645: // find out missing tikhomirov@645: // TODO refactor same code in HgOutgoingCommand #getComparator and #getParentHelper tikhomirov@645: final HgParentChildMap parentHelper = new HgParentChildMap(repo.getChangelog()); tikhomirov@645: parentHelper.init(); tikhomirov@645: final RepositoryComparator comparator = new RepositoryComparator(parentHelper, remoteRepo); tikhomirov@645: comparator.compare(new ProgressSupport.Sub(progress, 50), getCancelSupport(null, true)); tikhomirov@645: List l = comparator.getLocalOnlyRevisions(); tikhomirov@645: // tikhomirov@645: // prepare bundle tikhomirov@645: BundleGenerator bg = new BundleGenerator(HgInternals.getImplementationRepo(repo)); tikhomirov@645: File bundleFile = bg.create(l); tikhomirov@645: progress.worked(20); tikhomirov@645: HgBundle b = new HgLookup(repo.getSessionContext()).loadBundle(bundleFile); tikhomirov@645: // tikhomirov@645: // send changes tikhomirov@645: remoteRepo.unbundle(b, comparator.getRemoteHeads()); tikhomirov@645: progress.worked(20); tikhomirov@645: // tikhomirov@645: // FIXME update phase information tikhomirov@645: // remote.listkeys("phases"); tikhomirov@645: progress.worked(5); tikhomirov@645: // tikhomirov@646: // update bookmark information tikhomirov@646: HgBookmarks localBookmarks = repo.getBookmarks(); tikhomirov@646: if (!localBookmarks.getAllBookmarks().isEmpty()) { tikhomirov@646: for (Pair bm : remoteRepo.bookmarks()) { tikhomirov@646: Nodeid localRevision = localBookmarks.getRevision(bm.first()); tikhomirov@646: if (localRevision == null || !parentHelper.knownNode(bm.second())) { tikhomirov@646: continue; tikhomirov@646: } tikhomirov@646: // we know both localRevision and revision of remote bookmark, tikhomirov@646: // need to make sure we don't push older revision than it's at the server tikhomirov@646: if (parentHelper.isChild(bm.second(), localRevision)) { tikhomirov@646: remoteRepo.updateBookmark(bm.first(), bm.second(), localRevision); tikhomirov@646: } tikhomirov@646: } tikhomirov@646: } tikhomirov@645: // remote.listkeys("bookmarks"); tikhomirov@646: // XXX WTF is obsolete in namespaces key?? tikhomirov@645: progress.worked(5); tikhomirov@645: } catch (IOException ex) { tikhomirov@645: throw new HgIOException(ex.getMessage(), null); // XXX not a nice idea to throw IOException from BundleGenerator#create tikhomirov@645: } catch (HgRepositoryNotFoundException ex) { tikhomirov@645: final HgInvalidStateException e = new HgInvalidStateException("Failed to load a just-created bundle"); tikhomirov@645: e.initCause(ex); tikhomirov@645: throw new HgLibraryFailureException(e); tikhomirov@645: } catch (HgRuntimeException ex) { tikhomirov@645: throw new HgLibraryFailureException(ex); tikhomirov@645: } finally { tikhomirov@645: progress.done(); tikhomirov@645: } tikhomirov@645: } tikhomirov@645: tikhomirov@645: /* tikhomirov@645: * To test, start a server: tikhomirov@645: * $ hg --config web.allow_push=* --config web.push_ssl=False --config server.validate=True --debug serve tikhomirov@645: */ tikhomirov@645: public static void main(String[] args) throws Exception { tikhomirov@645: final HgLookup hgLookup = new HgLookup(); tikhomirov@645: HgRepository r = hgLookup.detect("/home/artem/hg/junit-test-repos/log-1/"); tikhomirov@645: HgRemoteRepository rr = hgLookup.detect(new URL("http://localhost:8000/")); tikhomirov@645: new HgPushCommand(r).destination(rr).execute(); tikhomirov@645: } tikhomirov@645: }