##// END OF EJS Templates
push: move `remote` argument in the push object...
Pierre-Yves David -
r20348:d64c904d default
parent child Browse files
Show More
@@ -1,249 +1,253 b''
1 1 # exchange.py - utily to exchange data between repo.
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 from node import hex
10 10 import errno
11 11 import util, scmutil, changegroup
12 12 import discovery, phases, obsolete, bookmarks
13 13
14 14
15 15 class pushoperation(object):
16 16 """A object that represent a single push operation
17 17
18 18 It purpose is to carry push related state and very common operation.
19 19
20 20 A new should be created at the begining of each push and discarded
21 21 afterward.
22 22 """
23 23
24 def __init__(self, repo):
24 def __init__(self, repo, remote):
25 25 # repo we push from
26 26 self.repo = repo
27 27 self.ui = repo.ui
28 # repo we push to
29 self.remote = remote
28 30
29 31 def push(repo, remote, force=False, revs=None, newbranch=False):
30 32 '''Push outgoing changesets (limited by revs) from a local
31 33 repository to remote. Return an integer:
32 34 - None means nothing to push
33 35 - 0 means HTTP error
34 36 - 1 means we pushed and remote head count is unchanged *or*
35 37 we have outgoing changesets but refused to push
36 38 - other values as described by addchangegroup()
37 39 '''
38 pushop = pushoperation(repo)
39 if remote.local():
40 missing = set(pushop.repo.requirements) - remote.local().supported
40 pushop = pushoperation(repo, remote)
41 if pushop.remote.local():
42 missing = (set(pushop.repo.requirements)
43 - pushop.remote.local().supported)
41 44 if missing:
42 45 msg = _("required features are not"
43 46 " supported in the destination:"
44 47 " %s") % (', '.join(sorted(missing)))
45 48 raise util.Abort(msg)
46 49
47 50 # there are two ways to push to remote repo:
48 51 #
49 52 # addchangegroup assumes local user can lock remote
50 53 # repo (local filesystem, old ssh servers).
51 54 #
52 55 # unbundle assumes local user cannot lock remote repo (new ssh
53 56 # servers, http servers).
54 57
55 if not remote.canpush():
58 if not pushop.remote.canpush():
56 59 raise util.Abort(_("destination does not support push"))
57 60 unfi = pushop.repo.unfiltered()
58 61 def localphasemove(nodes, phase=phases.public):
59 62 """move <nodes> to <phase> in the local source repo"""
60 63 if locallock is not None:
61 64 phases.advanceboundary(pushop.repo, phase, nodes)
62 65 else:
63 66 # repo is not locked, do not change any phases!
64 67 # Informs the user that phases should have been moved when
65 68 # applicable.
66 69 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
67 70 phasestr = phases.phasenames[phase]
68 71 if actualmoves:
69 72 pushop.ui.status(_('cannot lock source repo, skipping '
70 73 'local %s phase update\n') % phasestr)
71 74 # get local lock as we might write phase data
72 75 locallock = None
73 76 try:
74 77 locallock = pushop.repo.lock()
75 78 except IOError, err:
76 79 if err.errno != errno.EACCES:
77 80 raise
78 81 # source repo cannot be locked.
79 82 # We do not abort the push, but just disable the local phase
80 83 # synchronisation.
81 84 msg = 'cannot lock source repository: %s\n' % err
82 85 pushop.ui.debug(msg)
83 86 try:
84 87 pushop.repo.checkpush(force, revs)
85 88 lock = None
86 unbundle = remote.capable('unbundle')
89 unbundle = pushop.remote.capable('unbundle')
87 90 if not unbundle:
88 lock = remote.lock()
91 lock = pushop.remote.lock()
89 92 try:
90 93 # discovery
91 94 fci = discovery.findcommonincoming
92 commoninc = fci(unfi, remote, force=force)
95 commoninc = fci(unfi, pushop.remote, force=force)
93 96 common, inc, remoteheads = commoninc
94 97 fco = discovery.findcommonoutgoing
95 outgoing = fco(unfi, remote, onlyheads=revs,
98 outgoing = fco(unfi, pushop.remote, onlyheads=revs,
96 99 commoninc=commoninc, force=force)
97 100
98 101
99 102 if not outgoing.missing:
100 103 # nothing to push
101 104 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
102 105 ret = None
103 106 else:
104 107 # something to push
105 108 if not force:
106 109 # if repo.obsstore == False --> no obsolete
107 110 # then, save the iteration
108 111 if unfi.obsstore:
109 112 # this message are here for 80 char limit reason
110 113 mso = _("push includes obsolete changeset: %s!")
111 114 mst = "push includes %s changeset: %s!"
112 115 # plain versions for i18n tool to detect them
113 116 _("push includes unstable changeset: %s!")
114 117 _("push includes bumped changeset: %s!")
115 118 _("push includes divergent changeset: %s!")
116 119 # If we are to push if there is at least one
117 120 # obsolete or unstable changeset in missing, at
118 121 # least one of the missinghead will be obsolete or
119 122 # unstable. So checking heads only is ok
120 123 for node in outgoing.missingheads:
121 124 ctx = unfi[node]
122 125 if ctx.obsolete():
123 126 raise util.Abort(mso % ctx)
124 127 elif ctx.troubled():
125 128 raise util.Abort(_(mst)
126 129 % (ctx.troubles()[0],
127 130 ctx))
128 131 newbm = pushop.ui.configlist('bookmarks', 'pushing')
129 discovery.checkheads(unfi, remote, outgoing,
132 discovery.checkheads(unfi, pushop.remote, outgoing,
130 133 remoteheads, newbranch,
131 134 bool(inc), newbm)
132 135
133 136 # TODO: get bundlecaps from remote
134 137 bundlecaps = None
135 138 # create a changegroup from local
136 139 if revs is None and not (outgoing.excluded
137 140 or pushop.repo.changelog.filteredrevs):
138 141 # push everything,
139 142 # use the fast path, no race possible on push
140 143 bundler = changegroup.bundle10(pushop.repo, bundlecaps)
141 144 cg = pushop.repo._changegroupsubset(outgoing,
142 145 bundler,
143 146 'push',
144 147 fastpath=True)
145 148 else:
146 149 cg = pushop.repo.getlocalbundle('push', outgoing,
147 150 bundlecaps)
148 151
149 152 # apply changegroup to remote
150 153 if unbundle:
151 154 # local repo finds heads on server, finds out what
152 155 # revs it must push. once revs transferred, if server
153 156 # finds it has different heads (someone else won
154 157 # commit/push race), server aborts.
155 158 if force:
156 159 remoteheads = ['force']
157 160 # ssh: return remote's addchangegroup()
158 161 # http: return remote's addchangegroup() or 0 for error
159 ret = remote.unbundle(cg, remoteheads, 'push')
162 ret = pushop.remote.unbundle(cg, remoteheads, 'push')
160 163 else:
161 164 # we return an integer indicating remote head count
162 165 # change
163 ret = remote.addchangegroup(cg, 'push', pushop.repo.url())
166 ret = pushop.remote.addchangegroup(cg, 'push',
167 pushop.repo.url())
164 168
165 169 if ret:
166 170 # push succeed, synchronize target of the push
167 171 cheads = outgoing.missingheads
168 172 elif revs is None:
169 173 # All out push fails. synchronize all common
170 174 cheads = outgoing.commonheads
171 175 else:
172 176 # I want cheads = heads(::missingheads and ::commonheads)
173 177 # (missingheads is revs with secret changeset filtered out)
174 178 #
175 179 # This can be expressed as:
176 180 # cheads = ( (missingheads and ::commonheads)
177 181 # + (commonheads and ::missingheads))"
178 182 # )
179 183 #
180 184 # while trying to push we already computed the following:
181 185 # common = (::commonheads)
182 186 # missing = ((commonheads::missingheads) - commonheads)
183 187 #
184 188 # We can pick:
185 189 # * missingheads part of common (::commonheads)
186 190 common = set(outgoing.common)
187 191 nm = pushop.repo.changelog.nodemap
188 192 cheads = [node for node in revs if nm[node] in common]
189 193 # and
190 194 # * commonheads parents on missing
191 195 revset = unfi.set('%ln and parents(roots(%ln))',
192 196 outgoing.commonheads,
193 197 outgoing.missing)
194 198 cheads.extend(c.node() for c in revset)
195 199 # even when we don't push, exchanging phase data is useful
196 remotephases = remote.listkeys('phases')
200 remotephases = pushop.remote.listkeys('phases')
197 201 if (pushop.ui.configbool('ui', '_usedassubrepo', False)
198 202 and remotephases # server supports phases
199 203 and ret is None # nothing was pushed
200 204 and remotephases.get('publishing', False)):
201 205 # When:
202 206 # - this is a subrepo push
203 207 # - and remote support phase
204 208 # - and no changeset was pushed
205 209 # - and remote is publishing
206 210 # We may be in issue 3871 case!
207 211 # We drop the possible phase synchronisation done by
208 212 # courtesy to publish changesets possibly locally draft
209 213 # on the remote.
210 214 remotephases = {'publishing': 'True'}
211 215 if not remotephases: # old server or public only repo
212 216 localphasemove(cheads)
213 217 # don't push any phase data as there is nothing to push
214 218 else:
215 219 ana = phases.analyzeremotephases(pushop.repo, cheads,
216 220 remotephases)
217 221 pheads, droots = ana
218 222 ### Apply remote phase on local
219 223 if remotephases.get('publishing', False):
220 224 localphasemove(cheads)
221 225 else: # publish = False
222 226 localphasemove(pheads)
223 227 localphasemove(cheads, phases.draft)
224 228 ### Apply local phase on remote
225 229
226 230 # Get the list of all revs draft on remote by public here.
227 231 # XXX Beware that revset break if droots is not strictly
228 232 # XXX root we may want to ensure it is but it is costly
229 233 outdated = unfi.set('heads((%ln::%ln) and public())',
230 234 droots, cheads)
231 235 for newremotehead in outdated:
232 r = remote.pushkey('phases',
233 newremotehead.hex(),
234 str(phases.draft),
235 str(phases.public))
236 r = pushop.remote.pushkey('phases',
237 newremotehead.hex(),
238 str(phases.draft),
239 str(phases.public))
236 240 if not r:
237 241 pushop.ui.warn(_('updating %s to public failed!\n')
238 242 % newremotehead)
239 243 pushop.ui.debug('try to push obsolete markers to remote\n')
240 obsolete.syncpush(pushop.repo, remote)
244 obsolete.syncpush(pushop.repo, pushop.remote)
241 245 finally:
242 246 if lock is not None:
243 247 lock.release()
244 248 finally:
245 249 if locallock is not None:
246 250 locallock.release()
247 251
248 bookmarks.updateremote(pushop.ui, unfi, remote, revs)
252 bookmarks.updateremote(pushop.ui, unfi, pushop.remote, revs)
249 253 return ret
General Comments 0
You need to be logged in to leave comments. Login now