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 }