Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgPushCommand.java @ 649:e79cf9a8130b
Push: phase4 - update local and remote phase information
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Wed, 26 Jun 2013 20:52:38 +0200 |
| parents | 3b7d51ed4c65 |
| children | 3b275cc2d2aa |
comparison
equal
deleted
inserted
replaced
| 648:690e71d29bf6 | 649:e79cf9a8130b |
|---|---|
| 17 package org.tmatesoft.hg.core; | 17 package org.tmatesoft.hg.core; |
| 18 | 18 |
| 19 import java.io.File; | 19 import java.io.File; |
| 20 import java.io.IOException; | 20 import java.io.IOException; |
| 21 import java.net.URL; | 21 import java.net.URL; |
| 22 import java.util.ArrayList; | |
| 22 import java.util.List; | 23 import java.util.List; |
| 23 | 24 |
| 24 import org.tmatesoft.hg.internal.BundleGenerator; | 25 import org.tmatesoft.hg.internal.BundleGenerator; |
| 26 import org.tmatesoft.hg.internal.Internals; | |
| 27 import org.tmatesoft.hg.internal.PhasesHelper; | |
| 25 import org.tmatesoft.hg.internal.RepositoryComparator; | 28 import org.tmatesoft.hg.internal.RepositoryComparator; |
| 29 import org.tmatesoft.hg.internal.RevisionSet; | |
| 26 import org.tmatesoft.hg.repo.HgBookmarks; | 30 import org.tmatesoft.hg.repo.HgBookmarks; |
| 27 import org.tmatesoft.hg.repo.HgBundle; | 31 import org.tmatesoft.hg.repo.HgBundle; |
| 28 import org.tmatesoft.hg.repo.HgChangelog; | 32 import org.tmatesoft.hg.repo.HgChangelog; |
| 29 import org.tmatesoft.hg.repo.HgInternals; | 33 import org.tmatesoft.hg.repo.HgInternals; |
| 30 import org.tmatesoft.hg.repo.HgInvalidStateException; | 34 import org.tmatesoft.hg.repo.HgInvalidStateException; |
| 31 import org.tmatesoft.hg.repo.HgLookup; | 35 import org.tmatesoft.hg.repo.HgLookup; |
| 32 import org.tmatesoft.hg.repo.HgParentChildMap; | 36 import org.tmatesoft.hg.repo.HgParentChildMap; |
| 37 import org.tmatesoft.hg.repo.HgPhase; | |
| 33 import org.tmatesoft.hg.repo.HgRemoteRepository; | 38 import org.tmatesoft.hg.repo.HgRemoteRepository; |
| 34 import org.tmatesoft.hg.repo.HgRepository; | 39 import org.tmatesoft.hg.repo.HgRepository; |
| 35 import org.tmatesoft.hg.repo.HgRuntimeException; | 40 import org.tmatesoft.hg.repo.HgRuntimeException; |
| 36 import org.tmatesoft.hg.util.CancelledException; | 41 import org.tmatesoft.hg.util.CancelledException; |
| 37 import org.tmatesoft.hg.util.Pair; | 42 import org.tmatesoft.hg.util.Pair; |
| 38 import org.tmatesoft.hg.util.ProgressSupport; | 43 import org.tmatesoft.hg.util.ProgressSupport; |
| 44 import org.tmatesoft.hg.util.LogFacility.Severity; | |
| 39 | 45 |
| 40 /** | 46 /** |
| 41 * | 47 * |
| 42 * @author Artem Tikhomirov | 48 * @author Artem Tikhomirov |
| 43 * @author TMate Software Ltd. | 49 * @author TMate Software Ltd. |
| 61 try { | 67 try { |
| 62 progress.start(100); | 68 progress.start(100); |
| 63 // | 69 // |
| 64 // find out missing | 70 // find out missing |
| 65 // TODO refactor same code in HgOutgoingCommand #getComparator and #getParentHelper | 71 // TODO refactor same code in HgOutgoingCommand #getComparator and #getParentHelper |
| 66 final HgParentChildMap<HgChangelog> parentHelper = new HgParentChildMap<HgChangelog>(repo.getChangelog()); | 72 final HgChangelog clog = repo.getChangelog(); |
| 73 final HgParentChildMap<HgChangelog> parentHelper = new HgParentChildMap<HgChangelog>(clog); | |
| 67 parentHelper.init(); | 74 parentHelper.init(); |
| 68 final RepositoryComparator comparator = new RepositoryComparator(parentHelper, remoteRepo); | 75 final RepositoryComparator comparator = new RepositoryComparator(parentHelper, remoteRepo); |
| 69 comparator.compare(new ProgressSupport.Sub(progress, 50), getCancelSupport(null, true)); | 76 comparator.compare(new ProgressSupport.Sub(progress, 50), getCancelSupport(null, true)); |
| 70 List<Nodeid> l = comparator.getLocalOnlyRevisions(); | 77 List<Nodeid> l = comparator.getLocalOnlyRevisions(); |
| 71 // | 78 // |
| 72 // prepare bundle | 79 // prepare bundle |
| 73 BundleGenerator bg = new BundleGenerator(HgInternals.getImplementationRepo(repo)); | 80 final Internals implRepo = HgInternals.getImplementationRepo(repo); |
| 81 BundleGenerator bg = new BundleGenerator(implRepo); | |
| 74 File bundleFile = bg.create(l); | 82 File bundleFile = bg.create(l); |
| 75 progress.worked(20); | 83 progress.worked(20); |
| 76 HgBundle b = new HgLookup(repo.getSessionContext()).loadBundle(bundleFile); | 84 HgBundle b = new HgLookup(repo.getSessionContext()).loadBundle(bundleFile); |
| 77 // | 85 // |
| 78 // send changes | 86 // send changes |
| 79 remoteRepo.unbundle(b, comparator.getRemoteHeads()); | 87 remoteRepo.unbundle(b, comparator.getRemoteHeads()); |
| 80 progress.worked(20); | 88 progress.worked(20); |
| 81 // | 89 // |
| 82 // FIXME update phase information | 90 // update phase information |
| 83 // remote.listkeys("phases"); | 91 PhasesHelper phaseHelper = new PhasesHelper(implRepo, parentHelper); |
| 92 if (phaseHelper.isCapableOfPhases()) { | |
| 93 RevisionSet outgoing = new RevisionSet(l); | |
| 94 RevisionSet presentSecret = phaseHelper.allSecret(); | |
| 95 RevisionSet presentDraft = phaseHelper.allDraft(); | |
| 96 RevisionSet secretLeft, draftLeft; | |
| 97 HgRemoteRepository.Phases remotePhases = remoteRepo.getPhases(); | |
| 98 if (remotePhases.isPublishingServer()) { | |
| 99 // although it's unlikely outgoing would affect secret changesets, | |
| 100 // it doesn't hurt to check secret roots along with draft ones | |
| 101 secretLeft = presentSecret.subtract(outgoing); | |
| 102 draftLeft = presentDraft.subtract(outgoing); | |
| 103 } else { | |
| 104 // shall merge local and remote phase states | |
| 105 ArrayList<Nodeid> knownRemoteDraftRoots = new ArrayList<Nodeid>(); | |
| 106 for (Nodeid rdr : remotePhases.draftRoots()) { | |
| 107 if (clog.isKnown(rdr)) { | |
| 108 knownRemoteDraftRoots.add(rdr); | |
| 109 } | |
| 110 } | |
| 111 // childrenOf(knownRemoteDraftRoots) is everything remote may treat as Draft | |
| 112 RevisionSet remoteDrafts = new RevisionSet(parentHelper.childrenOf(knownRemoteDraftRoots)); | |
| 113 List<Nodeid> localChildrenNotSent = parentHelper.childrenOf(outgoing.heads(parentHelper).asList()); | |
| 114 // remote shall know only what we've sent, subtract revisions we didn't actually sent | |
| 115 remoteDrafts = remoteDrafts.subtract(new RevisionSet(localChildrenNotSent)); | |
| 116 // if there's a remote draft root that points to revision we know is public | |
| 117 RevisionSet remoteDraftsLocallyPublic = remoteDrafts.subtract(presentSecret).subtract(presentDraft); | |
| 118 if (!remoteDraftsLocallyPublic.isEmpty()) { | |
| 119 // foreach remoteDraftsLocallyPublic.heads() do push Draft->Public | |
| 120 for (Nodeid n : remoteDraftsLocallyPublic.heads(parentHelper)) { | |
| 121 try { | |
| 122 remoteRepo.updatePhase(HgPhase.Draft, HgPhase.Public, n); | |
| 123 } catch (HgRemoteConnectionException ex) { | |
| 124 implRepo.getLog().dump(getClass(), Severity.Error, ex, String.format("Failed to update phase of %s", n.shortNotation())); | |
| 125 } | |
| 126 } | |
| 127 remoteDrafts = remoteDrafts.subtract(remoteDraftsLocallyPublic); | |
| 128 } | |
| 129 // revisions that cease to be secret (gonna become Public), e.g. someone else pushed them | |
| 130 RevisionSet secretGone = presentSecret.intersect(remoteDrafts); | |
| 131 // trace parents of these published secret revisions | |
| 132 RevisionSet secretMadePublic = presentSecret.parentsOf(secretGone, parentHelper); | |
| 133 secretLeft = presentSecret.subtract(secretGone).subtract(secretMadePublic); | |
| 134 // same for drafts | |
| 135 RevisionSet draftGone = presentDraft.intersect(remoteDrafts); | |
| 136 RevisionSet draftMadePublic = presentDraft.parentsOf(draftGone, parentHelper); | |
| 137 draftLeft = presentDraft.subtract(draftGone).subtract(draftMadePublic); | |
| 138 } | |
| 139 final RevisionSet newDraftRoots = draftLeft.roots(parentHelper); | |
| 140 final RevisionSet newSecretRoots = secretLeft.roots(parentHelper); | |
| 141 phaseHelper.updateRoots(newDraftRoots.asList(), newSecretRoots.asList()); | |
| 142 } | |
| 84 progress.worked(5); | 143 progress.worked(5); |
| 85 // | 144 // |
| 86 // update bookmark information | 145 // update bookmark information |
| 87 HgBookmarks localBookmarks = repo.getBookmarks(); | 146 HgBookmarks localBookmarks = repo.getBookmarks(); |
| 88 if (!localBookmarks.getAllBookmarks().isEmpty()) { | 147 if (!localBookmarks.getAllBookmarks().isEmpty()) { |
| 89 for (Pair<String,Nodeid> bm : remoteRepo.bookmarks()) { | 148 for (Pair<String,Nodeid> bm : remoteRepo.getBookmarks()) { |
| 90 Nodeid localRevision = localBookmarks.getRevision(bm.first()); | 149 Nodeid localRevision = localBookmarks.getRevision(bm.first()); |
| 91 if (localRevision == null || !parentHelper.knownNode(bm.second())) { | 150 if (localRevision == null || !parentHelper.knownNode(bm.second())) { |
| 92 continue; | 151 continue; |
| 93 } | 152 } |
| 94 // we know both localRevision and revision of remote bookmark, | 153 // we know both localRevision and revision of remote bookmark, |
| 96 if (parentHelper.isChild(bm.second(), localRevision)) { | 155 if (parentHelper.isChild(bm.second(), localRevision)) { |
| 97 remoteRepo.updateBookmark(bm.first(), bm.second(), localRevision); | 156 remoteRepo.updateBookmark(bm.first(), bm.second(), localRevision); |
| 98 } | 157 } |
| 99 } | 158 } |
| 100 } | 159 } |
| 101 // remote.listkeys("bookmarks"); | |
| 102 // XXX WTF is obsolete in namespaces key?? | 160 // XXX WTF is obsolete in namespaces key?? |
| 103 progress.worked(5); | 161 progress.worked(5); |
| 104 } catch (IOException ex) { | 162 } catch (IOException ex) { |
| 105 throw new HgIOException(ex.getMessage(), null); // XXX not a nice idea to throw IOException from BundleGenerator#create | 163 throw new HgIOException(ex.getMessage(), null); // XXX not a nice idea to throw IOException from BundleGenerator#create |
| 106 } catch (HgRepositoryNotFoundException ex) { | 164 } catch (HgRepositoryNotFoundException ex) { |
| 118 * To test, start a server: | 176 * To test, start a server: |
| 119 * $ hg --config web.allow_push=* --config web.push_ssl=False --config server.validate=True --debug serve | 177 * $ hg --config web.allow_push=* --config web.push_ssl=False --config server.validate=True --debug serve |
| 120 */ | 178 */ |
| 121 public static void main(String[] args) throws Exception { | 179 public static void main(String[] args) throws Exception { |
| 122 final HgLookup hgLookup = new HgLookup(); | 180 final HgLookup hgLookup = new HgLookup(); |
| 123 HgRepository r = hgLookup.detect("/home/artem/hg/junit-test-repos/log-1/"); | 181 HgRepository r = hgLookup.detect("/home/artem/hg/test-phases/"); |
| 124 HgRemoteRepository rr = hgLookup.detect(new URL("http://localhost:8000/")); | 182 HgRemoteRepository rr = hgLookup.detect(new URL("http://localhost:8000/")); |
| 125 new HgPushCommand(r).destination(rr).execute(); | 183 new HgPushCommand(r).destination(rr).execute(); |
| 126 } | 184 } |
| 127 } | 185 } |
