##// END OF EJS Templates
ssh: capture output with bundle2 again (issue4642)...
Pierre-Yves David -
r25192:36111f98 stable
parent child Browse files
Show More
@@ -1,1332 +1,1332 b''
1 # exchange.py - utility to exchange data between repos.
1 # exchange.py - utility to exchange data between repos.
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 from node import hex, nullid
9 from node import hex, nullid
10 import errno, urllib
10 import errno, urllib
11 import util, scmutil, changegroup, base85, error
11 import util, scmutil, changegroup, base85, error
12 import discovery, phases, obsolete, bookmarks as bookmod, bundle2, pushkey
12 import discovery, phases, obsolete, bookmarks as bookmod, bundle2, pushkey
13 import lock as lockmod
13 import lock as lockmod
14
14
15 def readbundle(ui, fh, fname, vfs=None):
15 def readbundle(ui, fh, fname, vfs=None):
16 header = changegroup.readexactly(fh, 4)
16 header = changegroup.readexactly(fh, 4)
17
17
18 alg = None
18 alg = None
19 if not fname:
19 if not fname:
20 fname = "stream"
20 fname = "stream"
21 if not header.startswith('HG') and header.startswith('\0'):
21 if not header.startswith('HG') and header.startswith('\0'):
22 fh = changegroup.headerlessfixup(fh, header)
22 fh = changegroup.headerlessfixup(fh, header)
23 header = "HG10"
23 header = "HG10"
24 alg = 'UN'
24 alg = 'UN'
25 elif vfs:
25 elif vfs:
26 fname = vfs.join(fname)
26 fname = vfs.join(fname)
27
27
28 magic, version = header[0:2], header[2:4]
28 magic, version = header[0:2], header[2:4]
29
29
30 if magic != 'HG':
30 if magic != 'HG':
31 raise util.Abort(_('%s: not a Mercurial bundle') % fname)
31 raise util.Abort(_('%s: not a Mercurial bundle') % fname)
32 if version == '10':
32 if version == '10':
33 if alg is None:
33 if alg is None:
34 alg = changegroup.readexactly(fh, 2)
34 alg = changegroup.readexactly(fh, 2)
35 return changegroup.cg1unpacker(fh, alg)
35 return changegroup.cg1unpacker(fh, alg)
36 elif version.startswith('2'):
36 elif version.startswith('2'):
37 return bundle2.getunbundler(ui, fh, header=magic + version)
37 return bundle2.getunbundler(ui, fh, header=magic + version)
38 else:
38 else:
39 raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
39 raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
40
40
41 def buildobsmarkerspart(bundler, markers):
41 def buildobsmarkerspart(bundler, markers):
42 """add an obsmarker part to the bundler with <markers>
42 """add an obsmarker part to the bundler with <markers>
43
43
44 No part is created if markers is empty.
44 No part is created if markers is empty.
45 Raises ValueError if the bundler doesn't support any known obsmarker format.
45 Raises ValueError if the bundler doesn't support any known obsmarker format.
46 """
46 """
47 if markers:
47 if markers:
48 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
48 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
49 version = obsolete.commonversion(remoteversions)
49 version = obsolete.commonversion(remoteversions)
50 if version is None:
50 if version is None:
51 raise ValueError('bundler do not support common obsmarker format')
51 raise ValueError('bundler do not support common obsmarker format')
52 stream = obsolete.encodemarkers(markers, True, version=version)
52 stream = obsolete.encodemarkers(markers, True, version=version)
53 return bundler.newpart('obsmarkers', data=stream)
53 return bundler.newpart('obsmarkers', data=stream)
54 return None
54 return None
55
55
56 def _canusebundle2(op):
56 def _canusebundle2(op):
57 """return true if a pull/push can use bundle2
57 """return true if a pull/push can use bundle2
58
58
59 Feel free to nuke this function when we drop the experimental option"""
59 Feel free to nuke this function when we drop the experimental option"""
60 return (op.repo.ui.configbool('experimental', 'bundle2-exp', False)
60 return (op.repo.ui.configbool('experimental', 'bundle2-exp', False)
61 and op.remote.capable('bundle2'))
61 and op.remote.capable('bundle2'))
62
62
63
63
64 class pushoperation(object):
64 class pushoperation(object):
65 """A object that represent a single push operation
65 """A object that represent a single push operation
66
66
67 It purpose is to carry push related state and very common operation.
67 It purpose is to carry push related state and very common operation.
68
68
69 A new should be created at the beginning of each push and discarded
69 A new should be created at the beginning of each push and discarded
70 afterward.
70 afterward.
71 """
71 """
72
72
73 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
73 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
74 bookmarks=()):
74 bookmarks=()):
75 # repo we push from
75 # repo we push from
76 self.repo = repo
76 self.repo = repo
77 self.ui = repo.ui
77 self.ui = repo.ui
78 # repo we push to
78 # repo we push to
79 self.remote = remote
79 self.remote = remote
80 # force option provided
80 # force option provided
81 self.force = force
81 self.force = force
82 # revs to be pushed (None is "all")
82 # revs to be pushed (None is "all")
83 self.revs = revs
83 self.revs = revs
84 # bookmark explicitly pushed
84 # bookmark explicitly pushed
85 self.bookmarks = bookmarks
85 self.bookmarks = bookmarks
86 # allow push of new branch
86 # allow push of new branch
87 self.newbranch = newbranch
87 self.newbranch = newbranch
88 # did a local lock get acquired?
88 # did a local lock get acquired?
89 self.locallocked = None
89 self.locallocked = None
90 # step already performed
90 # step already performed
91 # (used to check what steps have been already performed through bundle2)
91 # (used to check what steps have been already performed through bundle2)
92 self.stepsdone = set()
92 self.stepsdone = set()
93 # Integer version of the changegroup push result
93 # Integer version of the changegroup push result
94 # - None means nothing to push
94 # - None means nothing to push
95 # - 0 means HTTP error
95 # - 0 means HTTP error
96 # - 1 means we pushed and remote head count is unchanged *or*
96 # - 1 means we pushed and remote head count is unchanged *or*
97 # we have outgoing changesets but refused to push
97 # we have outgoing changesets but refused to push
98 # - other values as described by addchangegroup()
98 # - other values as described by addchangegroup()
99 self.cgresult = None
99 self.cgresult = None
100 # Boolean value for the bookmark push
100 # Boolean value for the bookmark push
101 self.bkresult = None
101 self.bkresult = None
102 # discover.outgoing object (contains common and outgoing data)
102 # discover.outgoing object (contains common and outgoing data)
103 self.outgoing = None
103 self.outgoing = None
104 # all remote heads before the push
104 # all remote heads before the push
105 self.remoteheads = None
105 self.remoteheads = None
106 # testable as a boolean indicating if any nodes are missing locally.
106 # testable as a boolean indicating if any nodes are missing locally.
107 self.incoming = None
107 self.incoming = None
108 # phases changes that must be pushed along side the changesets
108 # phases changes that must be pushed along side the changesets
109 self.outdatedphases = None
109 self.outdatedphases = None
110 # phases changes that must be pushed if changeset push fails
110 # phases changes that must be pushed if changeset push fails
111 self.fallbackoutdatedphases = None
111 self.fallbackoutdatedphases = None
112 # outgoing obsmarkers
112 # outgoing obsmarkers
113 self.outobsmarkers = set()
113 self.outobsmarkers = set()
114 # outgoing bookmarks
114 # outgoing bookmarks
115 self.outbookmarks = []
115 self.outbookmarks = []
116 # transaction manager
116 # transaction manager
117 self.trmanager = None
117 self.trmanager = None
118
118
119 @util.propertycache
119 @util.propertycache
120 def futureheads(self):
120 def futureheads(self):
121 """future remote heads if the changeset push succeeds"""
121 """future remote heads if the changeset push succeeds"""
122 return self.outgoing.missingheads
122 return self.outgoing.missingheads
123
123
124 @util.propertycache
124 @util.propertycache
125 def fallbackheads(self):
125 def fallbackheads(self):
126 """future remote heads if the changeset push fails"""
126 """future remote heads if the changeset push fails"""
127 if self.revs is None:
127 if self.revs is None:
128 # not target to push, all common are relevant
128 # not target to push, all common are relevant
129 return self.outgoing.commonheads
129 return self.outgoing.commonheads
130 unfi = self.repo.unfiltered()
130 unfi = self.repo.unfiltered()
131 # I want cheads = heads(::missingheads and ::commonheads)
131 # I want cheads = heads(::missingheads and ::commonheads)
132 # (missingheads is revs with secret changeset filtered out)
132 # (missingheads is revs with secret changeset filtered out)
133 #
133 #
134 # This can be expressed as:
134 # This can be expressed as:
135 # cheads = ( (missingheads and ::commonheads)
135 # cheads = ( (missingheads and ::commonheads)
136 # + (commonheads and ::missingheads))"
136 # + (commonheads and ::missingheads))"
137 # )
137 # )
138 #
138 #
139 # while trying to push we already computed the following:
139 # while trying to push we already computed the following:
140 # common = (::commonheads)
140 # common = (::commonheads)
141 # missing = ((commonheads::missingheads) - commonheads)
141 # missing = ((commonheads::missingheads) - commonheads)
142 #
142 #
143 # We can pick:
143 # We can pick:
144 # * missingheads part of common (::commonheads)
144 # * missingheads part of common (::commonheads)
145 common = set(self.outgoing.common)
145 common = set(self.outgoing.common)
146 nm = self.repo.changelog.nodemap
146 nm = self.repo.changelog.nodemap
147 cheads = [node for node in self.revs if nm[node] in common]
147 cheads = [node for node in self.revs if nm[node] in common]
148 # and
148 # and
149 # * commonheads parents on missing
149 # * commonheads parents on missing
150 revset = unfi.set('%ln and parents(roots(%ln))',
150 revset = unfi.set('%ln and parents(roots(%ln))',
151 self.outgoing.commonheads,
151 self.outgoing.commonheads,
152 self.outgoing.missing)
152 self.outgoing.missing)
153 cheads.extend(c.node() for c in revset)
153 cheads.extend(c.node() for c in revset)
154 return cheads
154 return cheads
155
155
156 @property
156 @property
157 def commonheads(self):
157 def commonheads(self):
158 """set of all common heads after changeset bundle push"""
158 """set of all common heads after changeset bundle push"""
159 if self.cgresult:
159 if self.cgresult:
160 return self.futureheads
160 return self.futureheads
161 else:
161 else:
162 return self.fallbackheads
162 return self.fallbackheads
163
163
164 # mapping of message used when pushing bookmark
164 # mapping of message used when pushing bookmark
165 bookmsgmap = {'update': (_("updating bookmark %s\n"),
165 bookmsgmap = {'update': (_("updating bookmark %s\n"),
166 _('updating bookmark %s failed!\n')),
166 _('updating bookmark %s failed!\n')),
167 'export': (_("exporting bookmark %s\n"),
167 'export': (_("exporting bookmark %s\n"),
168 _('exporting bookmark %s failed!\n')),
168 _('exporting bookmark %s failed!\n')),
169 'delete': (_("deleting remote bookmark %s\n"),
169 'delete': (_("deleting remote bookmark %s\n"),
170 _('deleting remote bookmark %s failed!\n')),
170 _('deleting remote bookmark %s failed!\n')),
171 }
171 }
172
172
173
173
174 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=()):
174 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=()):
175 '''Push outgoing changesets (limited by revs) from a local
175 '''Push outgoing changesets (limited by revs) from a local
176 repository to remote. Return an integer:
176 repository to remote. Return an integer:
177 - None means nothing to push
177 - None means nothing to push
178 - 0 means HTTP error
178 - 0 means HTTP error
179 - 1 means we pushed and remote head count is unchanged *or*
179 - 1 means we pushed and remote head count is unchanged *or*
180 we have outgoing changesets but refused to push
180 we have outgoing changesets but refused to push
181 - other values as described by addchangegroup()
181 - other values as described by addchangegroup()
182 '''
182 '''
183 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks)
183 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks)
184 if pushop.remote.local():
184 if pushop.remote.local():
185 missing = (set(pushop.repo.requirements)
185 missing = (set(pushop.repo.requirements)
186 - pushop.remote.local().supported)
186 - pushop.remote.local().supported)
187 if missing:
187 if missing:
188 msg = _("required features are not"
188 msg = _("required features are not"
189 " supported in the destination:"
189 " supported in the destination:"
190 " %s") % (', '.join(sorted(missing)))
190 " %s") % (', '.join(sorted(missing)))
191 raise util.Abort(msg)
191 raise util.Abort(msg)
192
192
193 # there are two ways to push to remote repo:
193 # there are two ways to push to remote repo:
194 #
194 #
195 # addchangegroup assumes local user can lock remote
195 # addchangegroup assumes local user can lock remote
196 # repo (local filesystem, old ssh servers).
196 # repo (local filesystem, old ssh servers).
197 #
197 #
198 # unbundle assumes local user cannot lock remote repo (new ssh
198 # unbundle assumes local user cannot lock remote repo (new ssh
199 # servers, http servers).
199 # servers, http servers).
200
200
201 if not pushop.remote.canpush():
201 if not pushop.remote.canpush():
202 raise util.Abort(_("destination does not support push"))
202 raise util.Abort(_("destination does not support push"))
203 # get local lock as we might write phase data
203 # get local lock as we might write phase data
204 localwlock = locallock = None
204 localwlock = locallock = None
205 try:
205 try:
206 # bundle2 push may receive a reply bundle touching bookmarks or other
206 # bundle2 push may receive a reply bundle touching bookmarks or other
207 # things requiring the wlock. Take it now to ensure proper ordering.
207 # things requiring the wlock. Take it now to ensure proper ordering.
208 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
208 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
209 if _canusebundle2(pushop) and maypushback:
209 if _canusebundle2(pushop) and maypushback:
210 localwlock = pushop.repo.wlock()
210 localwlock = pushop.repo.wlock()
211 locallock = pushop.repo.lock()
211 locallock = pushop.repo.lock()
212 pushop.locallocked = True
212 pushop.locallocked = True
213 except IOError, err:
213 except IOError, err:
214 pushop.locallocked = False
214 pushop.locallocked = False
215 if err.errno != errno.EACCES:
215 if err.errno != errno.EACCES:
216 raise
216 raise
217 # source repo cannot be locked.
217 # source repo cannot be locked.
218 # We do not abort the push, but just disable the local phase
218 # We do not abort the push, but just disable the local phase
219 # synchronisation.
219 # synchronisation.
220 msg = 'cannot lock source repository: %s\n' % err
220 msg = 'cannot lock source repository: %s\n' % err
221 pushop.ui.debug(msg)
221 pushop.ui.debug(msg)
222 try:
222 try:
223 if pushop.locallocked:
223 if pushop.locallocked:
224 pushop.trmanager = transactionmanager(repo,
224 pushop.trmanager = transactionmanager(repo,
225 'push-response',
225 'push-response',
226 pushop.remote.url())
226 pushop.remote.url())
227 pushop.repo.checkpush(pushop)
227 pushop.repo.checkpush(pushop)
228 lock = None
228 lock = None
229 unbundle = pushop.remote.capable('unbundle')
229 unbundle = pushop.remote.capable('unbundle')
230 if not unbundle:
230 if not unbundle:
231 lock = pushop.remote.lock()
231 lock = pushop.remote.lock()
232 try:
232 try:
233 _pushdiscovery(pushop)
233 _pushdiscovery(pushop)
234 if _canusebundle2(pushop):
234 if _canusebundle2(pushop):
235 _pushbundle2(pushop)
235 _pushbundle2(pushop)
236 _pushchangeset(pushop)
236 _pushchangeset(pushop)
237 _pushsyncphase(pushop)
237 _pushsyncphase(pushop)
238 _pushobsolete(pushop)
238 _pushobsolete(pushop)
239 _pushbookmark(pushop)
239 _pushbookmark(pushop)
240 finally:
240 finally:
241 if lock is not None:
241 if lock is not None:
242 lock.release()
242 lock.release()
243 if pushop.trmanager:
243 if pushop.trmanager:
244 pushop.trmanager.close()
244 pushop.trmanager.close()
245 finally:
245 finally:
246 if pushop.trmanager:
246 if pushop.trmanager:
247 pushop.trmanager.release()
247 pushop.trmanager.release()
248 if locallock is not None:
248 if locallock is not None:
249 locallock.release()
249 locallock.release()
250 if localwlock is not None:
250 if localwlock is not None:
251 localwlock.release()
251 localwlock.release()
252
252
253 return pushop
253 return pushop
254
254
255 # list of steps to perform discovery before push
255 # list of steps to perform discovery before push
256 pushdiscoveryorder = []
256 pushdiscoveryorder = []
257
257
258 # Mapping between step name and function
258 # Mapping between step name and function
259 #
259 #
260 # This exists to help extensions wrap steps if necessary
260 # This exists to help extensions wrap steps if necessary
261 pushdiscoverymapping = {}
261 pushdiscoverymapping = {}
262
262
263 def pushdiscovery(stepname):
263 def pushdiscovery(stepname):
264 """decorator for function performing discovery before push
264 """decorator for function performing discovery before push
265
265
266 The function is added to the step -> function mapping and appended to the
266 The function is added to the step -> function mapping and appended to the
267 list of steps. Beware that decorated function will be added in order (this
267 list of steps. Beware that decorated function will be added in order (this
268 may matter).
268 may matter).
269
269
270 You can only use this decorator for a new step, if you want to wrap a step
270 You can only use this decorator for a new step, if you want to wrap a step
271 from an extension, change the pushdiscovery dictionary directly."""
271 from an extension, change the pushdiscovery dictionary directly."""
272 def dec(func):
272 def dec(func):
273 assert stepname not in pushdiscoverymapping
273 assert stepname not in pushdiscoverymapping
274 pushdiscoverymapping[stepname] = func
274 pushdiscoverymapping[stepname] = func
275 pushdiscoveryorder.append(stepname)
275 pushdiscoveryorder.append(stepname)
276 return func
276 return func
277 return dec
277 return dec
278
278
279 def _pushdiscovery(pushop):
279 def _pushdiscovery(pushop):
280 """Run all discovery steps"""
280 """Run all discovery steps"""
281 for stepname in pushdiscoveryorder:
281 for stepname in pushdiscoveryorder:
282 step = pushdiscoverymapping[stepname]
282 step = pushdiscoverymapping[stepname]
283 step(pushop)
283 step(pushop)
284
284
285 @pushdiscovery('changeset')
285 @pushdiscovery('changeset')
286 def _pushdiscoverychangeset(pushop):
286 def _pushdiscoverychangeset(pushop):
287 """discover the changeset that need to be pushed"""
287 """discover the changeset that need to be pushed"""
288 fci = discovery.findcommonincoming
288 fci = discovery.findcommonincoming
289 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
289 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
290 common, inc, remoteheads = commoninc
290 common, inc, remoteheads = commoninc
291 fco = discovery.findcommonoutgoing
291 fco = discovery.findcommonoutgoing
292 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
292 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
293 commoninc=commoninc, force=pushop.force)
293 commoninc=commoninc, force=pushop.force)
294 pushop.outgoing = outgoing
294 pushop.outgoing = outgoing
295 pushop.remoteheads = remoteheads
295 pushop.remoteheads = remoteheads
296 pushop.incoming = inc
296 pushop.incoming = inc
297
297
298 @pushdiscovery('phase')
298 @pushdiscovery('phase')
299 def _pushdiscoveryphase(pushop):
299 def _pushdiscoveryphase(pushop):
300 """discover the phase that needs to be pushed
300 """discover the phase that needs to be pushed
301
301
302 (computed for both success and failure case for changesets push)"""
302 (computed for both success and failure case for changesets push)"""
303 outgoing = pushop.outgoing
303 outgoing = pushop.outgoing
304 unfi = pushop.repo.unfiltered()
304 unfi = pushop.repo.unfiltered()
305 remotephases = pushop.remote.listkeys('phases')
305 remotephases = pushop.remote.listkeys('phases')
306 publishing = remotephases.get('publishing', False)
306 publishing = remotephases.get('publishing', False)
307 ana = phases.analyzeremotephases(pushop.repo,
307 ana = phases.analyzeremotephases(pushop.repo,
308 pushop.fallbackheads,
308 pushop.fallbackheads,
309 remotephases)
309 remotephases)
310 pheads, droots = ana
310 pheads, droots = ana
311 extracond = ''
311 extracond = ''
312 if not publishing:
312 if not publishing:
313 extracond = ' and public()'
313 extracond = ' and public()'
314 revset = 'heads((%%ln::%%ln) %s)' % extracond
314 revset = 'heads((%%ln::%%ln) %s)' % extracond
315 # Get the list of all revs draft on remote by public here.
315 # Get the list of all revs draft on remote by public here.
316 # XXX Beware that revset break if droots is not strictly
316 # XXX Beware that revset break if droots is not strictly
317 # XXX root we may want to ensure it is but it is costly
317 # XXX root we may want to ensure it is but it is costly
318 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
318 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
319 if not outgoing.missing:
319 if not outgoing.missing:
320 future = fallback
320 future = fallback
321 else:
321 else:
322 # adds changeset we are going to push as draft
322 # adds changeset we are going to push as draft
323 #
323 #
324 # should not be necessary for publishing server, but because of an
324 # should not be necessary for publishing server, but because of an
325 # issue fixed in xxxxx we have to do it anyway.
325 # issue fixed in xxxxx we have to do it anyway.
326 fdroots = list(unfi.set('roots(%ln + %ln::)',
326 fdroots = list(unfi.set('roots(%ln + %ln::)',
327 outgoing.missing, droots))
327 outgoing.missing, droots))
328 fdroots = [f.node() for f in fdroots]
328 fdroots = [f.node() for f in fdroots]
329 future = list(unfi.set(revset, fdroots, pushop.futureheads))
329 future = list(unfi.set(revset, fdroots, pushop.futureheads))
330 pushop.outdatedphases = future
330 pushop.outdatedphases = future
331 pushop.fallbackoutdatedphases = fallback
331 pushop.fallbackoutdatedphases = fallback
332
332
333 @pushdiscovery('obsmarker')
333 @pushdiscovery('obsmarker')
334 def _pushdiscoveryobsmarkers(pushop):
334 def _pushdiscoveryobsmarkers(pushop):
335 if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
335 if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
336 and pushop.repo.obsstore
336 and pushop.repo.obsstore
337 and 'obsolete' in pushop.remote.listkeys('namespaces')):
337 and 'obsolete' in pushop.remote.listkeys('namespaces')):
338 repo = pushop.repo
338 repo = pushop.repo
339 # very naive computation, that can be quite expensive on big repo.
339 # very naive computation, that can be quite expensive on big repo.
340 # However: evolution is currently slow on them anyway.
340 # However: evolution is currently slow on them anyway.
341 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
341 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
342 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
342 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
343
343
344 @pushdiscovery('bookmarks')
344 @pushdiscovery('bookmarks')
345 def _pushdiscoverybookmarks(pushop):
345 def _pushdiscoverybookmarks(pushop):
346 ui = pushop.ui
346 ui = pushop.ui
347 repo = pushop.repo.unfiltered()
347 repo = pushop.repo.unfiltered()
348 remote = pushop.remote
348 remote = pushop.remote
349 ui.debug("checking for updated bookmarks\n")
349 ui.debug("checking for updated bookmarks\n")
350 ancestors = ()
350 ancestors = ()
351 if pushop.revs:
351 if pushop.revs:
352 revnums = map(repo.changelog.rev, pushop.revs)
352 revnums = map(repo.changelog.rev, pushop.revs)
353 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
353 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
354 remotebookmark = remote.listkeys('bookmarks')
354 remotebookmark = remote.listkeys('bookmarks')
355
355
356 explicit = set(pushop.bookmarks)
356 explicit = set(pushop.bookmarks)
357
357
358 comp = bookmod.compare(repo, repo._bookmarks, remotebookmark, srchex=hex)
358 comp = bookmod.compare(repo, repo._bookmarks, remotebookmark, srchex=hex)
359 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
359 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
360 for b, scid, dcid in advsrc:
360 for b, scid, dcid in advsrc:
361 if b in explicit:
361 if b in explicit:
362 explicit.remove(b)
362 explicit.remove(b)
363 if not ancestors or repo[scid].rev() in ancestors:
363 if not ancestors or repo[scid].rev() in ancestors:
364 pushop.outbookmarks.append((b, dcid, scid))
364 pushop.outbookmarks.append((b, dcid, scid))
365 # search added bookmark
365 # search added bookmark
366 for b, scid, dcid in addsrc:
366 for b, scid, dcid in addsrc:
367 if b in explicit:
367 if b in explicit:
368 explicit.remove(b)
368 explicit.remove(b)
369 pushop.outbookmarks.append((b, '', scid))
369 pushop.outbookmarks.append((b, '', scid))
370 # search for overwritten bookmark
370 # search for overwritten bookmark
371 for b, scid, dcid in advdst + diverge + differ:
371 for b, scid, dcid in advdst + diverge + differ:
372 if b in explicit:
372 if b in explicit:
373 explicit.remove(b)
373 explicit.remove(b)
374 pushop.outbookmarks.append((b, dcid, scid))
374 pushop.outbookmarks.append((b, dcid, scid))
375 # search for bookmark to delete
375 # search for bookmark to delete
376 for b, scid, dcid in adddst:
376 for b, scid, dcid in adddst:
377 if b in explicit:
377 if b in explicit:
378 explicit.remove(b)
378 explicit.remove(b)
379 # treat as "deleted locally"
379 # treat as "deleted locally"
380 pushop.outbookmarks.append((b, dcid, ''))
380 pushop.outbookmarks.append((b, dcid, ''))
381 # identical bookmarks shouldn't get reported
381 # identical bookmarks shouldn't get reported
382 for b, scid, dcid in same:
382 for b, scid, dcid in same:
383 if b in explicit:
383 if b in explicit:
384 explicit.remove(b)
384 explicit.remove(b)
385
385
386 if explicit:
386 if explicit:
387 explicit = sorted(explicit)
387 explicit = sorted(explicit)
388 # we should probably list all of them
388 # we should probably list all of them
389 ui.warn(_('bookmark %s does not exist on the local '
389 ui.warn(_('bookmark %s does not exist on the local '
390 'or remote repository!\n') % explicit[0])
390 'or remote repository!\n') % explicit[0])
391 pushop.bkresult = 2
391 pushop.bkresult = 2
392
392
393 pushop.outbookmarks.sort()
393 pushop.outbookmarks.sort()
394
394
395 def _pushcheckoutgoing(pushop):
395 def _pushcheckoutgoing(pushop):
396 outgoing = pushop.outgoing
396 outgoing = pushop.outgoing
397 unfi = pushop.repo.unfiltered()
397 unfi = pushop.repo.unfiltered()
398 if not outgoing.missing:
398 if not outgoing.missing:
399 # nothing to push
399 # nothing to push
400 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
400 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
401 return False
401 return False
402 # something to push
402 # something to push
403 if not pushop.force:
403 if not pushop.force:
404 # if repo.obsstore == False --> no obsolete
404 # if repo.obsstore == False --> no obsolete
405 # then, save the iteration
405 # then, save the iteration
406 if unfi.obsstore:
406 if unfi.obsstore:
407 # this message are here for 80 char limit reason
407 # this message are here for 80 char limit reason
408 mso = _("push includes obsolete changeset: %s!")
408 mso = _("push includes obsolete changeset: %s!")
409 mst = {"unstable": _("push includes unstable changeset: %s!"),
409 mst = {"unstable": _("push includes unstable changeset: %s!"),
410 "bumped": _("push includes bumped changeset: %s!"),
410 "bumped": _("push includes bumped changeset: %s!"),
411 "divergent": _("push includes divergent changeset: %s!")}
411 "divergent": _("push includes divergent changeset: %s!")}
412 # If we are to push if there is at least one
412 # If we are to push if there is at least one
413 # obsolete or unstable changeset in missing, at
413 # obsolete or unstable changeset in missing, at
414 # least one of the missinghead will be obsolete or
414 # least one of the missinghead will be obsolete or
415 # unstable. So checking heads only is ok
415 # unstable. So checking heads only is ok
416 for node in outgoing.missingheads:
416 for node in outgoing.missingheads:
417 ctx = unfi[node]
417 ctx = unfi[node]
418 if ctx.obsolete():
418 if ctx.obsolete():
419 raise util.Abort(mso % ctx)
419 raise util.Abort(mso % ctx)
420 elif ctx.troubled():
420 elif ctx.troubled():
421 raise util.Abort(mst[ctx.troubles()[0]] % ctx)
421 raise util.Abort(mst[ctx.troubles()[0]] % ctx)
422 newbm = pushop.ui.configlist('bookmarks', 'pushing')
422 newbm = pushop.ui.configlist('bookmarks', 'pushing')
423 discovery.checkheads(unfi, pushop.remote, outgoing,
423 discovery.checkheads(unfi, pushop.remote, outgoing,
424 pushop.remoteheads,
424 pushop.remoteheads,
425 pushop.newbranch,
425 pushop.newbranch,
426 bool(pushop.incoming),
426 bool(pushop.incoming),
427 newbm)
427 newbm)
428 return True
428 return True
429
429
430 # List of names of steps to perform for an outgoing bundle2, order matters.
430 # List of names of steps to perform for an outgoing bundle2, order matters.
431 b2partsgenorder = []
431 b2partsgenorder = []
432
432
433 # Mapping between step name and function
433 # Mapping between step name and function
434 #
434 #
435 # This exists to help extensions wrap steps if necessary
435 # This exists to help extensions wrap steps if necessary
436 b2partsgenmapping = {}
436 b2partsgenmapping = {}
437
437
438 def b2partsgenerator(stepname, idx=None):
438 def b2partsgenerator(stepname, idx=None):
439 """decorator for function generating bundle2 part
439 """decorator for function generating bundle2 part
440
440
441 The function is added to the step -> function mapping and appended to the
441 The function is added to the step -> function mapping and appended to the
442 list of steps. Beware that decorated functions will be added in order
442 list of steps. Beware that decorated functions will be added in order
443 (this may matter).
443 (this may matter).
444
444
445 You can only use this decorator for new steps, if you want to wrap a step
445 You can only use this decorator for new steps, if you want to wrap a step
446 from an extension, attack the b2partsgenmapping dictionary directly."""
446 from an extension, attack the b2partsgenmapping dictionary directly."""
447 def dec(func):
447 def dec(func):
448 assert stepname not in b2partsgenmapping
448 assert stepname not in b2partsgenmapping
449 b2partsgenmapping[stepname] = func
449 b2partsgenmapping[stepname] = func
450 if idx is None:
450 if idx is None:
451 b2partsgenorder.append(stepname)
451 b2partsgenorder.append(stepname)
452 else:
452 else:
453 b2partsgenorder.insert(idx, stepname)
453 b2partsgenorder.insert(idx, stepname)
454 return func
454 return func
455 return dec
455 return dec
456
456
457 @b2partsgenerator('changeset')
457 @b2partsgenerator('changeset')
458 def _pushb2ctx(pushop, bundler):
458 def _pushb2ctx(pushop, bundler):
459 """handle changegroup push through bundle2
459 """handle changegroup push through bundle2
460
460
461 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
461 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
462 """
462 """
463 if 'changesets' in pushop.stepsdone:
463 if 'changesets' in pushop.stepsdone:
464 return
464 return
465 pushop.stepsdone.add('changesets')
465 pushop.stepsdone.add('changesets')
466 # Send known heads to the server for race detection.
466 # Send known heads to the server for race detection.
467 if not _pushcheckoutgoing(pushop):
467 if not _pushcheckoutgoing(pushop):
468 return
468 return
469 pushop.repo.prepushoutgoinghooks(pushop.repo,
469 pushop.repo.prepushoutgoinghooks(pushop.repo,
470 pushop.remote,
470 pushop.remote,
471 pushop.outgoing)
471 pushop.outgoing)
472 if not pushop.force:
472 if not pushop.force:
473 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
473 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
474 b2caps = bundle2.bundle2caps(pushop.remote)
474 b2caps = bundle2.bundle2caps(pushop.remote)
475 version = None
475 version = None
476 cgversions = b2caps.get('changegroup')
476 cgversions = b2caps.get('changegroup')
477 if not cgversions: # 3.1 and 3.2 ship with an empty value
477 if not cgversions: # 3.1 and 3.2 ship with an empty value
478 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push',
478 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push',
479 pushop.outgoing)
479 pushop.outgoing)
480 else:
480 else:
481 cgversions = [v for v in cgversions if v in changegroup.packermap]
481 cgversions = [v for v in cgversions if v in changegroup.packermap]
482 if not cgversions:
482 if not cgversions:
483 raise ValueError(_('no common changegroup version'))
483 raise ValueError(_('no common changegroup version'))
484 version = max(cgversions)
484 version = max(cgversions)
485 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push',
485 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push',
486 pushop.outgoing,
486 pushop.outgoing,
487 version=version)
487 version=version)
488 cgpart = bundler.newpart('changegroup', data=cg)
488 cgpart = bundler.newpart('changegroup', data=cg)
489 if version is not None:
489 if version is not None:
490 cgpart.addparam('version', version)
490 cgpart.addparam('version', version)
491 def handlereply(op):
491 def handlereply(op):
492 """extract addchangegroup returns from server reply"""
492 """extract addchangegroup returns from server reply"""
493 cgreplies = op.records.getreplies(cgpart.id)
493 cgreplies = op.records.getreplies(cgpart.id)
494 assert len(cgreplies['changegroup']) == 1
494 assert len(cgreplies['changegroup']) == 1
495 pushop.cgresult = cgreplies['changegroup'][0]['return']
495 pushop.cgresult = cgreplies['changegroup'][0]['return']
496 return handlereply
496 return handlereply
497
497
498 @b2partsgenerator('phase')
498 @b2partsgenerator('phase')
499 def _pushb2phases(pushop, bundler):
499 def _pushb2phases(pushop, bundler):
500 """handle phase push through bundle2"""
500 """handle phase push through bundle2"""
501 if 'phases' in pushop.stepsdone:
501 if 'phases' in pushop.stepsdone:
502 return
502 return
503 b2caps = bundle2.bundle2caps(pushop.remote)
503 b2caps = bundle2.bundle2caps(pushop.remote)
504 if not 'pushkey' in b2caps:
504 if not 'pushkey' in b2caps:
505 return
505 return
506 pushop.stepsdone.add('phases')
506 pushop.stepsdone.add('phases')
507 part2node = []
507 part2node = []
508 enc = pushkey.encode
508 enc = pushkey.encode
509 for newremotehead in pushop.outdatedphases:
509 for newremotehead in pushop.outdatedphases:
510 part = bundler.newpart('pushkey')
510 part = bundler.newpart('pushkey')
511 part.addparam('namespace', enc('phases'))
511 part.addparam('namespace', enc('phases'))
512 part.addparam('key', enc(newremotehead.hex()))
512 part.addparam('key', enc(newremotehead.hex()))
513 part.addparam('old', enc(str(phases.draft)))
513 part.addparam('old', enc(str(phases.draft)))
514 part.addparam('new', enc(str(phases.public)))
514 part.addparam('new', enc(str(phases.public)))
515 part2node.append((part.id, newremotehead))
515 part2node.append((part.id, newremotehead))
516 def handlereply(op):
516 def handlereply(op):
517 for partid, node in part2node:
517 for partid, node in part2node:
518 partrep = op.records.getreplies(partid)
518 partrep = op.records.getreplies(partid)
519 results = partrep['pushkey']
519 results = partrep['pushkey']
520 assert len(results) <= 1
520 assert len(results) <= 1
521 msg = None
521 msg = None
522 if not results:
522 if not results:
523 msg = _('server ignored update of %s to public!\n') % node
523 msg = _('server ignored update of %s to public!\n') % node
524 elif not int(results[0]['return']):
524 elif not int(results[0]['return']):
525 msg = _('updating %s to public failed!\n') % node
525 msg = _('updating %s to public failed!\n') % node
526 if msg is not None:
526 if msg is not None:
527 pushop.ui.warn(msg)
527 pushop.ui.warn(msg)
528 return handlereply
528 return handlereply
529
529
530 @b2partsgenerator('obsmarkers')
530 @b2partsgenerator('obsmarkers')
531 def _pushb2obsmarkers(pushop, bundler):
531 def _pushb2obsmarkers(pushop, bundler):
532 if 'obsmarkers' in pushop.stepsdone:
532 if 'obsmarkers' in pushop.stepsdone:
533 return
533 return
534 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
534 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
535 if obsolete.commonversion(remoteversions) is None:
535 if obsolete.commonversion(remoteversions) is None:
536 return
536 return
537 pushop.stepsdone.add('obsmarkers')
537 pushop.stepsdone.add('obsmarkers')
538 if pushop.outobsmarkers:
538 if pushop.outobsmarkers:
539 buildobsmarkerspart(bundler, pushop.outobsmarkers)
539 buildobsmarkerspart(bundler, pushop.outobsmarkers)
540
540
541 @b2partsgenerator('bookmarks')
541 @b2partsgenerator('bookmarks')
542 def _pushb2bookmarks(pushop, bundler):
542 def _pushb2bookmarks(pushop, bundler):
543 """handle phase push through bundle2"""
543 """handle phase push through bundle2"""
544 if 'bookmarks' in pushop.stepsdone:
544 if 'bookmarks' in pushop.stepsdone:
545 return
545 return
546 b2caps = bundle2.bundle2caps(pushop.remote)
546 b2caps = bundle2.bundle2caps(pushop.remote)
547 if 'pushkey' not in b2caps:
547 if 'pushkey' not in b2caps:
548 return
548 return
549 pushop.stepsdone.add('bookmarks')
549 pushop.stepsdone.add('bookmarks')
550 part2book = []
550 part2book = []
551 enc = pushkey.encode
551 enc = pushkey.encode
552 for book, old, new in pushop.outbookmarks:
552 for book, old, new in pushop.outbookmarks:
553 part = bundler.newpart('pushkey')
553 part = bundler.newpart('pushkey')
554 part.addparam('namespace', enc('bookmarks'))
554 part.addparam('namespace', enc('bookmarks'))
555 part.addparam('key', enc(book))
555 part.addparam('key', enc(book))
556 part.addparam('old', enc(old))
556 part.addparam('old', enc(old))
557 part.addparam('new', enc(new))
557 part.addparam('new', enc(new))
558 action = 'update'
558 action = 'update'
559 if not old:
559 if not old:
560 action = 'export'
560 action = 'export'
561 elif not new:
561 elif not new:
562 action = 'delete'
562 action = 'delete'
563 part2book.append((part.id, book, action))
563 part2book.append((part.id, book, action))
564
564
565
565
566 def handlereply(op):
566 def handlereply(op):
567 ui = pushop.ui
567 ui = pushop.ui
568 for partid, book, action in part2book:
568 for partid, book, action in part2book:
569 partrep = op.records.getreplies(partid)
569 partrep = op.records.getreplies(partid)
570 results = partrep['pushkey']
570 results = partrep['pushkey']
571 assert len(results) <= 1
571 assert len(results) <= 1
572 if not results:
572 if not results:
573 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
573 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
574 else:
574 else:
575 ret = int(results[0]['return'])
575 ret = int(results[0]['return'])
576 if ret:
576 if ret:
577 ui.status(bookmsgmap[action][0] % book)
577 ui.status(bookmsgmap[action][0] % book)
578 else:
578 else:
579 ui.warn(bookmsgmap[action][1] % book)
579 ui.warn(bookmsgmap[action][1] % book)
580 if pushop.bkresult is not None:
580 if pushop.bkresult is not None:
581 pushop.bkresult = 1
581 pushop.bkresult = 1
582 return handlereply
582 return handlereply
583
583
584
584
585 def _pushbundle2(pushop):
585 def _pushbundle2(pushop):
586 """push data to the remote using bundle2
586 """push data to the remote using bundle2
587
587
588 The only currently supported type of data is changegroup but this will
588 The only currently supported type of data is changegroup but this will
589 evolve in the future."""
589 evolve in the future."""
590 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
590 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
591 pushback = (pushop.trmanager
591 pushback = (pushop.trmanager
592 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
592 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
593
593
594 # create reply capability
594 # create reply capability
595 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
595 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
596 allowpushback=pushback))
596 allowpushback=pushback))
597 bundler.newpart('replycaps', data=capsblob)
597 bundler.newpart('replycaps', data=capsblob)
598 replyhandlers = []
598 replyhandlers = []
599 for partgenname in b2partsgenorder:
599 for partgenname in b2partsgenorder:
600 partgen = b2partsgenmapping[partgenname]
600 partgen = b2partsgenmapping[partgenname]
601 ret = partgen(pushop, bundler)
601 ret = partgen(pushop, bundler)
602 if callable(ret):
602 if callable(ret):
603 replyhandlers.append(ret)
603 replyhandlers.append(ret)
604 # do not push if nothing to push
604 # do not push if nothing to push
605 if bundler.nbparts <= 1:
605 if bundler.nbparts <= 1:
606 return
606 return
607 stream = util.chunkbuffer(bundler.getchunks())
607 stream = util.chunkbuffer(bundler.getchunks())
608 try:
608 try:
609 reply = pushop.remote.unbundle(stream, ['force'], 'push')
609 reply = pushop.remote.unbundle(stream, ['force'], 'push')
610 except error.BundleValueError, exc:
610 except error.BundleValueError, exc:
611 raise util.Abort('missing support for %s' % exc)
611 raise util.Abort('missing support for %s' % exc)
612 try:
612 try:
613 trgetter = None
613 trgetter = None
614 if pushback:
614 if pushback:
615 trgetter = pushop.trmanager.transaction
615 trgetter = pushop.trmanager.transaction
616 op = bundle2.processbundle(pushop.repo, reply, trgetter)
616 op = bundle2.processbundle(pushop.repo, reply, trgetter)
617 except error.BundleValueError, exc:
617 except error.BundleValueError, exc:
618 raise util.Abort('missing support for %s' % exc)
618 raise util.Abort('missing support for %s' % exc)
619 for rephand in replyhandlers:
619 for rephand in replyhandlers:
620 rephand(op)
620 rephand(op)
621
621
622 def _pushchangeset(pushop):
622 def _pushchangeset(pushop):
623 """Make the actual push of changeset bundle to remote repo"""
623 """Make the actual push of changeset bundle to remote repo"""
624 if 'changesets' in pushop.stepsdone:
624 if 'changesets' in pushop.stepsdone:
625 return
625 return
626 pushop.stepsdone.add('changesets')
626 pushop.stepsdone.add('changesets')
627 if not _pushcheckoutgoing(pushop):
627 if not _pushcheckoutgoing(pushop):
628 return
628 return
629 pushop.repo.prepushoutgoinghooks(pushop.repo,
629 pushop.repo.prepushoutgoinghooks(pushop.repo,
630 pushop.remote,
630 pushop.remote,
631 pushop.outgoing)
631 pushop.outgoing)
632 outgoing = pushop.outgoing
632 outgoing = pushop.outgoing
633 unbundle = pushop.remote.capable('unbundle')
633 unbundle = pushop.remote.capable('unbundle')
634 # TODO: get bundlecaps from remote
634 # TODO: get bundlecaps from remote
635 bundlecaps = None
635 bundlecaps = None
636 # create a changegroup from local
636 # create a changegroup from local
637 if pushop.revs is None and not (outgoing.excluded
637 if pushop.revs is None and not (outgoing.excluded
638 or pushop.repo.changelog.filteredrevs):
638 or pushop.repo.changelog.filteredrevs):
639 # push everything,
639 # push everything,
640 # use the fast path, no race possible on push
640 # use the fast path, no race possible on push
641 bundler = changegroup.cg1packer(pushop.repo, bundlecaps)
641 bundler = changegroup.cg1packer(pushop.repo, bundlecaps)
642 cg = changegroup.getsubset(pushop.repo,
642 cg = changegroup.getsubset(pushop.repo,
643 outgoing,
643 outgoing,
644 bundler,
644 bundler,
645 'push',
645 'push',
646 fastpath=True)
646 fastpath=True)
647 else:
647 else:
648 cg = changegroup.getlocalchangegroup(pushop.repo, 'push', outgoing,
648 cg = changegroup.getlocalchangegroup(pushop.repo, 'push', outgoing,
649 bundlecaps)
649 bundlecaps)
650
650
651 # apply changegroup to remote
651 # apply changegroup to remote
652 if unbundle:
652 if unbundle:
653 # local repo finds heads on server, finds out what
653 # local repo finds heads on server, finds out what
654 # revs it must push. once revs transferred, if server
654 # revs it must push. once revs transferred, if server
655 # finds it has different heads (someone else won
655 # finds it has different heads (someone else won
656 # commit/push race), server aborts.
656 # commit/push race), server aborts.
657 if pushop.force:
657 if pushop.force:
658 remoteheads = ['force']
658 remoteheads = ['force']
659 else:
659 else:
660 remoteheads = pushop.remoteheads
660 remoteheads = pushop.remoteheads
661 # ssh: return remote's addchangegroup()
661 # ssh: return remote's addchangegroup()
662 # http: return remote's addchangegroup() or 0 for error
662 # http: return remote's addchangegroup() or 0 for error
663 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
663 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
664 pushop.repo.url())
664 pushop.repo.url())
665 else:
665 else:
666 # we return an integer indicating remote head count
666 # we return an integer indicating remote head count
667 # change
667 # change
668 pushop.cgresult = pushop.remote.addchangegroup(cg, 'push',
668 pushop.cgresult = pushop.remote.addchangegroup(cg, 'push',
669 pushop.repo.url())
669 pushop.repo.url())
670
670
671 def _pushsyncphase(pushop):
671 def _pushsyncphase(pushop):
672 """synchronise phase information locally and remotely"""
672 """synchronise phase information locally and remotely"""
673 cheads = pushop.commonheads
673 cheads = pushop.commonheads
674 # even when we don't push, exchanging phase data is useful
674 # even when we don't push, exchanging phase data is useful
675 remotephases = pushop.remote.listkeys('phases')
675 remotephases = pushop.remote.listkeys('phases')
676 if (pushop.ui.configbool('ui', '_usedassubrepo', False)
676 if (pushop.ui.configbool('ui', '_usedassubrepo', False)
677 and remotephases # server supports phases
677 and remotephases # server supports phases
678 and pushop.cgresult is None # nothing was pushed
678 and pushop.cgresult is None # nothing was pushed
679 and remotephases.get('publishing', False)):
679 and remotephases.get('publishing', False)):
680 # When:
680 # When:
681 # - this is a subrepo push
681 # - this is a subrepo push
682 # - and remote support phase
682 # - and remote support phase
683 # - and no changeset was pushed
683 # - and no changeset was pushed
684 # - and remote is publishing
684 # - and remote is publishing
685 # We may be in issue 3871 case!
685 # We may be in issue 3871 case!
686 # We drop the possible phase synchronisation done by
686 # We drop the possible phase synchronisation done by
687 # courtesy to publish changesets possibly locally draft
687 # courtesy to publish changesets possibly locally draft
688 # on the remote.
688 # on the remote.
689 remotephases = {'publishing': 'True'}
689 remotephases = {'publishing': 'True'}
690 if not remotephases: # old server or public only reply from non-publishing
690 if not remotephases: # old server or public only reply from non-publishing
691 _localphasemove(pushop, cheads)
691 _localphasemove(pushop, cheads)
692 # don't push any phase data as there is nothing to push
692 # don't push any phase data as there is nothing to push
693 else:
693 else:
694 ana = phases.analyzeremotephases(pushop.repo, cheads,
694 ana = phases.analyzeremotephases(pushop.repo, cheads,
695 remotephases)
695 remotephases)
696 pheads, droots = ana
696 pheads, droots = ana
697 ### Apply remote phase on local
697 ### Apply remote phase on local
698 if remotephases.get('publishing', False):
698 if remotephases.get('publishing', False):
699 _localphasemove(pushop, cheads)
699 _localphasemove(pushop, cheads)
700 else: # publish = False
700 else: # publish = False
701 _localphasemove(pushop, pheads)
701 _localphasemove(pushop, pheads)
702 _localphasemove(pushop, cheads, phases.draft)
702 _localphasemove(pushop, cheads, phases.draft)
703 ### Apply local phase on remote
703 ### Apply local phase on remote
704
704
705 if pushop.cgresult:
705 if pushop.cgresult:
706 if 'phases' in pushop.stepsdone:
706 if 'phases' in pushop.stepsdone:
707 # phases already pushed though bundle2
707 # phases already pushed though bundle2
708 return
708 return
709 outdated = pushop.outdatedphases
709 outdated = pushop.outdatedphases
710 else:
710 else:
711 outdated = pushop.fallbackoutdatedphases
711 outdated = pushop.fallbackoutdatedphases
712
712
713 pushop.stepsdone.add('phases')
713 pushop.stepsdone.add('phases')
714
714
715 # filter heads already turned public by the push
715 # filter heads already turned public by the push
716 outdated = [c for c in outdated if c.node() not in pheads]
716 outdated = [c for c in outdated if c.node() not in pheads]
717 # fallback to independent pushkey command
717 # fallback to independent pushkey command
718 for newremotehead in outdated:
718 for newremotehead in outdated:
719 r = pushop.remote.pushkey('phases',
719 r = pushop.remote.pushkey('phases',
720 newremotehead.hex(),
720 newremotehead.hex(),
721 str(phases.draft),
721 str(phases.draft),
722 str(phases.public))
722 str(phases.public))
723 if not r:
723 if not r:
724 pushop.ui.warn(_('updating %s to public failed!\n')
724 pushop.ui.warn(_('updating %s to public failed!\n')
725 % newremotehead)
725 % newremotehead)
726
726
727 def _localphasemove(pushop, nodes, phase=phases.public):
727 def _localphasemove(pushop, nodes, phase=phases.public):
728 """move <nodes> to <phase> in the local source repo"""
728 """move <nodes> to <phase> in the local source repo"""
729 if pushop.trmanager:
729 if pushop.trmanager:
730 phases.advanceboundary(pushop.repo,
730 phases.advanceboundary(pushop.repo,
731 pushop.trmanager.transaction(),
731 pushop.trmanager.transaction(),
732 phase,
732 phase,
733 nodes)
733 nodes)
734 else:
734 else:
735 # repo is not locked, do not change any phases!
735 # repo is not locked, do not change any phases!
736 # Informs the user that phases should have been moved when
736 # Informs the user that phases should have been moved when
737 # applicable.
737 # applicable.
738 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
738 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
739 phasestr = phases.phasenames[phase]
739 phasestr = phases.phasenames[phase]
740 if actualmoves:
740 if actualmoves:
741 pushop.ui.status(_('cannot lock source repo, skipping '
741 pushop.ui.status(_('cannot lock source repo, skipping '
742 'local %s phase update\n') % phasestr)
742 'local %s phase update\n') % phasestr)
743
743
744 def _pushobsolete(pushop):
744 def _pushobsolete(pushop):
745 """utility function to push obsolete markers to a remote"""
745 """utility function to push obsolete markers to a remote"""
746 if 'obsmarkers' in pushop.stepsdone:
746 if 'obsmarkers' in pushop.stepsdone:
747 return
747 return
748 pushop.ui.debug('try to push obsolete markers to remote\n')
748 pushop.ui.debug('try to push obsolete markers to remote\n')
749 repo = pushop.repo
749 repo = pushop.repo
750 remote = pushop.remote
750 remote = pushop.remote
751 pushop.stepsdone.add('obsmarkers')
751 pushop.stepsdone.add('obsmarkers')
752 if pushop.outobsmarkers:
752 if pushop.outobsmarkers:
753 rslts = []
753 rslts = []
754 remotedata = obsolete._pushkeyescape(pushop.outobsmarkers)
754 remotedata = obsolete._pushkeyescape(pushop.outobsmarkers)
755 for key in sorted(remotedata, reverse=True):
755 for key in sorted(remotedata, reverse=True):
756 # reverse sort to ensure we end with dump0
756 # reverse sort to ensure we end with dump0
757 data = remotedata[key]
757 data = remotedata[key]
758 rslts.append(remote.pushkey('obsolete', key, '', data))
758 rslts.append(remote.pushkey('obsolete', key, '', data))
759 if [r for r in rslts if not r]:
759 if [r for r in rslts if not r]:
760 msg = _('failed to push some obsolete markers!\n')
760 msg = _('failed to push some obsolete markers!\n')
761 repo.ui.warn(msg)
761 repo.ui.warn(msg)
762
762
763 def _pushbookmark(pushop):
763 def _pushbookmark(pushop):
764 """Update bookmark position on remote"""
764 """Update bookmark position on remote"""
765 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
765 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
766 return
766 return
767 pushop.stepsdone.add('bookmarks')
767 pushop.stepsdone.add('bookmarks')
768 ui = pushop.ui
768 ui = pushop.ui
769 remote = pushop.remote
769 remote = pushop.remote
770
770
771 for b, old, new in pushop.outbookmarks:
771 for b, old, new in pushop.outbookmarks:
772 action = 'update'
772 action = 'update'
773 if not old:
773 if not old:
774 action = 'export'
774 action = 'export'
775 elif not new:
775 elif not new:
776 action = 'delete'
776 action = 'delete'
777 if remote.pushkey('bookmarks', b, old, new):
777 if remote.pushkey('bookmarks', b, old, new):
778 ui.status(bookmsgmap[action][0] % b)
778 ui.status(bookmsgmap[action][0] % b)
779 else:
779 else:
780 ui.warn(bookmsgmap[action][1] % b)
780 ui.warn(bookmsgmap[action][1] % b)
781 # discovery can have set the value form invalid entry
781 # discovery can have set the value form invalid entry
782 if pushop.bkresult is not None:
782 if pushop.bkresult is not None:
783 pushop.bkresult = 1
783 pushop.bkresult = 1
784
784
785 class pulloperation(object):
785 class pulloperation(object):
786 """A object that represent a single pull operation
786 """A object that represent a single pull operation
787
787
788 It purpose is to carry pull related state and very common operation.
788 It purpose is to carry pull related state and very common operation.
789
789
790 A new should be created at the beginning of each pull and discarded
790 A new should be created at the beginning of each pull and discarded
791 afterward.
791 afterward.
792 """
792 """
793
793
794 def __init__(self, repo, remote, heads=None, force=False, bookmarks=()):
794 def __init__(self, repo, remote, heads=None, force=False, bookmarks=()):
795 # repo we pull into
795 # repo we pull into
796 self.repo = repo
796 self.repo = repo
797 # repo we pull from
797 # repo we pull from
798 self.remote = remote
798 self.remote = remote
799 # revision we try to pull (None is "all")
799 # revision we try to pull (None is "all")
800 self.heads = heads
800 self.heads = heads
801 # bookmark pulled explicitly
801 # bookmark pulled explicitly
802 self.explicitbookmarks = bookmarks
802 self.explicitbookmarks = bookmarks
803 # do we force pull?
803 # do we force pull?
804 self.force = force
804 self.force = force
805 # transaction manager
805 # transaction manager
806 self.trmanager = None
806 self.trmanager = None
807 # set of common changeset between local and remote before pull
807 # set of common changeset between local and remote before pull
808 self.common = None
808 self.common = None
809 # set of pulled head
809 # set of pulled head
810 self.rheads = None
810 self.rheads = None
811 # list of missing changeset to fetch remotely
811 # list of missing changeset to fetch remotely
812 self.fetch = None
812 self.fetch = None
813 # remote bookmarks data
813 # remote bookmarks data
814 self.remotebookmarks = None
814 self.remotebookmarks = None
815 # result of changegroup pulling (used as return code by pull)
815 # result of changegroup pulling (used as return code by pull)
816 self.cgresult = None
816 self.cgresult = None
817 # list of step already done
817 # list of step already done
818 self.stepsdone = set()
818 self.stepsdone = set()
819
819
820 @util.propertycache
820 @util.propertycache
821 def pulledsubset(self):
821 def pulledsubset(self):
822 """heads of the set of changeset target by the pull"""
822 """heads of the set of changeset target by the pull"""
823 # compute target subset
823 # compute target subset
824 if self.heads is None:
824 if self.heads is None:
825 # We pulled every thing possible
825 # We pulled every thing possible
826 # sync on everything common
826 # sync on everything common
827 c = set(self.common)
827 c = set(self.common)
828 ret = list(self.common)
828 ret = list(self.common)
829 for n in self.rheads:
829 for n in self.rheads:
830 if n not in c:
830 if n not in c:
831 ret.append(n)
831 ret.append(n)
832 return ret
832 return ret
833 else:
833 else:
834 # We pulled a specific subset
834 # We pulled a specific subset
835 # sync on this subset
835 # sync on this subset
836 return self.heads
836 return self.heads
837
837
838 def gettransaction(self):
838 def gettransaction(self):
839 # deprecated; talk to trmanager directly
839 # deprecated; talk to trmanager directly
840 return self.trmanager.transaction()
840 return self.trmanager.transaction()
841
841
842 class transactionmanager(object):
842 class transactionmanager(object):
843 """An object to manage the life cycle of a transaction
843 """An object to manage the life cycle of a transaction
844
844
845 It creates the transaction on demand and calls the appropriate hooks when
845 It creates the transaction on demand and calls the appropriate hooks when
846 closing the transaction."""
846 closing the transaction."""
847 def __init__(self, repo, source, url):
847 def __init__(self, repo, source, url):
848 self.repo = repo
848 self.repo = repo
849 self.source = source
849 self.source = source
850 self.url = url
850 self.url = url
851 self._tr = None
851 self._tr = None
852
852
853 def transaction(self):
853 def transaction(self):
854 """Return an open transaction object, constructing if necessary"""
854 """Return an open transaction object, constructing if necessary"""
855 if not self._tr:
855 if not self._tr:
856 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
856 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
857 self._tr = self.repo.transaction(trname)
857 self._tr = self.repo.transaction(trname)
858 self._tr.hookargs['source'] = self.source
858 self._tr.hookargs['source'] = self.source
859 self._tr.hookargs['url'] = self.url
859 self._tr.hookargs['url'] = self.url
860 return self._tr
860 return self._tr
861
861
862 def close(self):
862 def close(self):
863 """close transaction if created"""
863 """close transaction if created"""
864 if self._tr is not None:
864 if self._tr is not None:
865 self._tr.close()
865 self._tr.close()
866
866
867 def release(self):
867 def release(self):
868 """release transaction if created"""
868 """release transaction if created"""
869 if self._tr is not None:
869 if self._tr is not None:
870 self._tr.release()
870 self._tr.release()
871
871
872 def pull(repo, remote, heads=None, force=False, bookmarks=()):
872 def pull(repo, remote, heads=None, force=False, bookmarks=()):
873 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks)
873 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks)
874 if pullop.remote.local():
874 if pullop.remote.local():
875 missing = set(pullop.remote.requirements) - pullop.repo.supported
875 missing = set(pullop.remote.requirements) - pullop.repo.supported
876 if missing:
876 if missing:
877 msg = _("required features are not"
877 msg = _("required features are not"
878 " supported in the destination:"
878 " supported in the destination:"
879 " %s") % (', '.join(sorted(missing)))
879 " %s") % (', '.join(sorted(missing)))
880 raise util.Abort(msg)
880 raise util.Abort(msg)
881
881
882 pullop.remotebookmarks = remote.listkeys('bookmarks')
882 pullop.remotebookmarks = remote.listkeys('bookmarks')
883 lock = pullop.repo.lock()
883 lock = pullop.repo.lock()
884 try:
884 try:
885 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
885 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
886 _pulldiscovery(pullop)
886 _pulldiscovery(pullop)
887 if _canusebundle2(pullop):
887 if _canusebundle2(pullop):
888 _pullbundle2(pullop)
888 _pullbundle2(pullop)
889 _pullchangeset(pullop)
889 _pullchangeset(pullop)
890 _pullphase(pullop)
890 _pullphase(pullop)
891 _pullbookmarks(pullop)
891 _pullbookmarks(pullop)
892 _pullobsolete(pullop)
892 _pullobsolete(pullop)
893 pullop.trmanager.close()
893 pullop.trmanager.close()
894 finally:
894 finally:
895 pullop.trmanager.release()
895 pullop.trmanager.release()
896 lock.release()
896 lock.release()
897
897
898 return pullop
898 return pullop
899
899
900 # list of steps to perform discovery before pull
900 # list of steps to perform discovery before pull
901 pulldiscoveryorder = []
901 pulldiscoveryorder = []
902
902
903 # Mapping between step name and function
903 # Mapping between step name and function
904 #
904 #
905 # This exists to help extensions wrap steps if necessary
905 # This exists to help extensions wrap steps if necessary
906 pulldiscoverymapping = {}
906 pulldiscoverymapping = {}
907
907
908 def pulldiscovery(stepname):
908 def pulldiscovery(stepname):
909 """decorator for function performing discovery before pull
909 """decorator for function performing discovery before pull
910
910
911 The function is added to the step -> function mapping and appended to the
911 The function is added to the step -> function mapping and appended to the
912 list of steps. Beware that decorated function will be added in order (this
912 list of steps. Beware that decorated function will be added in order (this
913 may matter).
913 may matter).
914
914
915 You can only use this decorator for a new step, if you want to wrap a step
915 You can only use this decorator for a new step, if you want to wrap a step
916 from an extension, change the pulldiscovery dictionary directly."""
916 from an extension, change the pulldiscovery dictionary directly."""
917 def dec(func):
917 def dec(func):
918 assert stepname not in pulldiscoverymapping
918 assert stepname not in pulldiscoverymapping
919 pulldiscoverymapping[stepname] = func
919 pulldiscoverymapping[stepname] = func
920 pulldiscoveryorder.append(stepname)
920 pulldiscoveryorder.append(stepname)
921 return func
921 return func
922 return dec
922 return dec
923
923
924 def _pulldiscovery(pullop):
924 def _pulldiscovery(pullop):
925 """Run all discovery steps"""
925 """Run all discovery steps"""
926 for stepname in pulldiscoveryorder:
926 for stepname in pulldiscoveryorder:
927 step = pulldiscoverymapping[stepname]
927 step = pulldiscoverymapping[stepname]
928 step(pullop)
928 step(pullop)
929
929
930 @pulldiscovery('changegroup')
930 @pulldiscovery('changegroup')
931 def _pulldiscoverychangegroup(pullop):
931 def _pulldiscoverychangegroup(pullop):
932 """discovery phase for the pull
932 """discovery phase for the pull
933
933
934 Current handle changeset discovery only, will change handle all discovery
934 Current handle changeset discovery only, will change handle all discovery
935 at some point."""
935 at some point."""
936 tmp = discovery.findcommonincoming(pullop.repo,
936 tmp = discovery.findcommonincoming(pullop.repo,
937 pullop.remote,
937 pullop.remote,
938 heads=pullop.heads,
938 heads=pullop.heads,
939 force=pullop.force)
939 force=pullop.force)
940 common, fetch, rheads = tmp
940 common, fetch, rheads = tmp
941 nm = pullop.repo.unfiltered().changelog.nodemap
941 nm = pullop.repo.unfiltered().changelog.nodemap
942 if fetch and rheads:
942 if fetch and rheads:
943 # If a remote heads in filtered locally, lets drop it from the unknown
943 # If a remote heads in filtered locally, lets drop it from the unknown
944 # remote heads and put in back in common.
944 # remote heads and put in back in common.
945 #
945 #
946 # This is a hackish solution to catch most of "common but locally
946 # This is a hackish solution to catch most of "common but locally
947 # hidden situation". We do not performs discovery on unfiltered
947 # hidden situation". We do not performs discovery on unfiltered
948 # repository because it end up doing a pathological amount of round
948 # repository because it end up doing a pathological amount of round
949 # trip for w huge amount of changeset we do not care about.
949 # trip for w huge amount of changeset we do not care about.
950 #
950 #
951 # If a set of such "common but filtered" changeset exist on the server
951 # If a set of such "common but filtered" changeset exist on the server
952 # but are not including a remote heads, we'll not be able to detect it,
952 # but are not including a remote heads, we'll not be able to detect it,
953 scommon = set(common)
953 scommon = set(common)
954 filteredrheads = []
954 filteredrheads = []
955 for n in rheads:
955 for n in rheads:
956 if n in nm:
956 if n in nm:
957 if n not in scommon:
957 if n not in scommon:
958 common.append(n)
958 common.append(n)
959 else:
959 else:
960 filteredrheads.append(n)
960 filteredrheads.append(n)
961 if not filteredrheads:
961 if not filteredrheads:
962 fetch = []
962 fetch = []
963 rheads = filteredrheads
963 rheads = filteredrheads
964 pullop.common = common
964 pullop.common = common
965 pullop.fetch = fetch
965 pullop.fetch = fetch
966 pullop.rheads = rheads
966 pullop.rheads = rheads
967
967
968 def _pullbundle2(pullop):
968 def _pullbundle2(pullop):
969 """pull data using bundle2
969 """pull data using bundle2
970
970
971 For now, the only supported data are changegroup."""
971 For now, the only supported data are changegroup."""
972 remotecaps = bundle2.bundle2caps(pullop.remote)
972 remotecaps = bundle2.bundle2caps(pullop.remote)
973 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
973 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
974 # pulling changegroup
974 # pulling changegroup
975 pullop.stepsdone.add('changegroup')
975 pullop.stepsdone.add('changegroup')
976
976
977 kwargs['common'] = pullop.common
977 kwargs['common'] = pullop.common
978 kwargs['heads'] = pullop.heads or pullop.rheads
978 kwargs['heads'] = pullop.heads or pullop.rheads
979 kwargs['cg'] = pullop.fetch
979 kwargs['cg'] = pullop.fetch
980 if 'listkeys' in remotecaps:
980 if 'listkeys' in remotecaps:
981 kwargs['listkeys'] = ['phase', 'bookmarks']
981 kwargs['listkeys'] = ['phase', 'bookmarks']
982 if not pullop.fetch:
982 if not pullop.fetch:
983 pullop.repo.ui.status(_("no changes found\n"))
983 pullop.repo.ui.status(_("no changes found\n"))
984 pullop.cgresult = 0
984 pullop.cgresult = 0
985 else:
985 else:
986 if pullop.heads is None and list(pullop.common) == [nullid]:
986 if pullop.heads is None and list(pullop.common) == [nullid]:
987 pullop.repo.ui.status(_("requesting all changes\n"))
987 pullop.repo.ui.status(_("requesting all changes\n"))
988 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
988 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
989 remoteversions = bundle2.obsmarkersversion(remotecaps)
989 remoteversions = bundle2.obsmarkersversion(remotecaps)
990 if obsolete.commonversion(remoteversions) is not None:
990 if obsolete.commonversion(remoteversions) is not None:
991 kwargs['obsmarkers'] = True
991 kwargs['obsmarkers'] = True
992 pullop.stepsdone.add('obsmarkers')
992 pullop.stepsdone.add('obsmarkers')
993 _pullbundle2extraprepare(pullop, kwargs)
993 _pullbundle2extraprepare(pullop, kwargs)
994 bundle = pullop.remote.getbundle('pull', **kwargs)
994 bundle = pullop.remote.getbundle('pull', **kwargs)
995 try:
995 try:
996 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
996 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
997 except error.BundleValueError, exc:
997 except error.BundleValueError, exc:
998 raise util.Abort('missing support for %s' % exc)
998 raise util.Abort('missing support for %s' % exc)
999
999
1000 if pullop.fetch:
1000 if pullop.fetch:
1001 results = [cg['return'] for cg in op.records['changegroup']]
1001 results = [cg['return'] for cg in op.records['changegroup']]
1002 pullop.cgresult = changegroup.combineresults(results)
1002 pullop.cgresult = changegroup.combineresults(results)
1003
1003
1004 # processing phases change
1004 # processing phases change
1005 for namespace, value in op.records['listkeys']:
1005 for namespace, value in op.records['listkeys']:
1006 if namespace == 'phases':
1006 if namespace == 'phases':
1007 _pullapplyphases(pullop, value)
1007 _pullapplyphases(pullop, value)
1008
1008
1009 # processing bookmark update
1009 # processing bookmark update
1010 for namespace, value in op.records['listkeys']:
1010 for namespace, value in op.records['listkeys']:
1011 if namespace == 'bookmarks':
1011 if namespace == 'bookmarks':
1012 pullop.remotebookmarks = value
1012 pullop.remotebookmarks = value
1013 _pullbookmarks(pullop)
1013 _pullbookmarks(pullop)
1014
1014
1015 def _pullbundle2extraprepare(pullop, kwargs):
1015 def _pullbundle2extraprepare(pullop, kwargs):
1016 """hook function so that extensions can extend the getbundle call"""
1016 """hook function so that extensions can extend the getbundle call"""
1017 pass
1017 pass
1018
1018
1019 def _pullchangeset(pullop):
1019 def _pullchangeset(pullop):
1020 """pull changeset from unbundle into the local repo"""
1020 """pull changeset from unbundle into the local repo"""
1021 # We delay the open of the transaction as late as possible so we
1021 # We delay the open of the transaction as late as possible so we
1022 # don't open transaction for nothing or you break future useful
1022 # don't open transaction for nothing or you break future useful
1023 # rollback call
1023 # rollback call
1024 if 'changegroup' in pullop.stepsdone:
1024 if 'changegroup' in pullop.stepsdone:
1025 return
1025 return
1026 pullop.stepsdone.add('changegroup')
1026 pullop.stepsdone.add('changegroup')
1027 if not pullop.fetch:
1027 if not pullop.fetch:
1028 pullop.repo.ui.status(_("no changes found\n"))
1028 pullop.repo.ui.status(_("no changes found\n"))
1029 pullop.cgresult = 0
1029 pullop.cgresult = 0
1030 return
1030 return
1031 pullop.gettransaction()
1031 pullop.gettransaction()
1032 if pullop.heads is None and list(pullop.common) == [nullid]:
1032 if pullop.heads is None and list(pullop.common) == [nullid]:
1033 pullop.repo.ui.status(_("requesting all changes\n"))
1033 pullop.repo.ui.status(_("requesting all changes\n"))
1034 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1034 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1035 # issue1320, avoid a race if remote changed after discovery
1035 # issue1320, avoid a race if remote changed after discovery
1036 pullop.heads = pullop.rheads
1036 pullop.heads = pullop.rheads
1037
1037
1038 if pullop.remote.capable('getbundle'):
1038 if pullop.remote.capable('getbundle'):
1039 # TODO: get bundlecaps from remote
1039 # TODO: get bundlecaps from remote
1040 cg = pullop.remote.getbundle('pull', common=pullop.common,
1040 cg = pullop.remote.getbundle('pull', common=pullop.common,
1041 heads=pullop.heads or pullop.rheads)
1041 heads=pullop.heads or pullop.rheads)
1042 elif pullop.heads is None:
1042 elif pullop.heads is None:
1043 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
1043 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
1044 elif not pullop.remote.capable('changegroupsubset'):
1044 elif not pullop.remote.capable('changegroupsubset'):
1045 raise util.Abort(_("partial pull cannot be done because "
1045 raise util.Abort(_("partial pull cannot be done because "
1046 "other repository doesn't support "
1046 "other repository doesn't support "
1047 "changegroupsubset."))
1047 "changegroupsubset."))
1048 else:
1048 else:
1049 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
1049 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
1050 pullop.cgresult = changegroup.addchangegroup(pullop.repo, cg, 'pull',
1050 pullop.cgresult = changegroup.addchangegroup(pullop.repo, cg, 'pull',
1051 pullop.remote.url())
1051 pullop.remote.url())
1052
1052
1053 def _pullphase(pullop):
1053 def _pullphase(pullop):
1054 # Get remote phases data from remote
1054 # Get remote phases data from remote
1055 if 'phases' in pullop.stepsdone:
1055 if 'phases' in pullop.stepsdone:
1056 return
1056 return
1057 remotephases = pullop.remote.listkeys('phases')
1057 remotephases = pullop.remote.listkeys('phases')
1058 _pullapplyphases(pullop, remotephases)
1058 _pullapplyphases(pullop, remotephases)
1059
1059
1060 def _pullapplyphases(pullop, remotephases):
1060 def _pullapplyphases(pullop, remotephases):
1061 """apply phase movement from observed remote state"""
1061 """apply phase movement from observed remote state"""
1062 if 'phases' in pullop.stepsdone:
1062 if 'phases' in pullop.stepsdone:
1063 return
1063 return
1064 pullop.stepsdone.add('phases')
1064 pullop.stepsdone.add('phases')
1065 publishing = bool(remotephases.get('publishing', False))
1065 publishing = bool(remotephases.get('publishing', False))
1066 if remotephases and not publishing:
1066 if remotephases and not publishing:
1067 # remote is new and unpublishing
1067 # remote is new and unpublishing
1068 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1068 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1069 pullop.pulledsubset,
1069 pullop.pulledsubset,
1070 remotephases)
1070 remotephases)
1071 dheads = pullop.pulledsubset
1071 dheads = pullop.pulledsubset
1072 else:
1072 else:
1073 # Remote is old or publishing all common changesets
1073 # Remote is old or publishing all common changesets
1074 # should be seen as public
1074 # should be seen as public
1075 pheads = pullop.pulledsubset
1075 pheads = pullop.pulledsubset
1076 dheads = []
1076 dheads = []
1077 unfi = pullop.repo.unfiltered()
1077 unfi = pullop.repo.unfiltered()
1078 phase = unfi._phasecache.phase
1078 phase = unfi._phasecache.phase
1079 rev = unfi.changelog.nodemap.get
1079 rev = unfi.changelog.nodemap.get
1080 public = phases.public
1080 public = phases.public
1081 draft = phases.draft
1081 draft = phases.draft
1082
1082
1083 # exclude changesets already public locally and update the others
1083 # exclude changesets already public locally and update the others
1084 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1084 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1085 if pheads:
1085 if pheads:
1086 tr = pullop.gettransaction()
1086 tr = pullop.gettransaction()
1087 phases.advanceboundary(pullop.repo, tr, public, pheads)
1087 phases.advanceboundary(pullop.repo, tr, public, pheads)
1088
1088
1089 # exclude changesets already draft locally and update the others
1089 # exclude changesets already draft locally and update the others
1090 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1090 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1091 if dheads:
1091 if dheads:
1092 tr = pullop.gettransaction()
1092 tr = pullop.gettransaction()
1093 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1093 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1094
1094
1095 def _pullbookmarks(pullop):
1095 def _pullbookmarks(pullop):
1096 """process the remote bookmark information to update the local one"""
1096 """process the remote bookmark information to update the local one"""
1097 if 'bookmarks' in pullop.stepsdone:
1097 if 'bookmarks' in pullop.stepsdone:
1098 return
1098 return
1099 pullop.stepsdone.add('bookmarks')
1099 pullop.stepsdone.add('bookmarks')
1100 repo = pullop.repo
1100 repo = pullop.repo
1101 remotebookmarks = pullop.remotebookmarks
1101 remotebookmarks = pullop.remotebookmarks
1102 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1102 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1103 pullop.remote.url(),
1103 pullop.remote.url(),
1104 pullop.gettransaction,
1104 pullop.gettransaction,
1105 explicit=pullop.explicitbookmarks)
1105 explicit=pullop.explicitbookmarks)
1106
1106
1107 def _pullobsolete(pullop):
1107 def _pullobsolete(pullop):
1108 """utility function to pull obsolete markers from a remote
1108 """utility function to pull obsolete markers from a remote
1109
1109
1110 The `gettransaction` is function that return the pull transaction, creating
1110 The `gettransaction` is function that return the pull transaction, creating
1111 one if necessary. We return the transaction to inform the calling code that
1111 one if necessary. We return the transaction to inform the calling code that
1112 a new transaction have been created (when applicable).
1112 a new transaction have been created (when applicable).
1113
1113
1114 Exists mostly to allow overriding for experimentation purpose"""
1114 Exists mostly to allow overriding for experimentation purpose"""
1115 if 'obsmarkers' in pullop.stepsdone:
1115 if 'obsmarkers' in pullop.stepsdone:
1116 return
1116 return
1117 pullop.stepsdone.add('obsmarkers')
1117 pullop.stepsdone.add('obsmarkers')
1118 tr = None
1118 tr = None
1119 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1119 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1120 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1120 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1121 remoteobs = pullop.remote.listkeys('obsolete')
1121 remoteobs = pullop.remote.listkeys('obsolete')
1122 if 'dump0' in remoteobs:
1122 if 'dump0' in remoteobs:
1123 tr = pullop.gettransaction()
1123 tr = pullop.gettransaction()
1124 for key in sorted(remoteobs, reverse=True):
1124 for key in sorted(remoteobs, reverse=True):
1125 if key.startswith('dump'):
1125 if key.startswith('dump'):
1126 data = base85.b85decode(remoteobs[key])
1126 data = base85.b85decode(remoteobs[key])
1127 pullop.repo.obsstore.mergemarkers(tr, data)
1127 pullop.repo.obsstore.mergemarkers(tr, data)
1128 pullop.repo.invalidatevolatilesets()
1128 pullop.repo.invalidatevolatilesets()
1129 return tr
1129 return tr
1130
1130
1131 def caps20to10(repo):
1131 def caps20to10(repo):
1132 """return a set with appropriate options to use bundle20 during getbundle"""
1132 """return a set with appropriate options to use bundle20 during getbundle"""
1133 caps = set(['HG20'])
1133 caps = set(['HG20'])
1134 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1134 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1135 caps.add('bundle2=' + urllib.quote(capsblob))
1135 caps.add('bundle2=' + urllib.quote(capsblob))
1136 return caps
1136 return caps
1137
1137
1138 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1138 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1139 getbundle2partsorder = []
1139 getbundle2partsorder = []
1140
1140
1141 # Mapping between step name and function
1141 # Mapping between step name and function
1142 #
1142 #
1143 # This exists to help extensions wrap steps if necessary
1143 # This exists to help extensions wrap steps if necessary
1144 getbundle2partsmapping = {}
1144 getbundle2partsmapping = {}
1145
1145
1146 def getbundle2partsgenerator(stepname, idx=None):
1146 def getbundle2partsgenerator(stepname, idx=None):
1147 """decorator for function generating bundle2 part for getbundle
1147 """decorator for function generating bundle2 part for getbundle
1148
1148
1149 The function is added to the step -> function mapping and appended to the
1149 The function is added to the step -> function mapping and appended to the
1150 list of steps. Beware that decorated functions will be added in order
1150 list of steps. Beware that decorated functions will be added in order
1151 (this may matter).
1151 (this may matter).
1152
1152
1153 You can only use this decorator for new steps, if you want to wrap a step
1153 You can only use this decorator for new steps, if you want to wrap a step
1154 from an extension, attack the getbundle2partsmapping dictionary directly."""
1154 from an extension, attack the getbundle2partsmapping dictionary directly."""
1155 def dec(func):
1155 def dec(func):
1156 assert stepname not in getbundle2partsmapping
1156 assert stepname not in getbundle2partsmapping
1157 getbundle2partsmapping[stepname] = func
1157 getbundle2partsmapping[stepname] = func
1158 if idx is None:
1158 if idx is None:
1159 getbundle2partsorder.append(stepname)
1159 getbundle2partsorder.append(stepname)
1160 else:
1160 else:
1161 getbundle2partsorder.insert(idx, stepname)
1161 getbundle2partsorder.insert(idx, stepname)
1162 return func
1162 return func
1163 return dec
1163 return dec
1164
1164
1165 def getbundle(repo, source, heads=None, common=None, bundlecaps=None,
1165 def getbundle(repo, source, heads=None, common=None, bundlecaps=None,
1166 **kwargs):
1166 **kwargs):
1167 """return a full bundle (with potentially multiple kind of parts)
1167 """return a full bundle (with potentially multiple kind of parts)
1168
1168
1169 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
1169 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
1170 passed. For now, the bundle can contain only changegroup, but this will
1170 passed. For now, the bundle can contain only changegroup, but this will
1171 changes when more part type will be available for bundle2.
1171 changes when more part type will be available for bundle2.
1172
1172
1173 This is different from changegroup.getchangegroup that only returns an HG10
1173 This is different from changegroup.getchangegroup that only returns an HG10
1174 changegroup bundle. They may eventually get reunited in the future when we
1174 changegroup bundle. They may eventually get reunited in the future when we
1175 have a clearer idea of the API we what to query different data.
1175 have a clearer idea of the API we what to query different data.
1176
1176
1177 The implementation is at a very early stage and will get massive rework
1177 The implementation is at a very early stage and will get massive rework
1178 when the API of bundle is refined.
1178 when the API of bundle is refined.
1179 """
1179 """
1180 # bundle10 case
1180 # bundle10 case
1181 usebundle2 = False
1181 usebundle2 = False
1182 if bundlecaps is not None:
1182 if bundlecaps is not None:
1183 usebundle2 = util.any((cap.startswith('HG2') for cap in bundlecaps))
1183 usebundle2 = util.any((cap.startswith('HG2') for cap in bundlecaps))
1184 if not usebundle2:
1184 if not usebundle2:
1185 if bundlecaps and not kwargs.get('cg', True):
1185 if bundlecaps and not kwargs.get('cg', True):
1186 raise ValueError(_('request for bundle10 must include changegroup'))
1186 raise ValueError(_('request for bundle10 must include changegroup'))
1187
1187
1188 if kwargs:
1188 if kwargs:
1189 raise ValueError(_('unsupported getbundle arguments: %s')
1189 raise ValueError(_('unsupported getbundle arguments: %s')
1190 % ', '.join(sorted(kwargs.keys())))
1190 % ', '.join(sorted(kwargs.keys())))
1191 return changegroup.getchangegroup(repo, source, heads=heads,
1191 return changegroup.getchangegroup(repo, source, heads=heads,
1192 common=common, bundlecaps=bundlecaps)
1192 common=common, bundlecaps=bundlecaps)
1193
1193
1194 # bundle20 case
1194 # bundle20 case
1195 b2caps = {}
1195 b2caps = {}
1196 for bcaps in bundlecaps:
1196 for bcaps in bundlecaps:
1197 if bcaps.startswith('bundle2='):
1197 if bcaps.startswith('bundle2='):
1198 blob = urllib.unquote(bcaps[len('bundle2='):])
1198 blob = urllib.unquote(bcaps[len('bundle2='):])
1199 b2caps.update(bundle2.decodecaps(blob))
1199 b2caps.update(bundle2.decodecaps(blob))
1200 bundler = bundle2.bundle20(repo.ui, b2caps)
1200 bundler = bundle2.bundle20(repo.ui, b2caps)
1201
1201
1202 kwargs['heads'] = heads
1202 kwargs['heads'] = heads
1203 kwargs['common'] = common
1203 kwargs['common'] = common
1204
1204
1205 for name in getbundle2partsorder:
1205 for name in getbundle2partsorder:
1206 func = getbundle2partsmapping[name]
1206 func = getbundle2partsmapping[name]
1207 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1207 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1208 **kwargs)
1208 **kwargs)
1209
1209
1210 return util.chunkbuffer(bundler.getchunks())
1210 return util.chunkbuffer(bundler.getchunks())
1211
1211
1212 @getbundle2partsgenerator('changegroup')
1212 @getbundle2partsgenerator('changegroup')
1213 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1213 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1214 b2caps=None, heads=None, common=None, **kwargs):
1214 b2caps=None, heads=None, common=None, **kwargs):
1215 """add a changegroup part to the requested bundle"""
1215 """add a changegroup part to the requested bundle"""
1216 cg = None
1216 cg = None
1217 if kwargs.get('cg', True):
1217 if kwargs.get('cg', True):
1218 # build changegroup bundle here.
1218 # build changegroup bundle here.
1219 version = None
1219 version = None
1220 cgversions = b2caps.get('changegroup')
1220 cgversions = b2caps.get('changegroup')
1221 if not cgversions: # 3.1 and 3.2 ship with an empty value
1221 if not cgversions: # 3.1 and 3.2 ship with an empty value
1222 cg = changegroup.getchangegroupraw(repo, source, heads=heads,
1222 cg = changegroup.getchangegroupraw(repo, source, heads=heads,
1223 common=common,
1223 common=common,
1224 bundlecaps=bundlecaps)
1224 bundlecaps=bundlecaps)
1225 else:
1225 else:
1226 cgversions = [v for v in cgversions if v in changegroup.packermap]
1226 cgversions = [v for v in cgversions if v in changegroup.packermap]
1227 if not cgversions:
1227 if not cgversions:
1228 raise ValueError(_('no common changegroup version'))
1228 raise ValueError(_('no common changegroup version'))
1229 version = max(cgversions)
1229 version = max(cgversions)
1230 cg = changegroup.getchangegroupraw(repo, source, heads=heads,
1230 cg = changegroup.getchangegroupraw(repo, source, heads=heads,
1231 common=common,
1231 common=common,
1232 bundlecaps=bundlecaps,
1232 bundlecaps=bundlecaps,
1233 version=version)
1233 version=version)
1234
1234
1235 if cg:
1235 if cg:
1236 part = bundler.newpart('changegroup', data=cg)
1236 part = bundler.newpart('changegroup', data=cg)
1237 if version is not None:
1237 if version is not None:
1238 part.addparam('version', version)
1238 part.addparam('version', version)
1239
1239
1240 @getbundle2partsgenerator('listkeys')
1240 @getbundle2partsgenerator('listkeys')
1241 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1241 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1242 b2caps=None, **kwargs):
1242 b2caps=None, **kwargs):
1243 """add parts containing listkeys namespaces to the requested bundle"""
1243 """add parts containing listkeys namespaces to the requested bundle"""
1244 listkeys = kwargs.get('listkeys', ())
1244 listkeys = kwargs.get('listkeys', ())
1245 for namespace in listkeys:
1245 for namespace in listkeys:
1246 part = bundler.newpart('listkeys')
1246 part = bundler.newpart('listkeys')
1247 part.addparam('namespace', namespace)
1247 part.addparam('namespace', namespace)
1248 keys = repo.listkeys(namespace).items()
1248 keys = repo.listkeys(namespace).items()
1249 part.data = pushkey.encodekeys(keys)
1249 part.data = pushkey.encodekeys(keys)
1250
1250
1251 @getbundle2partsgenerator('obsmarkers')
1251 @getbundle2partsgenerator('obsmarkers')
1252 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1252 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1253 b2caps=None, heads=None, **kwargs):
1253 b2caps=None, heads=None, **kwargs):
1254 """add an obsolescence markers part to the requested bundle"""
1254 """add an obsolescence markers part to the requested bundle"""
1255 if kwargs.get('obsmarkers', False):
1255 if kwargs.get('obsmarkers', False):
1256 if heads is None:
1256 if heads is None:
1257 heads = repo.heads()
1257 heads = repo.heads()
1258 subset = [c.node() for c in repo.set('::%ln', heads)]
1258 subset = [c.node() for c in repo.set('::%ln', heads)]
1259 markers = repo.obsstore.relevantmarkers(subset)
1259 markers = repo.obsstore.relevantmarkers(subset)
1260 buildobsmarkerspart(bundler, markers)
1260 buildobsmarkerspart(bundler, markers)
1261
1261
1262 def check_heads(repo, their_heads, context):
1262 def check_heads(repo, their_heads, context):
1263 """check if the heads of a repo have been modified
1263 """check if the heads of a repo have been modified
1264
1264
1265 Used by peer for unbundling.
1265 Used by peer for unbundling.
1266 """
1266 """
1267 heads = repo.heads()
1267 heads = repo.heads()
1268 heads_hash = util.sha1(''.join(sorted(heads))).digest()
1268 heads_hash = util.sha1(''.join(sorted(heads))).digest()
1269 if not (their_heads == ['force'] or their_heads == heads or
1269 if not (their_heads == ['force'] or their_heads == heads or
1270 their_heads == ['hashed', heads_hash]):
1270 their_heads == ['hashed', heads_hash]):
1271 # someone else committed/pushed/unbundled while we
1271 # someone else committed/pushed/unbundled while we
1272 # were transferring data
1272 # were transferring data
1273 raise error.PushRaced('repository changed while %s - '
1273 raise error.PushRaced('repository changed while %s - '
1274 'please try again' % context)
1274 'please try again' % context)
1275
1275
1276 def unbundle(repo, cg, heads, source, url):
1276 def unbundle(repo, cg, heads, source, url):
1277 """Apply a bundle to a repo.
1277 """Apply a bundle to a repo.
1278
1278
1279 this function makes sure the repo is locked during the application and have
1279 this function makes sure the repo is locked during the application and have
1280 mechanism to check that no push race occurred between the creation of the
1280 mechanism to check that no push race occurred between the creation of the
1281 bundle and its application.
1281 bundle and its application.
1282
1282
1283 If the push was raced as PushRaced exception is raised."""
1283 If the push was raced as PushRaced exception is raised."""
1284 r = 0
1284 r = 0
1285 # need a transaction when processing a bundle2 stream
1285 # need a transaction when processing a bundle2 stream
1286 wlock = lock = tr = None
1286 wlock = lock = tr = None
1287 recordout = None
1287 recordout = None
1288 # quick fix for output mismatch with bundle2 in 3.4
1288 # quick fix for output mismatch with bundle2 in 3.4
1289 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture',
1289 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture',
1290 False)
1290 False)
1291 if url.startswith('remote:http:') or url.startswith('remote:https:'):
1291 if url.startswith('remote:'):
1292 captureoutput = True
1292 captureoutput = True
1293 try:
1293 try:
1294 check_heads(repo, heads, 'uploading changes')
1294 check_heads(repo, heads, 'uploading changes')
1295 # push can proceed
1295 # push can proceed
1296 if util.safehasattr(cg, 'params'):
1296 if util.safehasattr(cg, 'params'):
1297 r = None
1297 r = None
1298 try:
1298 try:
1299 wlock = repo.wlock()
1299 wlock = repo.wlock()
1300 lock = repo.lock()
1300 lock = repo.lock()
1301 tr = repo.transaction(source)
1301 tr = repo.transaction(source)
1302 tr.hookargs['source'] = source
1302 tr.hookargs['source'] = source
1303 tr.hookargs['url'] = url
1303 tr.hookargs['url'] = url
1304 tr.hookargs['bundle2'] = '1'
1304 tr.hookargs['bundle2'] = '1'
1305 op = bundle2.bundleoperation(repo, lambda: tr,
1305 op = bundle2.bundleoperation(repo, lambda: tr,
1306 captureoutput=captureoutput)
1306 captureoutput=captureoutput)
1307 try:
1307 try:
1308 r = bundle2.processbundle(repo, cg, op=op)
1308 r = bundle2.processbundle(repo, cg, op=op)
1309 finally:
1309 finally:
1310 r = op.reply
1310 r = op.reply
1311 if captureoutput and r is not None:
1311 if captureoutput and r is not None:
1312 repo.ui.pushbuffer(error=True, subproc=True)
1312 repo.ui.pushbuffer(error=True, subproc=True)
1313 def recordout(output):
1313 def recordout(output):
1314 r.newpart('output', data=output, mandatory=False)
1314 r.newpart('output', data=output, mandatory=False)
1315 tr.close()
1315 tr.close()
1316 except Exception, exc:
1316 except Exception, exc:
1317 exc.duringunbundle2 = True
1317 exc.duringunbundle2 = True
1318 if captureoutput and r is not None:
1318 if captureoutput and r is not None:
1319 parts = exc._bundle2salvagedoutput = r.salvageoutput()
1319 parts = exc._bundle2salvagedoutput = r.salvageoutput()
1320 def recordout(output):
1320 def recordout(output):
1321 part = bundle2.bundlepart('output', data=output,
1321 part = bundle2.bundlepart('output', data=output,
1322 mandatory=False)
1322 mandatory=False)
1323 parts.append(part)
1323 parts.append(part)
1324 raise
1324 raise
1325 else:
1325 else:
1326 lock = repo.lock()
1326 lock = repo.lock()
1327 r = changegroup.addchangegroup(repo, cg, source, url)
1327 r = changegroup.addchangegroup(repo, cg, source, url)
1328 finally:
1328 finally:
1329 lockmod.release(tr, lock, wlock)
1329 lockmod.release(tr, lock, wlock)
1330 if recordout is not None:
1330 if recordout is not None:
1331 recordout(repo.ui.popbuffer())
1331 recordout(repo.ui.popbuffer())
1332 return r
1332 return r
@@ -1,719 +1,719 b''
1 Test exchange of common information using bundle2
1 Test exchange of common information using bundle2
2
2
3
3
4 $ getmainid() {
4 $ getmainid() {
5 > hg -R main log --template '{node}\n' --rev "$1"
5 > hg -R main log --template '{node}\n' --rev "$1"
6 > }
6 > }
7
7
8 enable obsolescence
8 enable obsolescence
9
9
10 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
10 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
11 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
11 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
12 > hg debuglock
12 > hg debuglock
13 > EOF
13 > EOF
14
14
15 $ cat >> $HGRCPATH << EOF
15 $ cat >> $HGRCPATH << EOF
16 > [experimental]
16 > [experimental]
17 > evolution=createmarkers,exchange
17 > evolution=createmarkers,exchange
18 > bundle2-exp=True
18 > bundle2-exp=True
19 > bundle2-output-capture=True
19 > bundle2-output-capture=True
20 > [ui]
20 > [ui]
21 > ssh=python "$TESTDIR/dummyssh"
21 > ssh=python "$TESTDIR/dummyssh"
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
23 > [web]
23 > [web]
24 > push_ssl = false
24 > push_ssl = false
25 > allow_push = *
25 > allow_push = *
26 > [phases]
26 > [phases]
27 > publish=False
27 > publish=False
28 > [hooks]
28 > [hooks]
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
31 > txnclose.env = sh -c "HG_LOCAL= python \"$TESTDIR/printenv.py\" txnclose"
31 > txnclose.env = sh -c "HG_LOCAL= python \"$TESTDIR/printenv.py\" txnclose"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
33 > EOF
33 > EOF
34
34
35 The extension requires a repo (currently unused)
35 The extension requires a repo (currently unused)
36
36
37 $ hg init main
37 $ hg init main
38 $ cd main
38 $ cd main
39 $ touch a
39 $ touch a
40 $ hg add a
40 $ hg add a
41 $ hg commit -m 'a'
41 $ hg commit -m 'a'
42 pre-close-tip:3903775176ed draft
42 pre-close-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
44 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
44 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
45
45
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
47 adding changesets
47 adding changesets
48 adding manifests
48 adding manifests
49 adding file changes
49 adding file changes
50 added 8 changesets with 7 changes to 7 files (+3 heads)
50 added 8 changesets with 7 changes to 7 files (+3 heads)
51 pre-close-tip:02de42196ebe draft
51 pre-close-tip:02de42196ebe draft
52 postclose-tip:02de42196ebe draft
52 postclose-tip:02de42196ebe draft
53 txnclose hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:* HG_TXNNAME=unbundle (glob)
53 txnclose hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:* HG_TXNNAME=unbundle (glob)
54 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
54 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
56
56
57 $ cd ..
57 $ cd ..
58
58
59 Real world exchange
59 Real world exchange
60 =====================
60 =====================
61
61
62 Add more obsolescence information
62 Add more obsolescence information
63
63
64 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
64 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
65 pre-close-tip:02de42196ebe draft
65 pre-close-tip:02de42196ebe draft
66 postclose-tip:02de42196ebe draft
66 postclose-tip:02de42196ebe draft
67 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
67 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
68 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
68 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
69 pre-close-tip:02de42196ebe draft
69 pre-close-tip:02de42196ebe draft
70 postclose-tip:02de42196ebe draft
70 postclose-tip:02de42196ebe draft
71 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
71 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
72
72
73 clone --pull
73 clone --pull
74
74
75 $ hg -R main phase --public cd010b8cd998
75 $ hg -R main phase --public cd010b8cd998
76 pre-close-tip:02de42196ebe draft
76 pre-close-tip:02de42196ebe draft
77 postclose-tip:02de42196ebe draft
77 postclose-tip:02de42196ebe draft
78 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
78 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
79 $ hg clone main other --pull --rev 9520eea781bc
79 $ hg clone main other --pull --rev 9520eea781bc
80 adding changesets
80 adding changesets
81 adding manifests
81 adding manifests
82 adding file changes
82 adding file changes
83 added 2 changesets with 2 changes to 2 files
83 added 2 changesets with 2 changes to 2 files
84 1 new obsolescence markers
84 1 new obsolescence markers
85 pre-close-tip:9520eea781bc draft
85 pre-close-tip:9520eea781bc draft
86 postclose-tip:9520eea781bc draft
86 postclose-tip:9520eea781bc draft
87 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
87 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
88 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
88 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
89 updating to branch default
89 updating to branch default
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 $ hg -R other log -G
91 $ hg -R other log -G
92 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
92 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
93 |
93 |
94 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
94 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
95
95
96 $ hg -R other debugobsolete
96 $ hg -R other debugobsolete
97 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
97 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
98
98
99 pull
99 pull
100
100
101 $ hg -R main phase --public 9520eea781bc
101 $ hg -R main phase --public 9520eea781bc
102 pre-close-tip:02de42196ebe draft
102 pre-close-tip:02de42196ebe draft
103 postclose-tip:02de42196ebe draft
103 postclose-tip:02de42196ebe draft
104 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
104 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
105 $ hg -R other pull -r 24b6387c8c8c
105 $ hg -R other pull -r 24b6387c8c8c
106 pulling from $TESTTMP/main (glob)
106 pulling from $TESTTMP/main (glob)
107 searching for changes
107 searching for changes
108 adding changesets
108 adding changesets
109 adding manifests
109 adding manifests
110 adding file changes
110 adding file changes
111 added 1 changesets with 1 changes to 1 files (+1 heads)
111 added 1 changesets with 1 changes to 1 files (+1 heads)
112 1 new obsolescence markers
112 1 new obsolescence markers
113 pre-close-tip:24b6387c8c8c draft
113 pre-close-tip:24b6387c8c8c draft
114 postclose-tip:24b6387c8c8c draft
114 postclose-tip:24b6387c8c8c draft
115 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
115 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
116 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
116 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
117 (run 'hg heads' to see heads, 'hg merge' to merge)
117 (run 'hg heads' to see heads, 'hg merge' to merge)
118 $ hg -R other log -G
118 $ hg -R other log -G
119 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
119 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
120 |
120 |
121 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
121 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
122 |/
122 |/
123 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
123 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
124
124
125 $ hg -R other debugobsolete
125 $ hg -R other debugobsolete
126 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
126 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
127 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
127 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
128
128
129 pull empty (with phase movement)
129 pull empty (with phase movement)
130
130
131 $ hg -R main phase --public 24b6387c8c8c
131 $ hg -R main phase --public 24b6387c8c8c
132 pre-close-tip:02de42196ebe draft
132 pre-close-tip:02de42196ebe draft
133 postclose-tip:02de42196ebe draft
133 postclose-tip:02de42196ebe draft
134 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
134 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
135 $ hg -R other pull -r 24b6387c8c8c
135 $ hg -R other pull -r 24b6387c8c8c
136 pulling from $TESTTMP/main (glob)
136 pulling from $TESTTMP/main (glob)
137 no changes found
137 no changes found
138 pre-close-tip:24b6387c8c8c public
138 pre-close-tip:24b6387c8c8c public
139 postclose-tip:24b6387c8c8c public
139 postclose-tip:24b6387c8c8c public
140 txnclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
140 txnclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
141 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
141 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
142 $ hg -R other log -G
142 $ hg -R other log -G
143 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
143 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
144 |
144 |
145 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
145 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
146 |/
146 |/
147 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
147 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
148
148
149 $ hg -R other debugobsolete
149 $ hg -R other debugobsolete
150 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
150 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
151 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
151 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
152
152
153 pull empty
153 pull empty
154
154
155 $ hg -R other pull -r 24b6387c8c8c
155 $ hg -R other pull -r 24b6387c8c8c
156 pulling from $TESTTMP/main (glob)
156 pulling from $TESTTMP/main (glob)
157 no changes found
157 no changes found
158 pre-close-tip:24b6387c8c8c public
158 pre-close-tip:24b6387c8c8c public
159 postclose-tip:24b6387c8c8c public
159 postclose-tip:24b6387c8c8c public
160 txnclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
160 txnclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
161 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
161 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
162 $ hg -R other log -G
162 $ hg -R other log -G
163 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
163 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
164 |
164 |
165 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
165 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
166 |/
166 |/
167 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
167 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
168
168
169 $ hg -R other debugobsolete
169 $ hg -R other debugobsolete
170 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
170 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
171 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
171 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
172
172
173 add extra data to test their exchange during push
173 add extra data to test their exchange during push
174
174
175 $ hg -R main bookmark --rev eea13746799a book_eea1
175 $ hg -R main bookmark --rev eea13746799a book_eea1
176 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
176 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
177 pre-close-tip:02de42196ebe draft
177 pre-close-tip:02de42196ebe draft
178 postclose-tip:02de42196ebe draft
178 postclose-tip:02de42196ebe draft
179 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
179 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
180 $ hg -R main bookmark --rev 02de42196ebe book_02de
180 $ hg -R main bookmark --rev 02de42196ebe book_02de
181 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
181 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
182 pre-close-tip:02de42196ebe draft book_02de
182 pre-close-tip:02de42196ebe draft book_02de
183 postclose-tip:02de42196ebe draft book_02de
183 postclose-tip:02de42196ebe draft book_02de
184 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
184 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
185 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
185 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
186 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
186 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
187 pre-close-tip:02de42196ebe draft book_02de
187 pre-close-tip:02de42196ebe draft book_02de
188 postclose-tip:02de42196ebe draft book_02de
188 postclose-tip:02de42196ebe draft book_02de
189 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
189 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
190 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
190 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
191 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
191 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
192 pre-close-tip:02de42196ebe draft book_02de
192 pre-close-tip:02de42196ebe draft book_02de
193 postclose-tip:02de42196ebe draft book_02de
193 postclose-tip:02de42196ebe draft book_02de
194 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
194 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
195 $ hg -R main bookmark --rev 32af7686d403 book_32af
195 $ hg -R main bookmark --rev 32af7686d403 book_32af
196 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
196 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
197 pre-close-tip:02de42196ebe draft book_02de
197 pre-close-tip:02de42196ebe draft book_02de
198 postclose-tip:02de42196ebe draft book_02de
198 postclose-tip:02de42196ebe draft book_02de
199 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
199 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
200
200
201 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
201 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
202 $ hg -R other bookmark --rev cd010b8cd998 book_02de
202 $ hg -R other bookmark --rev cd010b8cd998 book_02de
203 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
203 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
204 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
204 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
205 $ hg -R other bookmark --rev cd010b8cd998 book_32af
205 $ hg -R other bookmark --rev cd010b8cd998 book_32af
206
206
207 $ hg -R main phase --public eea13746799a
207 $ hg -R main phase --public eea13746799a
208 pre-close-tip:02de42196ebe draft book_02de
208 pre-close-tip:02de42196ebe draft book_02de
209 postclose-tip:02de42196ebe draft book_02de
209 postclose-tip:02de42196ebe draft book_02de
210 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
210 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
211
211
212 push
212 push
213 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
213 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
214 pushing to other
214 pushing to other
215 searching for changes
215 searching for changes
216 remote: adding changesets
216 remote: adding changesets
217 remote: adding manifests
217 remote: adding manifests
218 remote: adding file changes
218 remote: adding file changes
219 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
219 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
220 remote: 1 new obsolescence markers
220 remote: 1 new obsolescence markers
221 remote: pre-close-tip:eea13746799a public book_eea1
221 remote: pre-close-tip:eea13746799a public book_eea1
222 remote: pushkey: lock state after "phases"
222 remote: pushkey: lock state after "phases"
223 remote: lock: free
223 remote: lock: free
224 remote: wlock: free
224 remote: wlock: free
225 remote: pushkey: lock state after "bookmarks"
225 remote: pushkey: lock state after "bookmarks"
226 remote: lock: free
226 remote: lock: free
227 remote: wlock: free
227 remote: wlock: free
228 remote: postclose-tip:eea13746799a public book_eea1
228 remote: postclose-tip:eea13746799a public book_eea1
229 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
229 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
230 updating bookmark book_eea1
230 updating bookmark book_eea1
231 pre-close-tip:02de42196ebe draft book_02de
231 pre-close-tip:02de42196ebe draft book_02de
232 postclose-tip:02de42196ebe draft book_02de
232 postclose-tip:02de42196ebe draft book_02de
233 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
233 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
234 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
234 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
235 $ hg -R other log -G
235 $ hg -R other log -G
236 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
236 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
237 |\
237 |\
238 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
238 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
239 | |
239 | |
240 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
240 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
241 |/
241 |/
242 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
242 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
243
243
244 $ hg -R other debugobsolete
244 $ hg -R other debugobsolete
245 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
245 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
246 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
246 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
247 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
247 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
248
248
249 pull over ssh
249 pull over ssh
250
250
251 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
251 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
252 pulling from ssh://user@dummy/main
252 pulling from ssh://user@dummy/main
253 searching for changes
253 searching for changes
254 adding changesets
254 adding changesets
255 adding manifests
255 adding manifests
256 adding file changes
256 adding file changes
257 added 1 changesets with 1 changes to 1 files (+1 heads)
257 added 1 changesets with 1 changes to 1 files (+1 heads)
258 1 new obsolescence markers
258 1 new obsolescence markers
259 updating bookmark book_02de
259 updating bookmark book_02de
260 pre-close-tip:02de42196ebe draft book_02de
260 pre-close-tip:02de42196ebe draft book_02de
261 postclose-tip:02de42196ebe draft book_02de
261 postclose-tip:02de42196ebe draft book_02de
262 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
262 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
263 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
263 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
264 (run 'hg heads' to see heads, 'hg merge' to merge)
264 (run 'hg heads' to see heads, 'hg merge' to merge)
265 $ hg -R other debugobsolete
265 $ hg -R other debugobsolete
266 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
266 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
267 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
267 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
268 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
268 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
269 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
269 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
270
270
271 pull over http
271 pull over http
272
272
273 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
273 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
274 $ cat main.pid >> $DAEMON_PIDS
274 $ cat main.pid >> $DAEMON_PIDS
275
275
276 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
276 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
277 pulling from http://localhost:$HGPORT/
277 pulling from http://localhost:$HGPORT/
278 searching for changes
278 searching for changes
279 adding changesets
279 adding changesets
280 adding manifests
280 adding manifests
281 adding file changes
281 adding file changes
282 added 1 changesets with 1 changes to 1 files (+1 heads)
282 added 1 changesets with 1 changes to 1 files (+1 heads)
283 1 new obsolescence markers
283 1 new obsolescence markers
284 updating bookmark book_42cc
284 updating bookmark book_42cc
285 pre-close-tip:42ccdea3bb16 draft book_42cc
285 pre-close-tip:42ccdea3bb16 draft book_42cc
286 postclose-tip:42ccdea3bb16 draft book_42cc
286 postclose-tip:42ccdea3bb16 draft book_42cc
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
288 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
288 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
289 (run 'hg heads .' to see heads, 'hg merge' to merge)
289 (run 'hg heads .' to see heads, 'hg merge' to merge)
290 $ cat main-error.log
290 $ cat main-error.log
291 $ hg -R other debugobsolete
291 $ hg -R other debugobsolete
292 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
292 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
293 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
293 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
294 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
294 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
295 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
295 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
296 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
296 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
297
297
298 push over ssh
298 push over ssh
299
299
300 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
300 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
301 pushing to ssh://user@dummy/other
301 pushing to ssh://user@dummy/other
302 searching for changes
302 searching for changes
303 remote: adding changesets
303 remote: adding changesets
304 remote: adding manifests
304 remote: adding manifests
305 remote: adding file changes
305 remote: adding file changes
306 remote: added 1 changesets with 1 changes to 1 files
306 remote: added 1 changesets with 1 changes to 1 files
307 remote: 1 new obsolescence markers
307 remote: 1 new obsolescence markers
308 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
308 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
309 remote: pushkey: lock state after "bookmarks"
309 remote: pushkey: lock state after "bookmarks"
310 remote: lock: free
310 remote: lock: free
311 remote: wlock: free
311 remote: wlock: free
312 remote: postclose-tip:5fddd98957c8 draft book_5fdd
312 remote: postclose-tip:5fddd98957c8 draft book_5fdd
313 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:ssh:127.0.0.1 (glob)
313 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:ssh:127.0.0.1 (glob)
314 updating bookmark book_5fdd
314 updating bookmark book_5fdd
315 pre-close-tip:02de42196ebe draft book_02de
315 pre-close-tip:02de42196ebe draft book_02de
316 postclose-tip:02de42196ebe draft book_02de
316 postclose-tip:02de42196ebe draft book_02de
317 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
317 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
318 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
318 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
319 $ hg -R other log -G
319 $ hg -R other log -G
320 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
320 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
321 |
321 |
322 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
322 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
323 |
323 |
324 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
324 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
325 | |
325 | |
326 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
326 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
327 | |/|
327 | |/|
328 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
328 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
329 |/ /
329 |/ /
330 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
330 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
331 |/
331 |/
332 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
332 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
333
333
334 $ hg -R other debugobsolete
334 $ hg -R other debugobsolete
335 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
335 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
336 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
336 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
337 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
337 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
338 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
338 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
339 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
339 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
340 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
340 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
341
341
342 push over http
342 push over http
343
343
344 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
344 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
345 $ cat other.pid >> $DAEMON_PIDS
345 $ cat other.pid >> $DAEMON_PIDS
346
346
347 $ hg -R main phase --public 32af7686d403
347 $ hg -R main phase --public 32af7686d403
348 pre-close-tip:02de42196ebe draft book_02de
348 pre-close-tip:02de42196ebe draft book_02de
349 postclose-tip:02de42196ebe draft book_02de
349 postclose-tip:02de42196ebe draft book_02de
350 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
350 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
351 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
351 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
352 pushing to http://localhost:$HGPORT2/
352 pushing to http://localhost:$HGPORT2/
353 searching for changes
353 searching for changes
354 remote: adding changesets
354 remote: adding changesets
355 remote: adding manifests
355 remote: adding manifests
356 remote: adding file changes
356 remote: adding file changes
357 remote: added 1 changesets with 1 changes to 1 files
357 remote: added 1 changesets with 1 changes to 1 files
358 remote: 1 new obsolescence markers
358 remote: 1 new obsolescence markers
359 remote: pre-close-tip:32af7686d403 public book_32af
359 remote: pre-close-tip:32af7686d403 public book_32af
360 remote: pushkey: lock state after "phases"
360 remote: pushkey: lock state after "phases"
361 remote: lock: free
361 remote: lock: free
362 remote: wlock: free
362 remote: wlock: free
363 remote: pushkey: lock state after "bookmarks"
363 remote: pushkey: lock state after "bookmarks"
364 remote: lock: free
364 remote: lock: free
365 remote: wlock: free
365 remote: wlock: free
366 remote: postclose-tip:32af7686d403 public book_32af
366 remote: postclose-tip:32af7686d403 public book_32af
367 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:http:127.0.0.1: (glob)
367 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:http:127.0.0.1: (glob)
368 updating bookmark book_32af
368 updating bookmark book_32af
369 pre-close-tip:02de42196ebe draft book_02de
369 pre-close-tip:02de42196ebe draft book_02de
370 postclose-tip:02de42196ebe draft book_02de
370 postclose-tip:02de42196ebe draft book_02de
371 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
371 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
372 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
372 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
373 $ cat other-error.log
373 $ cat other-error.log
374
374
375 Check final content.
375 Check final content.
376
376
377 $ hg -R other log -G
377 $ hg -R other log -G
378 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
378 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
379 |
379 |
380 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
380 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
381 |
381 |
382 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
382 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
383 |
383 |
384 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
384 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
385 | |
385 | |
386 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
386 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
387 | |/|
387 | |/|
388 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
388 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
389 |/ /
389 |/ /
390 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
390 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
391 |/
391 |/
392 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
392 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
393
393
394 $ hg -R other debugobsolete
394 $ hg -R other debugobsolete
395 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
395 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
396 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
396 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
397 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
397 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
398 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
398 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
399 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
399 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
400 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
400 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
401 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
401 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
402
402
403 (check that no 'pending' files remain)
403 (check that no 'pending' files remain)
404
404
405 $ ls -1 other/.hg/bookmarks*
405 $ ls -1 other/.hg/bookmarks*
406 other/.hg/bookmarks
406 other/.hg/bookmarks
407 $ ls -1 other/.hg/store/phaseroots*
407 $ ls -1 other/.hg/store/phaseroots*
408 other/.hg/store/phaseroots
408 other/.hg/store/phaseroots
409 $ ls -1 other/.hg/store/00changelog.i*
409 $ ls -1 other/.hg/store/00changelog.i*
410 other/.hg/store/00changelog.i
410 other/.hg/store/00changelog.i
411
411
412 Error Handling
412 Error Handling
413 ==============
413 ==============
414
414
415 Check that errors are properly returned to the client during push.
415 Check that errors are properly returned to the client during push.
416
416
417 Setting up
417 Setting up
418
418
419 $ cat > failpush.py << EOF
419 $ cat > failpush.py << EOF
420 > """A small extension that makes push fails when using bundle2
420 > """A small extension that makes push fails when using bundle2
421 >
421 >
422 > used to test error handling in bundle2
422 > used to test error handling in bundle2
423 > """
423 > """
424 >
424 >
425 > from mercurial import util
425 > from mercurial import util
426 > from mercurial import bundle2
426 > from mercurial import bundle2
427 > from mercurial import exchange
427 > from mercurial import exchange
428 > from mercurial import extensions
428 > from mercurial import extensions
429 >
429 >
430 > def _pushbundle2failpart(pushop, bundler):
430 > def _pushbundle2failpart(pushop, bundler):
431 > reason = pushop.ui.config('failpush', 'reason', None)
431 > reason = pushop.ui.config('failpush', 'reason', None)
432 > part = None
432 > part = None
433 > if reason == 'abort':
433 > if reason == 'abort':
434 > bundler.newpart('test:abort')
434 > bundler.newpart('test:abort')
435 > if reason == 'unknown':
435 > if reason == 'unknown':
436 > bundler.newpart('test:unknown')
436 > bundler.newpart('test:unknown')
437 > if reason == 'race':
437 > if reason == 'race':
438 > # 20 Bytes of crap
438 > # 20 Bytes of crap
439 > bundler.newpart('check:heads', data='01234567890123456789')
439 > bundler.newpart('check:heads', data='01234567890123456789')
440 >
440 >
441 > @bundle2.parthandler("test:abort")
441 > @bundle2.parthandler("test:abort")
442 > def handleabort(op, part):
442 > def handleabort(op, part):
443 > raise util.Abort('Abandon ship!', hint="don't panic")
443 > raise util.Abort('Abandon ship!', hint="don't panic")
444 >
444 >
445 > def uisetup(ui):
445 > def uisetup(ui):
446 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
446 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
447 > exchange.b2partsgenorder.insert(0, 'failpart')
447 > exchange.b2partsgenorder.insert(0, 'failpart')
448 >
448 >
449 > EOF
449 > EOF
450
450
451 $ cd main
451 $ cd main
452 $ hg up tip
452 $ hg up tip
453 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
453 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
454 $ echo 'I' > I
454 $ echo 'I' > I
455 $ hg add I
455 $ hg add I
456 $ hg ci -m 'I'
456 $ hg ci -m 'I'
457 pre-close-tip:e7ec4e813ba6 draft
457 pre-close-tip:e7ec4e813ba6 draft
458 postclose-tip:e7ec4e813ba6 draft
458 postclose-tip:e7ec4e813ba6 draft
459 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
459 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
460 $ hg id
460 $ hg id
461 e7ec4e813ba6 tip
461 e7ec4e813ba6 tip
462 $ cd ..
462 $ cd ..
463
463
464 $ cat << EOF >> $HGRCPATH
464 $ cat << EOF >> $HGRCPATH
465 > [extensions]
465 > [extensions]
466 > failpush=$TESTTMP/failpush.py
466 > failpush=$TESTTMP/failpush.py
467 > EOF
467 > EOF
468
468
469 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
469 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
470 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
470 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
471 $ cat other.pid >> $DAEMON_PIDS
471 $ cat other.pid >> $DAEMON_PIDS
472
472
473 Doing the actual push: Abort error
473 Doing the actual push: Abort error
474
474
475 $ cat << EOF >> $HGRCPATH
475 $ cat << EOF >> $HGRCPATH
476 > [failpush]
476 > [failpush]
477 > reason = abort
477 > reason = abort
478 > EOF
478 > EOF
479
479
480 $ hg -R main push other -r e7ec4e813ba6
480 $ hg -R main push other -r e7ec4e813ba6
481 pushing to other
481 pushing to other
482 searching for changes
482 searching for changes
483 abort: Abandon ship!
483 abort: Abandon ship!
484 (don't panic)
484 (don't panic)
485 [255]
485 [255]
486
486
487 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
487 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
488 pushing to ssh://user@dummy/other
488 pushing to ssh://user@dummy/other
489 searching for changes
489 searching for changes
490 abort: Abandon ship!
490 abort: Abandon ship!
491 (don't panic)
491 (don't panic)
492 [255]
492 [255]
493
493
494 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
494 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
495 pushing to http://localhost:$HGPORT2/
495 pushing to http://localhost:$HGPORT2/
496 searching for changes
496 searching for changes
497 abort: Abandon ship!
497 abort: Abandon ship!
498 (don't panic)
498 (don't panic)
499 [255]
499 [255]
500
500
501
501
502 Doing the actual push: unknown mandatory parts
502 Doing the actual push: unknown mandatory parts
503
503
504 $ cat << EOF >> $HGRCPATH
504 $ cat << EOF >> $HGRCPATH
505 > [failpush]
505 > [failpush]
506 > reason = unknown
506 > reason = unknown
507 > EOF
507 > EOF
508
508
509 $ hg -R main push other -r e7ec4e813ba6
509 $ hg -R main push other -r e7ec4e813ba6
510 pushing to other
510 pushing to other
511 searching for changes
511 searching for changes
512 abort: missing support for test:unknown
512 abort: missing support for test:unknown
513 [255]
513 [255]
514
514
515 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
515 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
516 pushing to ssh://user@dummy/other
516 pushing to ssh://user@dummy/other
517 searching for changes
517 searching for changes
518 abort: missing support for test:unknown
518 abort: missing support for test:unknown
519 [255]
519 [255]
520
520
521 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
521 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
522 pushing to http://localhost:$HGPORT2/
522 pushing to http://localhost:$HGPORT2/
523 searching for changes
523 searching for changes
524 abort: missing support for test:unknown
524 abort: missing support for test:unknown
525 [255]
525 [255]
526
526
527 Doing the actual push: race
527 Doing the actual push: race
528
528
529 $ cat << EOF >> $HGRCPATH
529 $ cat << EOF >> $HGRCPATH
530 > [failpush]
530 > [failpush]
531 > reason = race
531 > reason = race
532 > EOF
532 > EOF
533
533
534 $ hg -R main push other -r e7ec4e813ba6
534 $ hg -R main push other -r e7ec4e813ba6
535 pushing to other
535 pushing to other
536 searching for changes
536 searching for changes
537 abort: push failed:
537 abort: push failed:
538 'repository changed while pushing - please try again'
538 'repository changed while pushing - please try again'
539 [255]
539 [255]
540
540
541 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
541 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
542 pushing to ssh://user@dummy/other
542 pushing to ssh://user@dummy/other
543 searching for changes
543 searching for changes
544 abort: push failed:
544 abort: push failed:
545 'repository changed while pushing - please try again'
545 'repository changed while pushing - please try again'
546 [255]
546 [255]
547
547
548 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
548 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
549 pushing to http://localhost:$HGPORT2/
549 pushing to http://localhost:$HGPORT2/
550 searching for changes
550 searching for changes
551 abort: push failed:
551 abort: push failed:
552 'repository changed while pushing - please try again'
552 'repository changed while pushing - please try again'
553 [255]
553 [255]
554
554
555 Doing the actual push: hook abort
555 Doing the actual push: hook abort
556
556
557 $ cat << EOF >> $HGRCPATH
557 $ cat << EOF >> $HGRCPATH
558 > [failpush]
558 > [failpush]
559 > reason =
559 > reason =
560 > [hooks]
560 > [hooks]
561 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
561 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
562 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
562 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
563 > EOF
563 > EOF
564
564
565 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
565 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
566 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
566 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
567 $ cat other.pid >> $DAEMON_PIDS
567 $ cat other.pid >> $DAEMON_PIDS
568
568
569 $ hg -R main push other -r e7ec4e813ba6
569 $ hg -R main push other -r e7ec4e813ba6
570 pushing to other
570 pushing to other
571 searching for changes
571 searching for changes
572 remote: adding changesets
572 remote: adding changesets
573 remote: adding manifests
573 remote: adding manifests
574 remote: adding file changes
574 remote: adding file changes
575 remote: added 1 changesets with 1 changes to 1 files
575 remote: added 1 changesets with 1 changes to 1 files
576 remote: pre-close-tip:e7ec4e813ba6 draft
576 remote: pre-close-tip:e7ec4e813ba6 draft
577 remote: You shall not pass!
577 remote: You shall not pass!
578 remote: transaction abort!
578 remote: transaction abort!
579 remote: Cleaning up the mess...
579 remote: Cleaning up the mess...
580 remote: rollback completed
580 remote: rollback completed
581 abort: pretxnclose.failpush hook exited with status 1
581 abort: pretxnclose.failpush hook exited with status 1
582 [255]
582 [255]
583
583
584 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
584 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
585 pushing to ssh://user@dummy/other
585 pushing to ssh://user@dummy/other
586 searching for changes
586 searching for changes
587 remote: adding changesets
587 remote: adding changesets
588 remote: adding manifests
588 remote: adding manifests
589 remote: adding file changes
589 remote: adding file changes
590 remote: added 1 changesets with 1 changes to 1 files
590 remote: added 1 changesets with 1 changes to 1 files
591 remote: pre-close-tip:e7ec4e813ba6 draft
591 remote: pre-close-tip:e7ec4e813ba6 draft
592 remote: You shall not pass!
592 remote: You shall not pass!
593 remote: transaction abort!
593 remote: transaction abort!
594 remote: Cleaning up the mess...
594 remote: Cleaning up the mess...
595 remote: rollback completed
595 remote: rollback completed
596 abort: pretxnclose.failpush hook exited with status 1
596 abort: pretxnclose.failpush hook exited with status 1
597 [255]
597 [255]
598
598
599 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
599 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
600 pushing to http://localhost:$HGPORT2/
600 pushing to http://localhost:$HGPORT2/
601 searching for changes
601 searching for changes
602 remote: adding changesets
602 remote: adding changesets
603 remote: adding manifests
603 remote: adding manifests
604 remote: adding file changes
604 remote: adding file changes
605 remote: added 1 changesets with 1 changes to 1 files
605 remote: added 1 changesets with 1 changes to 1 files
606 remote: pre-close-tip:e7ec4e813ba6 draft
606 remote: pre-close-tip:e7ec4e813ba6 draft
607 remote: You shall not pass!
607 remote: You shall not pass!
608 remote: transaction abort!
608 remote: transaction abort!
609 remote: Cleaning up the mess...
609 remote: Cleaning up the mess...
610 remote: rollback completed
610 remote: rollback completed
611 abort: pretxnclose.failpush hook exited with status 1
611 abort: pretxnclose.failpush hook exited with status 1
612 [255]
612 [255]
613
613
614 (check that no 'pending' files remain)
614 (check that no 'pending' files remain)
615
615
616 $ ls -1 other/.hg/bookmarks*
616 $ ls -1 other/.hg/bookmarks*
617 other/.hg/bookmarks
617 other/.hg/bookmarks
618 $ ls -1 other/.hg/store/phaseroots*
618 $ ls -1 other/.hg/store/phaseroots*
619 other/.hg/store/phaseroots
619 other/.hg/store/phaseroots
620 $ ls -1 other/.hg/store/00changelog.i*
620 $ ls -1 other/.hg/store/00changelog.i*
621 other/.hg/store/00changelog.i
621 other/.hg/store/00changelog.i
622
622
623 Check error from hook during the unbundling process itself
623 Check error from hook during the unbundling process itself
624
624
625 $ cat << EOF >> $HGRCPATH
625 $ cat << EOF >> $HGRCPATH
626 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
626 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
627 > EOF
627 > EOF
628 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
628 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
629 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
629 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
630 $ cat other.pid >> $DAEMON_PIDS
630 $ cat other.pid >> $DAEMON_PIDS
631
631
632 $ hg -R main push other -r e7ec4e813ba6
632 $ hg -R main push other -r e7ec4e813ba6
633 pushing to other
633 pushing to other
634 searching for changes
634 searching for changes
635 remote: adding changesets
635 remote: adding changesets
636 remote: adding manifests
636 remote: adding manifests
637 remote: adding file changes
637 remote: adding file changes
638 remote: added 1 changesets with 1 changes to 1 files
638 remote: added 1 changesets with 1 changes to 1 files
639 remote: Fail early!
639 remote: Fail early!
640 remote: transaction abort!
640 remote: transaction abort!
641 remote: Cleaning up the mess...
641 remote: Cleaning up the mess...
642 remote: rollback completed
642 remote: rollback completed
643 abort: pretxnchangegroup hook exited with status 1
643 abort: pretxnchangegroup hook exited with status 1
644 [255]
644 [255]
645 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
645 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
646 pushing to ssh://user@dummy/other
646 pushing to ssh://user@dummy/other
647 searching for changes
647 searching for changes
648 remote: adding changesets
648 remote: adding changesets
649 remote: adding manifests
649 remote: adding manifests
650 remote: adding file changes
650 remote: adding file changes
651 remote: added 1 changesets with 1 changes to 1 files
651 remote: added 1 changesets with 1 changes to 1 files
652 remote: Fail early!
652 remote: Fail early!
653 remote: transaction abort!
653 remote: transaction abort!
654 remote: Cleaning up the mess...
654 remote: Cleaning up the mess...
655 remote: rollback completed
655 remote: rollback completed
656 abort: pretxnchangegroup hook exited with status 1
656 abort: pretxnchangegroup hook exited with status 1
657 [255]
657 [255]
658 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
658 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
659 pushing to http://localhost:$HGPORT2/
659 pushing to http://localhost:$HGPORT2/
660 searching for changes
660 searching for changes
661 remote: adding changesets
661 remote: adding changesets
662 remote: adding manifests
662 remote: adding manifests
663 remote: adding file changes
663 remote: adding file changes
664 remote: added 1 changesets with 1 changes to 1 files
664 remote: added 1 changesets with 1 changes to 1 files
665 remote: Fail early!
665 remote: Fail early!
666 remote: transaction abort!
666 remote: transaction abort!
667 remote: Cleaning up the mess...
667 remote: Cleaning up the mess...
668 remote: rollback completed
668 remote: rollback completed
669 abort: pretxnchangegroup hook exited with status 1
669 abort: pretxnchangegroup hook exited with status 1
670 [255]
670 [255]
671
671
672 Check output capture control.
672 Check output capture control.
673
673
674 (should be still forced for http, disabled for local and ssh)
674 (should be still forced for http, disabled for local and ssh)
675
675
676 $ cat >> $HGRCPATH << EOF
676 $ cat >> $HGRCPATH << EOF
677 > [experimental]
677 > [experimental]
678 > bundle2-output-capture=False
678 > bundle2-output-capture=False
679 > EOF
679 > EOF
680
680
681 $ hg -R main push other -r e7ec4e813ba6
681 $ hg -R main push other -r e7ec4e813ba6
682 pushing to other
682 pushing to other
683 searching for changes
683 searching for changes
684 adding changesets
684 adding changesets
685 adding manifests
685 adding manifests
686 adding file changes
686 adding file changes
687 added 1 changesets with 1 changes to 1 files
687 added 1 changesets with 1 changes to 1 files
688 Fail early!
688 Fail early!
689 transaction abort!
689 transaction abort!
690 Cleaning up the mess...
690 Cleaning up the mess...
691 rollback completed
691 rollback completed
692 abort: pretxnchangegroup hook exited with status 1
692 abort: pretxnchangegroup hook exited with status 1
693 [255]
693 [255]
694 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
694 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
695 pushing to ssh://user@dummy/other
695 pushing to ssh://user@dummy/other
696 searching for changes
696 searching for changes
697 abort: pretxnchangegroup hook exited with status 1
698 remote: adding changesets
697 remote: adding changesets
699 remote: adding manifests
698 remote: adding manifests
700 remote: adding file changes
699 remote: adding file changes
701 remote: added 1 changesets with 1 changes to 1 files
700 remote: added 1 changesets with 1 changes to 1 files
702 remote: Fail early!
701 remote: Fail early!
703 remote: transaction abort!
702 remote: transaction abort!
704 remote: Cleaning up the mess...
703 remote: Cleaning up the mess...
705 remote: rollback completed
704 remote: rollback completed
705 abort: pretxnchangegroup hook exited with status 1
706 [255]
706 [255]
707 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
707 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
708 pushing to http://localhost:$HGPORT2/
708 pushing to http://localhost:$HGPORT2/
709 searching for changes
709 searching for changes
710 remote: adding changesets
710 remote: adding changesets
711 remote: adding manifests
711 remote: adding manifests
712 remote: adding file changes
712 remote: adding file changes
713 remote: added 1 changesets with 1 changes to 1 files
713 remote: added 1 changesets with 1 changes to 1 files
714 remote: Fail early!
714 remote: Fail early!
715 remote: transaction abort!
715 remote: transaction abort!
716 remote: Cleaning up the mess...
716 remote: Cleaning up the mess...
717 remote: rollback completed
717 remote: rollback completed
718 abort: pretxnchangegroup hook exited with status 1
718 abort: pretxnchangegroup hook exited with status 1
719 [255]
719 [255]
General Comments 0
You need to be logged in to leave comments. Login now