##// END OF EJS Templates
push: gather all bookmark decisions together...
Pierre-Yves David -
r22651:b901645a default
parent child Browse files
Show More
@@ -1,1170 +1,1195
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
13
14 def readbundle(ui, fh, fname, vfs=None):
14 def readbundle(ui, fh, fname, vfs=None):
15 header = changegroup.readexactly(fh, 4)
15 header = changegroup.readexactly(fh, 4)
16
16
17 alg = None
17 alg = None
18 if not fname:
18 if not fname:
19 fname = "stream"
19 fname = "stream"
20 if not header.startswith('HG') and header.startswith('\0'):
20 if not header.startswith('HG') and header.startswith('\0'):
21 fh = changegroup.headerlessfixup(fh, header)
21 fh = changegroup.headerlessfixup(fh, header)
22 header = "HG10"
22 header = "HG10"
23 alg = 'UN'
23 alg = 'UN'
24 elif vfs:
24 elif vfs:
25 fname = vfs.join(fname)
25 fname = vfs.join(fname)
26
26
27 magic, version = header[0:2], header[2:4]
27 magic, version = header[0:2], header[2:4]
28
28
29 if magic != 'HG':
29 if magic != 'HG':
30 raise util.Abort(_('%s: not a Mercurial bundle') % fname)
30 raise util.Abort(_('%s: not a Mercurial bundle') % fname)
31 if version == '10':
31 if version == '10':
32 if alg is None:
32 if alg is None:
33 alg = changegroup.readexactly(fh, 2)
33 alg = changegroup.readexactly(fh, 2)
34 return changegroup.cg1unpacker(fh, alg)
34 return changegroup.cg1unpacker(fh, alg)
35 elif version == '2X':
35 elif version == '2X':
36 return bundle2.unbundle20(ui, fh, header=magic + version)
36 return bundle2.unbundle20(ui, fh, header=magic + version)
37 else:
37 else:
38 raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
38 raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
39
39
40 def buildobsmarkerspart(bundler, markers):
40 def buildobsmarkerspart(bundler, markers):
41 """add an obsmarker part to the bundler with <markers>
41 """add an obsmarker part to the bundler with <markers>
42
42
43 No part is created if markers is empty.
43 No part is created if markers is empty.
44 Raises ValueError if the bundler doesn't support any known obsmarker format.
44 Raises ValueError if the bundler doesn't support any known obsmarker format.
45 """
45 """
46 if markers:
46 if markers:
47 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
47 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
48 version = obsolete.commonversion(remoteversions)
48 version = obsolete.commonversion(remoteversions)
49 if version is None:
49 if version is None:
50 raise ValueError('bundler do not support common obsmarker format')
50 raise ValueError('bundler do not support common obsmarker format')
51 stream = obsolete.encodemarkers(markers, True, version=version)
51 stream = obsolete.encodemarkers(markers, True, version=version)
52 return bundler.newpart('B2X:OBSMARKERS', data=stream)
52 return bundler.newpart('B2X:OBSMARKERS', data=stream)
53 return None
53 return None
54
54
55 class pushoperation(object):
55 class pushoperation(object):
56 """A object that represent a single push operation
56 """A object that represent a single push operation
57
57
58 It purpose is to carry push related state and very common operation.
58 It purpose is to carry push related state and very common operation.
59
59
60 A new should be created at the beginning of each push and discarded
60 A new should be created at the beginning of each push and discarded
61 afterward.
61 afterward.
62 """
62 """
63
63
64 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
64 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
65 bookmarks=()):
65 bookmarks=()):
66 # repo we push from
66 # repo we push from
67 self.repo = repo
67 self.repo = repo
68 self.ui = repo.ui
68 self.ui = repo.ui
69 # repo we push to
69 # repo we push to
70 self.remote = remote
70 self.remote = remote
71 # force option provided
71 # force option provided
72 self.force = force
72 self.force = force
73 # revs to be pushed (None is "all")
73 # revs to be pushed (None is "all")
74 self.revs = revs
74 self.revs = revs
75 # bookmark explicitly pushed
75 # bookmark explicitly pushed
76 self.bookmarks = bookmarks
76 self.bookmarks = bookmarks
77 # allow push of new branch
77 # allow push of new branch
78 self.newbranch = newbranch
78 self.newbranch = newbranch
79 # did a local lock get acquired?
79 # did a local lock get acquired?
80 self.locallocked = None
80 self.locallocked = None
81 # step already performed
81 # step already performed
82 # (used to check what steps have been already performed through bundle2)
82 # (used to check what steps have been already performed through bundle2)
83 self.stepsdone = set()
83 self.stepsdone = set()
84 # Integer version of the changegroup push result
84 # Integer version of the changegroup push result
85 # - None means nothing to push
85 # - None means nothing to push
86 # - 0 means HTTP error
86 # - 0 means HTTP error
87 # - 1 means we pushed and remote head count is unchanged *or*
87 # - 1 means we pushed and remote head count is unchanged *or*
88 # we have outgoing changesets but refused to push
88 # we have outgoing changesets but refused to push
89 # - other values as described by addchangegroup()
89 # - other values as described by addchangegroup()
90 self.cgresult = None
90 self.cgresult = None
91 # Boolean value for the bookmark push
91 # Boolean value for the bookmark push
92 self.bkresult = None
92 self.bkresult = None
93 # discover.outgoing object (contains common and outgoing data)
93 # discover.outgoing object (contains common and outgoing data)
94 self.outgoing = None
94 self.outgoing = None
95 # all remote heads before the push
95 # all remote heads before the push
96 self.remoteheads = None
96 self.remoteheads = None
97 # testable as a boolean indicating if any nodes are missing locally.
97 # testable as a boolean indicating if any nodes are missing locally.
98 self.incoming = None
98 self.incoming = None
99 # phases changes that must be pushed along side the changesets
99 # phases changes that must be pushed along side the changesets
100 self.outdatedphases = None
100 self.outdatedphases = None
101 # phases changes that must be pushed if changeset push fails
101 # phases changes that must be pushed if changeset push fails
102 self.fallbackoutdatedphases = None
102 self.fallbackoutdatedphases = None
103 # outgoing obsmarkers
103 # outgoing obsmarkers
104 self.outobsmarkers = set()
104 self.outobsmarkers = set()
105 # outgoing bookmarks
105 # outgoing bookmarks
106 self.outbookmarks = []
106 self.outbookmarks = []
107
107
108 @util.propertycache
108 @util.propertycache
109 def futureheads(self):
109 def futureheads(self):
110 """future remote heads if the changeset push succeeds"""
110 """future remote heads if the changeset push succeeds"""
111 return self.outgoing.missingheads
111 return self.outgoing.missingheads
112
112
113 @util.propertycache
113 @util.propertycache
114 def fallbackheads(self):
114 def fallbackheads(self):
115 """future remote heads if the changeset push fails"""
115 """future remote heads if the changeset push fails"""
116 if self.revs is None:
116 if self.revs is None:
117 # not target to push, all common are relevant
117 # not target to push, all common are relevant
118 return self.outgoing.commonheads
118 return self.outgoing.commonheads
119 unfi = self.repo.unfiltered()
119 unfi = self.repo.unfiltered()
120 # I want cheads = heads(::missingheads and ::commonheads)
120 # I want cheads = heads(::missingheads and ::commonheads)
121 # (missingheads is revs with secret changeset filtered out)
121 # (missingheads is revs with secret changeset filtered out)
122 #
122 #
123 # This can be expressed as:
123 # This can be expressed as:
124 # cheads = ( (missingheads and ::commonheads)
124 # cheads = ( (missingheads and ::commonheads)
125 # + (commonheads and ::missingheads))"
125 # + (commonheads and ::missingheads))"
126 # )
126 # )
127 #
127 #
128 # while trying to push we already computed the following:
128 # while trying to push we already computed the following:
129 # common = (::commonheads)
129 # common = (::commonheads)
130 # missing = ((commonheads::missingheads) - commonheads)
130 # missing = ((commonheads::missingheads) - commonheads)
131 #
131 #
132 # We can pick:
132 # We can pick:
133 # * missingheads part of common (::commonheads)
133 # * missingheads part of common (::commonheads)
134 common = set(self.outgoing.common)
134 common = set(self.outgoing.common)
135 nm = self.repo.changelog.nodemap
135 nm = self.repo.changelog.nodemap
136 cheads = [node for node in self.revs if nm[node] in common]
136 cheads = [node for node in self.revs if nm[node] in common]
137 # and
137 # and
138 # * commonheads parents on missing
138 # * commonheads parents on missing
139 revset = unfi.set('%ln and parents(roots(%ln))',
139 revset = unfi.set('%ln and parents(roots(%ln))',
140 self.outgoing.commonheads,
140 self.outgoing.commonheads,
141 self.outgoing.missing)
141 self.outgoing.missing)
142 cheads.extend(c.node() for c in revset)
142 cheads.extend(c.node() for c in revset)
143 return cheads
143 return cheads
144
144
145 @property
145 @property
146 def commonheads(self):
146 def commonheads(self):
147 """set of all common heads after changeset bundle push"""
147 """set of all common heads after changeset bundle push"""
148 if self.cgresult:
148 if self.cgresult:
149 return self.futureheads
149 return self.futureheads
150 else:
150 else:
151 return self.fallbackheads
151 return self.fallbackheads
152
152
153 # mapping of message used when pushing bookmark
153 # mapping of message used when pushing bookmark
154 bookmsgmap = {'update': (_("updating bookmark %s\n"),
154 bookmsgmap = {'update': (_("updating bookmark %s\n"),
155 _('updating bookmark %s failed!\n')),
155 _('updating bookmark %s failed!\n')),
156 'export': (_("exporting bookmark %s\n"),
156 'export': (_("exporting bookmark %s\n"),
157 _('exporting bookmark %s failed!\n')),
157 _('exporting bookmark %s failed!\n')),
158 'delete': (_("deleting remote bookmark %s\n"),
158 'delete': (_("deleting remote bookmark %s\n"),
159 _('deleting remote bookmark %s failed!\n')),
159 _('deleting remote bookmark %s failed!\n')),
160 }
160 }
161
161
162
162
163 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=()):
163 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=()):
164 '''Push outgoing changesets (limited by revs) from a local
164 '''Push outgoing changesets (limited by revs) from a local
165 repository to remote. Return an integer:
165 repository to remote. Return an integer:
166 - None means nothing to push
166 - None means nothing to push
167 - 0 means HTTP error
167 - 0 means HTTP error
168 - 1 means we pushed and remote head count is unchanged *or*
168 - 1 means we pushed and remote head count is unchanged *or*
169 we have outgoing changesets but refused to push
169 we have outgoing changesets but refused to push
170 - other values as described by addchangegroup()
170 - other values as described by addchangegroup()
171 '''
171 '''
172 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks)
172 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks)
173 if pushop.remote.local():
173 if pushop.remote.local():
174 missing = (set(pushop.repo.requirements)
174 missing = (set(pushop.repo.requirements)
175 - pushop.remote.local().supported)
175 - pushop.remote.local().supported)
176 if missing:
176 if missing:
177 msg = _("required features are not"
177 msg = _("required features are not"
178 " supported in the destination:"
178 " supported in the destination:"
179 " %s") % (', '.join(sorted(missing)))
179 " %s") % (', '.join(sorted(missing)))
180 raise util.Abort(msg)
180 raise util.Abort(msg)
181
181
182 # there are two ways to push to remote repo:
182 # there are two ways to push to remote repo:
183 #
183 #
184 # addchangegroup assumes local user can lock remote
184 # addchangegroup assumes local user can lock remote
185 # repo (local filesystem, old ssh servers).
185 # repo (local filesystem, old ssh servers).
186 #
186 #
187 # unbundle assumes local user cannot lock remote repo (new ssh
187 # unbundle assumes local user cannot lock remote repo (new ssh
188 # servers, http servers).
188 # servers, http servers).
189
189
190 if not pushop.remote.canpush():
190 if not pushop.remote.canpush():
191 raise util.Abort(_("destination does not support push"))
191 raise util.Abort(_("destination does not support push"))
192 # get local lock as we might write phase data
192 # get local lock as we might write phase data
193 locallock = None
193 locallock = None
194 try:
194 try:
195 locallock = pushop.repo.lock()
195 locallock = pushop.repo.lock()
196 pushop.locallocked = True
196 pushop.locallocked = True
197 except IOError, err:
197 except IOError, err:
198 pushop.locallocked = False
198 pushop.locallocked = False
199 if err.errno != errno.EACCES:
199 if err.errno != errno.EACCES:
200 raise
200 raise
201 # source repo cannot be locked.
201 # source repo cannot be locked.
202 # We do not abort the push, but just disable the local phase
202 # We do not abort the push, but just disable the local phase
203 # synchronisation.
203 # synchronisation.
204 msg = 'cannot lock source repository: %s\n' % err
204 msg = 'cannot lock source repository: %s\n' % err
205 pushop.ui.debug(msg)
205 pushop.ui.debug(msg)
206 try:
206 try:
207 pushop.repo.checkpush(pushop)
207 pushop.repo.checkpush(pushop)
208 lock = None
208 lock = None
209 unbundle = pushop.remote.capable('unbundle')
209 unbundle = pushop.remote.capable('unbundle')
210 if not unbundle:
210 if not unbundle:
211 lock = pushop.remote.lock()
211 lock = pushop.remote.lock()
212 try:
212 try:
213 _pushdiscovery(pushop)
213 _pushdiscovery(pushop)
214 if (pushop.repo.ui.configbool('experimental', 'bundle2-exp',
214 if (pushop.repo.ui.configbool('experimental', 'bundle2-exp',
215 False)
215 False)
216 and pushop.remote.capable('bundle2-exp')):
216 and pushop.remote.capable('bundle2-exp')):
217 _pushbundle2(pushop)
217 _pushbundle2(pushop)
218 _pushchangeset(pushop)
218 _pushchangeset(pushop)
219 _pushsyncphase(pushop)
219 _pushsyncphase(pushop)
220 _pushobsolete(pushop)
220 _pushobsolete(pushop)
221 _pushbookmark(pushop)
221 _pushbookmark(pushop)
222 finally:
222 finally:
223 if lock is not None:
223 if lock is not None:
224 lock.release()
224 lock.release()
225 finally:
225 finally:
226 if locallock is not None:
226 if locallock is not None:
227 locallock.release()
227 locallock.release()
228
228
229 if pushop.bookmarks:
230 pushop.bkresult = bookmod.pushtoremote(repo.ui, repo, remote,
231 pushop.bookmarks)
232
233 return pushop
229 return pushop
234
230
235 # list of steps to perform discovery before push
231 # list of steps to perform discovery before push
236 pushdiscoveryorder = []
232 pushdiscoveryorder = []
237
233
238 # Mapping between step name and function
234 # Mapping between step name and function
239 #
235 #
240 # This exists to help extensions wrap steps if necessary
236 # This exists to help extensions wrap steps if necessary
241 pushdiscoverymapping = {}
237 pushdiscoverymapping = {}
242
238
243 def pushdiscovery(stepname):
239 def pushdiscovery(stepname):
244 """decorator for function performing discovery before push
240 """decorator for function performing discovery before push
245
241
246 The function is added to the step -> function mapping and appended to the
242 The function is added to the step -> function mapping and appended to the
247 list of steps. Beware that decorated function will be added in order (this
243 list of steps. Beware that decorated function will be added in order (this
248 may matter).
244 may matter).
249
245
250 You can only use this decorator for a new step, if you want to wrap a step
246 You can only use this decorator for a new step, if you want to wrap a step
251 from an extension, change the pushdiscovery dictionary directly."""
247 from an extension, change the pushdiscovery dictionary directly."""
252 def dec(func):
248 def dec(func):
253 assert stepname not in pushdiscoverymapping
249 assert stepname not in pushdiscoverymapping
254 pushdiscoverymapping[stepname] = func
250 pushdiscoverymapping[stepname] = func
255 pushdiscoveryorder.append(stepname)
251 pushdiscoveryorder.append(stepname)
256 return func
252 return func
257 return dec
253 return dec
258
254
259 def _pushdiscovery(pushop):
255 def _pushdiscovery(pushop):
260 """Run all discovery steps"""
256 """Run all discovery steps"""
261 for stepname in pushdiscoveryorder:
257 for stepname in pushdiscoveryorder:
262 step = pushdiscoverymapping[stepname]
258 step = pushdiscoverymapping[stepname]
263 step(pushop)
259 step(pushop)
264
260
265 @pushdiscovery('changeset')
261 @pushdiscovery('changeset')
266 def _pushdiscoverychangeset(pushop):
262 def _pushdiscoverychangeset(pushop):
267 """discover the changeset that need to be pushed"""
263 """discover the changeset that need to be pushed"""
268 unfi = pushop.repo.unfiltered()
264 unfi = pushop.repo.unfiltered()
269 fci = discovery.findcommonincoming
265 fci = discovery.findcommonincoming
270 commoninc = fci(unfi, pushop.remote, force=pushop.force)
266 commoninc = fci(unfi, pushop.remote, force=pushop.force)
271 common, inc, remoteheads = commoninc
267 common, inc, remoteheads = commoninc
272 fco = discovery.findcommonoutgoing
268 fco = discovery.findcommonoutgoing
273 outgoing = fco(unfi, pushop.remote, onlyheads=pushop.revs,
269 outgoing = fco(unfi, pushop.remote, onlyheads=pushop.revs,
274 commoninc=commoninc, force=pushop.force)
270 commoninc=commoninc, force=pushop.force)
275 pushop.outgoing = outgoing
271 pushop.outgoing = outgoing
276 pushop.remoteheads = remoteheads
272 pushop.remoteheads = remoteheads
277 pushop.incoming = inc
273 pushop.incoming = inc
278
274
279 @pushdiscovery('phase')
275 @pushdiscovery('phase')
280 def _pushdiscoveryphase(pushop):
276 def _pushdiscoveryphase(pushop):
281 """discover the phase that needs to be pushed
277 """discover the phase that needs to be pushed
282
278
283 (computed for both success and failure case for changesets push)"""
279 (computed for both success and failure case for changesets push)"""
284 outgoing = pushop.outgoing
280 outgoing = pushop.outgoing
285 unfi = pushop.repo.unfiltered()
281 unfi = pushop.repo.unfiltered()
286 remotephases = pushop.remote.listkeys('phases')
282 remotephases = pushop.remote.listkeys('phases')
287 publishing = remotephases.get('publishing', False)
283 publishing = remotephases.get('publishing', False)
288 ana = phases.analyzeremotephases(pushop.repo,
284 ana = phases.analyzeremotephases(pushop.repo,
289 pushop.fallbackheads,
285 pushop.fallbackheads,
290 remotephases)
286 remotephases)
291 pheads, droots = ana
287 pheads, droots = ana
292 extracond = ''
288 extracond = ''
293 if not publishing:
289 if not publishing:
294 extracond = ' and public()'
290 extracond = ' and public()'
295 revset = 'heads((%%ln::%%ln) %s)' % extracond
291 revset = 'heads((%%ln::%%ln) %s)' % extracond
296 # Get the list of all revs draft on remote by public here.
292 # Get the list of all revs draft on remote by public here.
297 # XXX Beware that revset break if droots is not strictly
293 # XXX Beware that revset break if droots is not strictly
298 # XXX root we may want to ensure it is but it is costly
294 # XXX root we may want to ensure it is but it is costly
299 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
295 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
300 if not outgoing.missing:
296 if not outgoing.missing:
301 future = fallback
297 future = fallback
302 else:
298 else:
303 # adds changeset we are going to push as draft
299 # adds changeset we are going to push as draft
304 #
300 #
305 # should not be necessary for pushblishing server, but because of an
301 # should not be necessary for pushblishing server, but because of an
306 # issue fixed in xxxxx we have to do it anyway.
302 # issue fixed in xxxxx we have to do it anyway.
307 fdroots = list(unfi.set('roots(%ln + %ln::)',
303 fdroots = list(unfi.set('roots(%ln + %ln::)',
308 outgoing.missing, droots))
304 outgoing.missing, droots))
309 fdroots = [f.node() for f in fdroots]
305 fdroots = [f.node() for f in fdroots]
310 future = list(unfi.set(revset, fdroots, pushop.futureheads))
306 future = list(unfi.set(revset, fdroots, pushop.futureheads))
311 pushop.outdatedphases = future
307 pushop.outdatedphases = future
312 pushop.fallbackoutdatedphases = fallback
308 pushop.fallbackoutdatedphases = fallback
313
309
314 @pushdiscovery('obsmarker')
310 @pushdiscovery('obsmarker')
315 def _pushdiscoveryobsmarkers(pushop):
311 def _pushdiscoveryobsmarkers(pushop):
316 if (obsolete._enabled
312 if (obsolete._enabled
317 and pushop.repo.obsstore
313 and pushop.repo.obsstore
318 and 'obsolete' in pushop.remote.listkeys('namespaces')):
314 and 'obsolete' in pushop.remote.listkeys('namespaces')):
319 repo = pushop.repo
315 repo = pushop.repo
320 # very naive computation, that can be quite expensive on big repo.
316 # very naive computation, that can be quite expensive on big repo.
321 # However: evolution is currently slow on them anyway.
317 # However: evolution is currently slow on them anyway.
322 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
318 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
323 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
319 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
324
320
325 @pushdiscovery('bookmarks')
321 @pushdiscovery('bookmarks')
326 def _pushdiscoverybookmarks(pushop):
322 def _pushdiscoverybookmarks(pushop):
327 ui = pushop.ui
323 ui = pushop.ui
328 repo = pushop.repo.unfiltered()
324 repo = pushop.repo.unfiltered()
329 remote = pushop.remote
325 remote = pushop.remote
330 ui.debug("checking for updated bookmarks\n")
326 ui.debug("checking for updated bookmarks\n")
331 ancestors = ()
327 ancestors = ()
332 if pushop.revs:
328 if pushop.revs:
333 revnums = map(repo.changelog.rev, pushop.revs)
329 revnums = map(repo.changelog.rev, pushop.revs)
334 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
330 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
335 remotebookmark = remote.listkeys('bookmarks')
331 remotebookmark = remote.listkeys('bookmarks')
336
332
333 explicit = set(pushop.bookmarks)
334
337 comp = bookmod.compare(repo, repo._bookmarks, remotebookmark, srchex=hex)
335 comp = bookmod.compare(repo, repo._bookmarks, remotebookmark, srchex=hex)
338 addsrc, adddst, advsrc, advdst, diverge, differ, invalid = comp
336 addsrc, adddst, advsrc, advdst, diverge, differ, invalid = comp
339 for b, scid, dcid in advsrc:
337 for b, scid, dcid in advsrc:
338 if b in explicit:
339 explicit.remove(b)
340 if not ancestors or repo[scid].rev() in ancestors:
340 if not ancestors or repo[scid].rev() in ancestors:
341 pushop.outbookmarks.append((b, dcid, scid))
341 pushop.outbookmarks.append((b, dcid, scid))
342 # search added bookmark
343 for b, scid, dcid in addsrc:
344 if b in explicit:
345 explicit.remove(b)
346 pushop.outbookmarks.append((b, '', scid))
347 # search for overwritten bookmark
348 for b, scid, dcid in advdst + diverge + differ:
349 if b in explicit:
350 explicit.remove(b)
351 pushop.outbookmarks.append((b, dcid, scid))
352 # search for bookmark to delete
353 for b, scid, dcid in adddst:
354 if b in explicit:
355 explicit.remove(b)
356 # treat as "deleted locally"
357 pushop.outbookmarks.append((b, dcid, ''))
358
359 if explicit:
360 explicit = sorted(explicit)
361 # we should probably list all of them
362 ui.warn(_('bookmark %s does not exist on the local '
363 'or remote repository!\n') % explicit[0])
364 pushop.bkresult = 2
365
366 pushop.outbookmarks.sort()
342
367
343 def _pushcheckoutgoing(pushop):
368 def _pushcheckoutgoing(pushop):
344 outgoing = pushop.outgoing
369 outgoing = pushop.outgoing
345 unfi = pushop.repo.unfiltered()
370 unfi = pushop.repo.unfiltered()
346 if not outgoing.missing:
371 if not outgoing.missing:
347 # nothing to push
372 # nothing to push
348 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
373 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
349 return False
374 return False
350 # something to push
375 # something to push
351 if not pushop.force:
376 if not pushop.force:
352 # if repo.obsstore == False --> no obsolete
377 # if repo.obsstore == False --> no obsolete
353 # then, save the iteration
378 # then, save the iteration
354 if unfi.obsstore:
379 if unfi.obsstore:
355 # this message are here for 80 char limit reason
380 # this message are here for 80 char limit reason
356 mso = _("push includes obsolete changeset: %s!")
381 mso = _("push includes obsolete changeset: %s!")
357 mst = {"unstable": _("push includes unstable changeset: %s!"),
382 mst = {"unstable": _("push includes unstable changeset: %s!"),
358 "bumped": _("push includes bumped changeset: %s!"),
383 "bumped": _("push includes bumped changeset: %s!"),
359 "divergent": _("push includes divergent changeset: %s!")}
384 "divergent": _("push includes divergent changeset: %s!")}
360 # If we are to push if there is at least one
385 # If we are to push if there is at least one
361 # obsolete or unstable changeset in missing, at
386 # obsolete or unstable changeset in missing, at
362 # least one of the missinghead will be obsolete or
387 # least one of the missinghead will be obsolete or
363 # unstable. So checking heads only is ok
388 # unstable. So checking heads only is ok
364 for node in outgoing.missingheads:
389 for node in outgoing.missingheads:
365 ctx = unfi[node]
390 ctx = unfi[node]
366 if ctx.obsolete():
391 if ctx.obsolete():
367 raise util.Abort(mso % ctx)
392 raise util.Abort(mso % ctx)
368 elif ctx.troubled():
393 elif ctx.troubled():
369 raise util.Abort(mst[ctx.troubles()[0]] % ctx)
394 raise util.Abort(mst[ctx.troubles()[0]] % ctx)
370 newbm = pushop.ui.configlist('bookmarks', 'pushing')
395 newbm = pushop.ui.configlist('bookmarks', 'pushing')
371 discovery.checkheads(unfi, pushop.remote, outgoing,
396 discovery.checkheads(unfi, pushop.remote, outgoing,
372 pushop.remoteheads,
397 pushop.remoteheads,
373 pushop.newbranch,
398 pushop.newbranch,
374 bool(pushop.incoming),
399 bool(pushop.incoming),
375 newbm)
400 newbm)
376 return True
401 return True
377
402
378 # List of names of steps to perform for an outgoing bundle2, order matters.
403 # List of names of steps to perform for an outgoing bundle2, order matters.
379 b2partsgenorder = []
404 b2partsgenorder = []
380
405
381 # Mapping between step name and function
406 # Mapping between step name and function
382 #
407 #
383 # This exists to help extensions wrap steps if necessary
408 # This exists to help extensions wrap steps if necessary
384 b2partsgenmapping = {}
409 b2partsgenmapping = {}
385
410
386 def b2partsgenerator(stepname):
411 def b2partsgenerator(stepname):
387 """decorator for function generating bundle2 part
412 """decorator for function generating bundle2 part
388
413
389 The function is added to the step -> function mapping and appended to the
414 The function is added to the step -> function mapping and appended to the
390 list of steps. Beware that decorated functions will be added in order
415 list of steps. Beware that decorated functions will be added in order
391 (this may matter).
416 (this may matter).
392
417
393 You can only use this decorator for new steps, if you want to wrap a step
418 You can only use this decorator for new steps, if you want to wrap a step
394 from an extension, attack the b2partsgenmapping dictionary directly."""
419 from an extension, attack the b2partsgenmapping dictionary directly."""
395 def dec(func):
420 def dec(func):
396 assert stepname not in b2partsgenmapping
421 assert stepname not in b2partsgenmapping
397 b2partsgenmapping[stepname] = func
422 b2partsgenmapping[stepname] = func
398 b2partsgenorder.append(stepname)
423 b2partsgenorder.append(stepname)
399 return func
424 return func
400 return dec
425 return dec
401
426
402 @b2partsgenerator('changeset')
427 @b2partsgenerator('changeset')
403 def _pushb2ctx(pushop, bundler):
428 def _pushb2ctx(pushop, bundler):
404 """handle changegroup push through bundle2
429 """handle changegroup push through bundle2
405
430
406 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
431 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
407 """
432 """
408 if 'changesets' in pushop.stepsdone:
433 if 'changesets' in pushop.stepsdone:
409 return
434 return
410 pushop.stepsdone.add('changesets')
435 pushop.stepsdone.add('changesets')
411 # Send known heads to the server for race detection.
436 # Send known heads to the server for race detection.
412 if not _pushcheckoutgoing(pushop):
437 if not _pushcheckoutgoing(pushop):
413 return
438 return
414 pushop.repo.prepushoutgoinghooks(pushop.repo,
439 pushop.repo.prepushoutgoinghooks(pushop.repo,
415 pushop.remote,
440 pushop.remote,
416 pushop.outgoing)
441 pushop.outgoing)
417 if not pushop.force:
442 if not pushop.force:
418 bundler.newpart('B2X:CHECK:HEADS', data=iter(pushop.remoteheads))
443 bundler.newpart('B2X:CHECK:HEADS', data=iter(pushop.remoteheads))
419 cg = changegroup.getlocalchangegroup(pushop.repo, 'push', pushop.outgoing)
444 cg = changegroup.getlocalchangegroup(pushop.repo, 'push', pushop.outgoing)
420 cgpart = bundler.newpart('B2X:CHANGEGROUP', data=cg.getchunks())
445 cgpart = bundler.newpart('B2X:CHANGEGROUP', data=cg.getchunks())
421 def handlereply(op):
446 def handlereply(op):
422 """extract addchangroup returns from server reply"""
447 """extract addchangroup returns from server reply"""
423 cgreplies = op.records.getreplies(cgpart.id)
448 cgreplies = op.records.getreplies(cgpart.id)
424 assert len(cgreplies['changegroup']) == 1
449 assert len(cgreplies['changegroup']) == 1
425 pushop.cgresult = cgreplies['changegroup'][0]['return']
450 pushop.cgresult = cgreplies['changegroup'][0]['return']
426 return handlereply
451 return handlereply
427
452
428 @b2partsgenerator('phase')
453 @b2partsgenerator('phase')
429 def _pushb2phases(pushop, bundler):
454 def _pushb2phases(pushop, bundler):
430 """handle phase push through bundle2"""
455 """handle phase push through bundle2"""
431 if 'phases' in pushop.stepsdone:
456 if 'phases' in pushop.stepsdone:
432 return
457 return
433 b2caps = bundle2.bundle2caps(pushop.remote)
458 b2caps = bundle2.bundle2caps(pushop.remote)
434 if not 'b2x:pushkey' in b2caps:
459 if not 'b2x:pushkey' in b2caps:
435 return
460 return
436 pushop.stepsdone.add('phases')
461 pushop.stepsdone.add('phases')
437 part2node = []
462 part2node = []
438 enc = pushkey.encode
463 enc = pushkey.encode
439 for newremotehead in pushop.outdatedphases:
464 for newremotehead in pushop.outdatedphases:
440 part = bundler.newpart('b2x:pushkey')
465 part = bundler.newpart('b2x:pushkey')
441 part.addparam('namespace', enc('phases'))
466 part.addparam('namespace', enc('phases'))
442 part.addparam('key', enc(newremotehead.hex()))
467 part.addparam('key', enc(newremotehead.hex()))
443 part.addparam('old', enc(str(phases.draft)))
468 part.addparam('old', enc(str(phases.draft)))
444 part.addparam('new', enc(str(phases.public)))
469 part.addparam('new', enc(str(phases.public)))
445 part2node.append((part.id, newremotehead))
470 part2node.append((part.id, newremotehead))
446 def handlereply(op):
471 def handlereply(op):
447 for partid, node in part2node:
472 for partid, node in part2node:
448 partrep = op.records.getreplies(partid)
473 partrep = op.records.getreplies(partid)
449 results = partrep['pushkey']
474 results = partrep['pushkey']
450 assert len(results) <= 1
475 assert len(results) <= 1
451 msg = None
476 msg = None
452 if not results:
477 if not results:
453 msg = _('server ignored update of %s to public!\n') % node
478 msg = _('server ignored update of %s to public!\n') % node
454 elif not int(results[0]['return']):
479 elif not int(results[0]['return']):
455 msg = _('updating %s to public failed!\n') % node
480 msg = _('updating %s to public failed!\n') % node
456 if msg is not None:
481 if msg is not None:
457 pushop.ui.warn(msg)
482 pushop.ui.warn(msg)
458 return handlereply
483 return handlereply
459
484
460 @b2partsgenerator('obsmarkers')
485 @b2partsgenerator('obsmarkers')
461 def _pushb2obsmarkers(pushop, bundler):
486 def _pushb2obsmarkers(pushop, bundler):
462 if 'obsmarkers' in pushop.stepsdone:
487 if 'obsmarkers' in pushop.stepsdone:
463 return
488 return
464 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
489 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
465 if obsolete.commonversion(remoteversions) is None:
490 if obsolete.commonversion(remoteversions) is None:
466 return
491 return
467 pushop.stepsdone.add('obsmarkers')
492 pushop.stepsdone.add('obsmarkers')
468 if pushop.outobsmarkers:
493 if pushop.outobsmarkers:
469 buildobsmarkerspart(bundler, pushop.outobsmarkers)
494 buildobsmarkerspart(bundler, pushop.outobsmarkers)
470
495
471 @b2partsgenerator('bookmarks')
496 @b2partsgenerator('bookmarks')
472 def _pushb2bookmarks(pushop, bundler):
497 def _pushb2bookmarks(pushop, bundler):
473 """handle phase push through bundle2"""
498 """handle phase push through bundle2"""
474 if 'bookmarks' in pushop.stepsdone:
499 if 'bookmarks' in pushop.stepsdone:
475 return
500 return
476 b2caps = bundle2.bundle2caps(pushop.remote)
501 b2caps = bundle2.bundle2caps(pushop.remote)
477 if 'b2x:pushkey' not in b2caps:
502 if 'b2x:pushkey' not in b2caps:
478 return
503 return
479 pushop.stepsdone.add('bookmarks')
504 pushop.stepsdone.add('bookmarks')
480 part2book = []
505 part2book = []
481 enc = pushkey.encode
506 enc = pushkey.encode
482 for book, old, new in pushop.outbookmarks:
507 for book, old, new in pushop.outbookmarks:
483 part = bundler.newpart('b2x:pushkey')
508 part = bundler.newpart('b2x:pushkey')
484 part.addparam('namespace', enc('bookmarks'))
509 part.addparam('namespace', enc('bookmarks'))
485 part.addparam('key', enc(book))
510 part.addparam('key', enc(book))
486 part.addparam('old', enc(old))
511 part.addparam('old', enc(old))
487 part.addparam('new', enc(new))
512 part.addparam('new', enc(new))
488 action = 'update'
513 action = 'update'
489 if not old:
514 if not old:
490 action = 'export'
515 action = 'export'
491 elif not new:
516 elif not new:
492 action = 'delete'
517 action = 'delete'
493 part2book.append((part.id, book, action))
518 part2book.append((part.id, book, action))
494
519
495
520
496 def handlereply(op):
521 def handlereply(op):
497 ui = pushop.ui
522 ui = pushop.ui
498 for partid, book, action in part2book:
523 for partid, book, action in part2book:
499 partrep = op.records.getreplies(partid)
524 partrep = op.records.getreplies(partid)
500 results = partrep['pushkey']
525 results = partrep['pushkey']
501 assert len(results) <= 1
526 assert len(results) <= 1
502 if not results:
527 if not results:
503 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
528 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
504 else:
529 else:
505 ret = int(results[0]['return'])
530 ret = int(results[0]['return'])
506 if ret:
531 if ret:
507 ui.status(bookmsgmap[action][0] % book)
532 ui.status(bookmsgmap[action][0] % book)
508 else:
533 else:
509 ui.warn(bookmsgmap[action][1] % book)
534 ui.warn(bookmsgmap[action][1] % book)
510 if pushop.bkresult is not None:
535 if pushop.bkresult is not None:
511 pushop.bkresult = 1
536 pushop.bkresult = 1
512 return handlereply
537 return handlereply
513
538
514
539
515 def _pushbundle2(pushop):
540 def _pushbundle2(pushop):
516 """push data to the remote using bundle2
541 """push data to the remote using bundle2
517
542
518 The only currently supported type of data is changegroup but this will
543 The only currently supported type of data is changegroup but this will
519 evolve in the future."""
544 evolve in the future."""
520 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
545 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
521 # create reply capability
546 # create reply capability
522 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo))
547 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo))
523 bundler.newpart('b2x:replycaps', data=capsblob)
548 bundler.newpart('b2x:replycaps', data=capsblob)
524 replyhandlers = []
549 replyhandlers = []
525 for partgenname in b2partsgenorder:
550 for partgenname in b2partsgenorder:
526 partgen = b2partsgenmapping[partgenname]
551 partgen = b2partsgenmapping[partgenname]
527 ret = partgen(pushop, bundler)
552 ret = partgen(pushop, bundler)
528 if callable(ret):
553 if callable(ret):
529 replyhandlers.append(ret)
554 replyhandlers.append(ret)
530 # do not push if nothing to push
555 # do not push if nothing to push
531 if bundler.nbparts <= 1:
556 if bundler.nbparts <= 1:
532 return
557 return
533 stream = util.chunkbuffer(bundler.getchunks())
558 stream = util.chunkbuffer(bundler.getchunks())
534 try:
559 try:
535 reply = pushop.remote.unbundle(stream, ['force'], 'push')
560 reply = pushop.remote.unbundle(stream, ['force'], 'push')
536 except error.BundleValueError, exc:
561 except error.BundleValueError, exc:
537 raise util.Abort('missing support for %s' % exc)
562 raise util.Abort('missing support for %s' % exc)
538 try:
563 try:
539 op = bundle2.processbundle(pushop.repo, reply)
564 op = bundle2.processbundle(pushop.repo, reply)
540 except error.BundleValueError, exc:
565 except error.BundleValueError, exc:
541 raise util.Abort('missing support for %s' % exc)
566 raise util.Abort('missing support for %s' % exc)
542 for rephand in replyhandlers:
567 for rephand in replyhandlers:
543 rephand(op)
568 rephand(op)
544
569
545 def _pushchangeset(pushop):
570 def _pushchangeset(pushop):
546 """Make the actual push of changeset bundle to remote repo"""
571 """Make the actual push of changeset bundle to remote repo"""
547 if 'changesets' in pushop.stepsdone:
572 if 'changesets' in pushop.stepsdone:
548 return
573 return
549 pushop.stepsdone.add('changesets')
574 pushop.stepsdone.add('changesets')
550 if not _pushcheckoutgoing(pushop):
575 if not _pushcheckoutgoing(pushop):
551 return
576 return
552 pushop.repo.prepushoutgoinghooks(pushop.repo,
577 pushop.repo.prepushoutgoinghooks(pushop.repo,
553 pushop.remote,
578 pushop.remote,
554 pushop.outgoing)
579 pushop.outgoing)
555 outgoing = pushop.outgoing
580 outgoing = pushop.outgoing
556 unbundle = pushop.remote.capable('unbundle')
581 unbundle = pushop.remote.capable('unbundle')
557 # TODO: get bundlecaps from remote
582 # TODO: get bundlecaps from remote
558 bundlecaps = None
583 bundlecaps = None
559 # create a changegroup from local
584 # create a changegroup from local
560 if pushop.revs is None and not (outgoing.excluded
585 if pushop.revs is None and not (outgoing.excluded
561 or pushop.repo.changelog.filteredrevs):
586 or pushop.repo.changelog.filteredrevs):
562 # push everything,
587 # push everything,
563 # use the fast path, no race possible on push
588 # use the fast path, no race possible on push
564 bundler = changegroup.cg1packer(pushop.repo, bundlecaps)
589 bundler = changegroup.cg1packer(pushop.repo, bundlecaps)
565 cg = changegroup.getsubset(pushop.repo,
590 cg = changegroup.getsubset(pushop.repo,
566 outgoing,
591 outgoing,
567 bundler,
592 bundler,
568 'push',
593 'push',
569 fastpath=True)
594 fastpath=True)
570 else:
595 else:
571 cg = changegroup.getlocalchangegroup(pushop.repo, 'push', outgoing,
596 cg = changegroup.getlocalchangegroup(pushop.repo, 'push', outgoing,
572 bundlecaps)
597 bundlecaps)
573
598
574 # apply changegroup to remote
599 # apply changegroup to remote
575 if unbundle:
600 if unbundle:
576 # local repo finds heads on server, finds out what
601 # local repo finds heads on server, finds out what
577 # revs it must push. once revs transferred, if server
602 # revs it must push. once revs transferred, if server
578 # finds it has different heads (someone else won
603 # finds it has different heads (someone else won
579 # commit/push race), server aborts.
604 # commit/push race), server aborts.
580 if pushop.force:
605 if pushop.force:
581 remoteheads = ['force']
606 remoteheads = ['force']
582 else:
607 else:
583 remoteheads = pushop.remoteheads
608 remoteheads = pushop.remoteheads
584 # ssh: return remote's addchangegroup()
609 # ssh: return remote's addchangegroup()
585 # http: return remote's addchangegroup() or 0 for error
610 # http: return remote's addchangegroup() or 0 for error
586 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
611 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
587 pushop.repo.url())
612 pushop.repo.url())
588 else:
613 else:
589 # we return an integer indicating remote head count
614 # we return an integer indicating remote head count
590 # change
615 # change
591 pushop.cgresult = pushop.remote.addchangegroup(cg, 'push',
616 pushop.cgresult = pushop.remote.addchangegroup(cg, 'push',
592 pushop.repo.url())
617 pushop.repo.url())
593
618
594 def _pushsyncphase(pushop):
619 def _pushsyncphase(pushop):
595 """synchronise phase information locally and remotely"""
620 """synchronise phase information locally and remotely"""
596 cheads = pushop.commonheads
621 cheads = pushop.commonheads
597 # even when we don't push, exchanging phase data is useful
622 # even when we don't push, exchanging phase data is useful
598 remotephases = pushop.remote.listkeys('phases')
623 remotephases = pushop.remote.listkeys('phases')
599 if (pushop.ui.configbool('ui', '_usedassubrepo', False)
624 if (pushop.ui.configbool('ui', '_usedassubrepo', False)
600 and remotephases # server supports phases
625 and remotephases # server supports phases
601 and pushop.cgresult is None # nothing was pushed
626 and pushop.cgresult is None # nothing was pushed
602 and remotephases.get('publishing', False)):
627 and remotephases.get('publishing', False)):
603 # When:
628 # When:
604 # - this is a subrepo push
629 # - this is a subrepo push
605 # - and remote support phase
630 # - and remote support phase
606 # - and no changeset was pushed
631 # - and no changeset was pushed
607 # - and remote is publishing
632 # - and remote is publishing
608 # We may be in issue 3871 case!
633 # We may be in issue 3871 case!
609 # We drop the possible phase synchronisation done by
634 # We drop the possible phase synchronisation done by
610 # courtesy to publish changesets possibly locally draft
635 # courtesy to publish changesets possibly locally draft
611 # on the remote.
636 # on the remote.
612 remotephases = {'publishing': 'True'}
637 remotephases = {'publishing': 'True'}
613 if not remotephases: # old server or public only reply from non-publishing
638 if not remotephases: # old server or public only reply from non-publishing
614 _localphasemove(pushop, cheads)
639 _localphasemove(pushop, cheads)
615 # don't push any phase data as there is nothing to push
640 # don't push any phase data as there is nothing to push
616 else:
641 else:
617 ana = phases.analyzeremotephases(pushop.repo, cheads,
642 ana = phases.analyzeremotephases(pushop.repo, cheads,
618 remotephases)
643 remotephases)
619 pheads, droots = ana
644 pheads, droots = ana
620 ### Apply remote phase on local
645 ### Apply remote phase on local
621 if remotephases.get('publishing', False):
646 if remotephases.get('publishing', False):
622 _localphasemove(pushop, cheads)
647 _localphasemove(pushop, cheads)
623 else: # publish = False
648 else: # publish = False
624 _localphasemove(pushop, pheads)
649 _localphasemove(pushop, pheads)
625 _localphasemove(pushop, cheads, phases.draft)
650 _localphasemove(pushop, cheads, phases.draft)
626 ### Apply local phase on remote
651 ### Apply local phase on remote
627
652
628 if pushop.cgresult:
653 if pushop.cgresult:
629 if 'phases' in pushop.stepsdone:
654 if 'phases' in pushop.stepsdone:
630 # phases already pushed though bundle2
655 # phases already pushed though bundle2
631 return
656 return
632 outdated = pushop.outdatedphases
657 outdated = pushop.outdatedphases
633 else:
658 else:
634 outdated = pushop.fallbackoutdatedphases
659 outdated = pushop.fallbackoutdatedphases
635
660
636 pushop.stepsdone.add('phases')
661 pushop.stepsdone.add('phases')
637
662
638 # filter heads already turned public by the push
663 # filter heads already turned public by the push
639 outdated = [c for c in outdated if c.node() not in pheads]
664 outdated = [c for c in outdated if c.node() not in pheads]
640 b2caps = bundle2.bundle2caps(pushop.remote)
665 b2caps = bundle2.bundle2caps(pushop.remote)
641 if 'b2x:pushkey' in b2caps:
666 if 'b2x:pushkey' in b2caps:
642 # server supports bundle2, let's do a batched push through it
667 # server supports bundle2, let's do a batched push through it
643 #
668 #
644 # This will eventually be unified with the changesets bundle2 push
669 # This will eventually be unified with the changesets bundle2 push
645 bundler = bundle2.bundle20(pushop.ui, b2caps)
670 bundler = bundle2.bundle20(pushop.ui, b2caps)
646 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo))
671 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo))
647 bundler.newpart('b2x:replycaps', data=capsblob)
672 bundler.newpart('b2x:replycaps', data=capsblob)
648 part2node = []
673 part2node = []
649 enc = pushkey.encode
674 enc = pushkey.encode
650 for newremotehead in outdated:
675 for newremotehead in outdated:
651 part = bundler.newpart('b2x:pushkey')
676 part = bundler.newpart('b2x:pushkey')
652 part.addparam('namespace', enc('phases'))
677 part.addparam('namespace', enc('phases'))
653 part.addparam('key', enc(newremotehead.hex()))
678 part.addparam('key', enc(newremotehead.hex()))
654 part.addparam('old', enc(str(phases.draft)))
679 part.addparam('old', enc(str(phases.draft)))
655 part.addparam('new', enc(str(phases.public)))
680 part.addparam('new', enc(str(phases.public)))
656 part2node.append((part.id, newremotehead))
681 part2node.append((part.id, newremotehead))
657 stream = util.chunkbuffer(bundler.getchunks())
682 stream = util.chunkbuffer(bundler.getchunks())
658 try:
683 try:
659 reply = pushop.remote.unbundle(stream, ['force'], 'push')
684 reply = pushop.remote.unbundle(stream, ['force'], 'push')
660 op = bundle2.processbundle(pushop.repo, reply)
685 op = bundle2.processbundle(pushop.repo, reply)
661 except error.BundleValueError, exc:
686 except error.BundleValueError, exc:
662 raise util.Abort('missing support for %s' % exc)
687 raise util.Abort('missing support for %s' % exc)
663 for partid, node in part2node:
688 for partid, node in part2node:
664 partrep = op.records.getreplies(partid)
689 partrep = op.records.getreplies(partid)
665 results = partrep['pushkey']
690 results = partrep['pushkey']
666 assert len(results) <= 1
691 assert len(results) <= 1
667 msg = None
692 msg = None
668 if not results:
693 if not results:
669 msg = _('server ignored update of %s to public!\n') % node
694 msg = _('server ignored update of %s to public!\n') % node
670 elif not int(results[0]['return']):
695 elif not int(results[0]['return']):
671 msg = _('updating %s to public failed!\n') % node
696 msg = _('updating %s to public failed!\n') % node
672 if msg is not None:
697 if msg is not None:
673 pushop.ui.warn(msg)
698 pushop.ui.warn(msg)
674
699
675 else:
700 else:
676 # fallback to independant pushkey command
701 # fallback to independant pushkey command
677 for newremotehead in outdated:
702 for newremotehead in outdated:
678 r = pushop.remote.pushkey('phases',
703 r = pushop.remote.pushkey('phases',
679 newremotehead.hex(),
704 newremotehead.hex(),
680 str(phases.draft),
705 str(phases.draft),
681 str(phases.public))
706 str(phases.public))
682 if not r:
707 if not r:
683 pushop.ui.warn(_('updating %s to public failed!\n')
708 pushop.ui.warn(_('updating %s to public failed!\n')
684 % newremotehead)
709 % newremotehead)
685
710
686 def _localphasemove(pushop, nodes, phase=phases.public):
711 def _localphasemove(pushop, nodes, phase=phases.public):
687 """move <nodes> to <phase> in the local source repo"""
712 """move <nodes> to <phase> in the local source repo"""
688 if pushop.locallocked:
713 if pushop.locallocked:
689 tr = pushop.repo.transaction('push-phase-sync')
714 tr = pushop.repo.transaction('push-phase-sync')
690 try:
715 try:
691 phases.advanceboundary(pushop.repo, tr, phase, nodes)
716 phases.advanceboundary(pushop.repo, tr, phase, nodes)
692 tr.close()
717 tr.close()
693 finally:
718 finally:
694 tr.release()
719 tr.release()
695 else:
720 else:
696 # repo is not locked, do not change any phases!
721 # repo is not locked, do not change any phases!
697 # Informs the user that phases should have been moved when
722 # Informs the user that phases should have been moved when
698 # applicable.
723 # applicable.
699 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
724 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
700 phasestr = phases.phasenames[phase]
725 phasestr = phases.phasenames[phase]
701 if actualmoves:
726 if actualmoves:
702 pushop.ui.status(_('cannot lock source repo, skipping '
727 pushop.ui.status(_('cannot lock source repo, skipping '
703 'local %s phase update\n') % phasestr)
728 'local %s phase update\n') % phasestr)
704
729
705 def _pushobsolete(pushop):
730 def _pushobsolete(pushop):
706 """utility function to push obsolete markers to a remote"""
731 """utility function to push obsolete markers to a remote"""
707 if 'obsmarkers' in pushop.stepsdone:
732 if 'obsmarkers' in pushop.stepsdone:
708 return
733 return
709 pushop.ui.debug('try to push obsolete markers to remote\n')
734 pushop.ui.debug('try to push obsolete markers to remote\n')
710 repo = pushop.repo
735 repo = pushop.repo
711 remote = pushop.remote
736 remote = pushop.remote
712 pushop.stepsdone.add('obsmarkers')
737 pushop.stepsdone.add('obsmarkers')
713 if pushop.outobsmarkers:
738 if pushop.outobsmarkers:
714 rslts = []
739 rslts = []
715 remotedata = obsolete._pushkeyescape(pushop.outobsmarkers)
740 remotedata = obsolete._pushkeyescape(pushop.outobsmarkers)
716 for key in sorted(remotedata, reverse=True):
741 for key in sorted(remotedata, reverse=True):
717 # reverse sort to ensure we end with dump0
742 # reverse sort to ensure we end with dump0
718 data = remotedata[key]
743 data = remotedata[key]
719 rslts.append(remote.pushkey('obsolete', key, '', data))
744 rslts.append(remote.pushkey('obsolete', key, '', data))
720 if [r for r in rslts if not r]:
745 if [r for r in rslts if not r]:
721 msg = _('failed to push some obsolete markers!\n')
746 msg = _('failed to push some obsolete markers!\n')
722 repo.ui.warn(msg)
747 repo.ui.warn(msg)
723
748
724 def _pushbookmark(pushop):
749 def _pushbookmark(pushop):
725 """Update bookmark position on remote"""
750 """Update bookmark position on remote"""
726 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
751 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
727 return
752 return
728 pushop.stepsdone.add('bookmarks')
753 pushop.stepsdone.add('bookmarks')
729 ui = pushop.ui
754 ui = pushop.ui
730 remote = pushop.remote
755 remote = pushop.remote
731
756
732 for b, old, new in pushop.outbookmarks:
757 for b, old, new in pushop.outbookmarks:
733 action = 'update'
758 action = 'update'
734 if not old:
759 if not old:
735 action = 'export'
760 action = 'export'
736 elif not new:
761 elif not new:
737 action = 'delete'
762 action = 'delete'
738 if remote.pushkey('bookmarks', b, old, new):
763 if remote.pushkey('bookmarks', b, old, new):
739 ui.status(bookmsgmap[action][0] % b)
764 ui.status(bookmsgmap[action][0] % b)
740 else:
765 else:
741 ui.warn(bookmsgmap[action][1] % b)
766 ui.warn(bookmsgmap[action][1] % b)
742 # discovery can have set the value form invalid entry
767 # discovery can have set the value form invalid entry
743 if pushop.bkresult is not None:
768 if pushop.bkresult is not None:
744 pushop.bkresult = 1
769 pushop.bkresult = 1
745
770
746 class pulloperation(object):
771 class pulloperation(object):
747 """A object that represent a single pull operation
772 """A object that represent a single pull operation
748
773
749 It purpose is to carry push related state and very common operation.
774 It purpose is to carry push related state and very common operation.
750
775
751 A new should be created at the beginning of each pull and discarded
776 A new should be created at the beginning of each pull and discarded
752 afterward.
777 afterward.
753 """
778 """
754
779
755 def __init__(self, repo, remote, heads=None, force=False):
780 def __init__(self, repo, remote, heads=None, force=False):
756 # repo we pull into
781 # repo we pull into
757 self.repo = repo
782 self.repo = repo
758 # repo we pull from
783 # repo we pull from
759 self.remote = remote
784 self.remote = remote
760 # revision we try to pull (None is "all")
785 # revision we try to pull (None is "all")
761 self.heads = heads
786 self.heads = heads
762 # do we force pull?
787 # do we force pull?
763 self.force = force
788 self.force = force
764 # the name the pull transaction
789 # the name the pull transaction
765 self._trname = 'pull\n' + util.hidepassword(remote.url())
790 self._trname = 'pull\n' + util.hidepassword(remote.url())
766 # hold the transaction once created
791 # hold the transaction once created
767 self._tr = None
792 self._tr = None
768 # set of common changeset between local and remote before pull
793 # set of common changeset between local and remote before pull
769 self.common = None
794 self.common = None
770 # set of pulled head
795 # set of pulled head
771 self.rheads = None
796 self.rheads = None
772 # list of missing changeset to fetch remotely
797 # list of missing changeset to fetch remotely
773 self.fetch = None
798 self.fetch = None
774 # result of changegroup pulling (used as return code by pull)
799 # result of changegroup pulling (used as return code by pull)
775 self.cgresult = None
800 self.cgresult = None
776 # list of step remaining todo (related to future bundle2 usage)
801 # list of step remaining todo (related to future bundle2 usage)
777 self.todosteps = set(['changegroup', 'phases', 'obsmarkers'])
802 self.todosteps = set(['changegroup', 'phases', 'obsmarkers'])
778
803
779 @util.propertycache
804 @util.propertycache
780 def pulledsubset(self):
805 def pulledsubset(self):
781 """heads of the set of changeset target by the pull"""
806 """heads of the set of changeset target by the pull"""
782 # compute target subset
807 # compute target subset
783 if self.heads is None:
808 if self.heads is None:
784 # We pulled every thing possible
809 # We pulled every thing possible
785 # sync on everything common
810 # sync on everything common
786 c = set(self.common)
811 c = set(self.common)
787 ret = list(self.common)
812 ret = list(self.common)
788 for n in self.rheads:
813 for n in self.rheads:
789 if n not in c:
814 if n not in c:
790 ret.append(n)
815 ret.append(n)
791 return ret
816 return ret
792 else:
817 else:
793 # We pulled a specific subset
818 # We pulled a specific subset
794 # sync on this subset
819 # sync on this subset
795 return self.heads
820 return self.heads
796
821
797 def gettransaction(self):
822 def gettransaction(self):
798 """get appropriate pull transaction, creating it if needed"""
823 """get appropriate pull transaction, creating it if needed"""
799 if self._tr is None:
824 if self._tr is None:
800 self._tr = self.repo.transaction(self._trname)
825 self._tr = self.repo.transaction(self._trname)
801 return self._tr
826 return self._tr
802
827
803 def closetransaction(self):
828 def closetransaction(self):
804 """close transaction if created"""
829 """close transaction if created"""
805 if self._tr is not None:
830 if self._tr is not None:
806 self._tr.close()
831 self._tr.close()
807
832
808 def releasetransaction(self):
833 def releasetransaction(self):
809 """release transaction if created"""
834 """release transaction if created"""
810 if self._tr is not None:
835 if self._tr is not None:
811 self._tr.release()
836 self._tr.release()
812
837
813 def pull(repo, remote, heads=None, force=False, bookmarks=()):
838 def pull(repo, remote, heads=None, force=False, bookmarks=()):
814 pullop = pulloperation(repo, remote, heads, force)
839 pullop = pulloperation(repo, remote, heads, force)
815 if pullop.remote.local():
840 if pullop.remote.local():
816 missing = set(pullop.remote.requirements) - pullop.repo.supported
841 missing = set(pullop.remote.requirements) - pullop.repo.supported
817 if missing:
842 if missing:
818 msg = _("required features are not"
843 msg = _("required features are not"
819 " supported in the destination:"
844 " supported in the destination:"
820 " %s") % (', '.join(sorted(missing)))
845 " %s") % (', '.join(sorted(missing)))
821 raise util.Abort(msg)
846 raise util.Abort(msg)
822
847
823 remotebookmarks = remote.listkeys('bookmarks')
848 remotebookmarks = remote.listkeys('bookmarks')
824 lock = pullop.repo.lock()
849 lock = pullop.repo.lock()
825 try:
850 try:
826 _pulldiscovery(pullop)
851 _pulldiscovery(pullop)
827 if (pullop.repo.ui.configbool('experimental', 'bundle2-exp', False)
852 if (pullop.repo.ui.configbool('experimental', 'bundle2-exp', False)
828 and pullop.remote.capable('bundle2-exp')):
853 and pullop.remote.capable('bundle2-exp')):
829 _pullbundle2(pullop)
854 _pullbundle2(pullop)
830 if 'changegroup' in pullop.todosteps:
855 if 'changegroup' in pullop.todosteps:
831 _pullchangeset(pullop)
856 _pullchangeset(pullop)
832 if 'phases' in pullop.todosteps:
857 if 'phases' in pullop.todosteps:
833 _pullphase(pullop)
858 _pullphase(pullop)
834 if 'obsmarkers' in pullop.todosteps:
859 if 'obsmarkers' in pullop.todosteps:
835 _pullobsolete(pullop)
860 _pullobsolete(pullop)
836 pullop.closetransaction()
861 pullop.closetransaction()
837 finally:
862 finally:
838 pullop.releasetransaction()
863 pullop.releasetransaction()
839 lock.release()
864 lock.release()
840 bookmod.updatefromremote(repo.ui, repo, remotebookmarks, remote.url())
865 bookmod.updatefromremote(repo.ui, repo, remotebookmarks, remote.url())
841 # update specified bookmarks
866 # update specified bookmarks
842 if bookmarks:
867 if bookmarks:
843 marks = repo._bookmarks
868 marks = repo._bookmarks
844 writer = repo.ui.status
869 writer = repo.ui.status
845 if repo.ui.configbool('ui', 'quietbookmarkmove', False):
870 if repo.ui.configbool('ui', 'quietbookmarkmove', False):
846 writer = repo.ui.debug
871 writer = repo.ui.debug
847 for b in bookmarks:
872 for b in bookmarks:
848 # explicit pull overrides local bookmark if any
873 # explicit pull overrides local bookmark if any
849 writer(_("importing bookmark %s\n") % b)
874 writer(_("importing bookmark %s\n") % b)
850 marks[b] = repo[remotebookmarks[b]].node()
875 marks[b] = repo[remotebookmarks[b]].node()
851 marks.write()
876 marks.write()
852
877
853 return pullop.cgresult
878 return pullop.cgresult
854
879
855 def _pulldiscovery(pullop):
880 def _pulldiscovery(pullop):
856 """discovery phase for the pull
881 """discovery phase for the pull
857
882
858 Current handle changeset discovery only, will change handle all discovery
883 Current handle changeset discovery only, will change handle all discovery
859 at some point."""
884 at some point."""
860 tmp = discovery.findcommonincoming(pullop.repo.unfiltered(),
885 tmp = discovery.findcommonincoming(pullop.repo.unfiltered(),
861 pullop.remote,
886 pullop.remote,
862 heads=pullop.heads,
887 heads=pullop.heads,
863 force=pullop.force)
888 force=pullop.force)
864 pullop.common, pullop.fetch, pullop.rheads = tmp
889 pullop.common, pullop.fetch, pullop.rheads = tmp
865
890
866 def _pullbundle2(pullop):
891 def _pullbundle2(pullop):
867 """pull data using bundle2
892 """pull data using bundle2
868
893
869 For now, the only supported data are changegroup."""
894 For now, the only supported data are changegroup."""
870 remotecaps = bundle2.bundle2caps(pullop.remote)
895 remotecaps = bundle2.bundle2caps(pullop.remote)
871 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
896 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
872 # pulling changegroup
897 # pulling changegroup
873 pullop.todosteps.remove('changegroup')
898 pullop.todosteps.remove('changegroup')
874
899
875 kwargs['common'] = pullop.common
900 kwargs['common'] = pullop.common
876 kwargs['heads'] = pullop.heads or pullop.rheads
901 kwargs['heads'] = pullop.heads or pullop.rheads
877 kwargs['cg'] = pullop.fetch
902 kwargs['cg'] = pullop.fetch
878 if 'b2x:listkeys' in remotecaps:
903 if 'b2x:listkeys' in remotecaps:
879 kwargs['listkeys'] = ['phase']
904 kwargs['listkeys'] = ['phase']
880 if not pullop.fetch:
905 if not pullop.fetch:
881 pullop.repo.ui.status(_("no changes found\n"))
906 pullop.repo.ui.status(_("no changes found\n"))
882 pullop.cgresult = 0
907 pullop.cgresult = 0
883 else:
908 else:
884 if pullop.heads is None and list(pullop.common) == [nullid]:
909 if pullop.heads is None and list(pullop.common) == [nullid]:
885 pullop.repo.ui.status(_("requesting all changes\n"))
910 pullop.repo.ui.status(_("requesting all changes\n"))
886 if obsolete._enabled:
911 if obsolete._enabled:
887 remoteversions = bundle2.obsmarkersversion(remotecaps)
912 remoteversions = bundle2.obsmarkersversion(remotecaps)
888 if obsolete.commonversion(remoteversions) is not None:
913 if obsolete.commonversion(remoteversions) is not None:
889 kwargs['obsmarkers'] = True
914 kwargs['obsmarkers'] = True
890 pullop.todosteps.remove('obsmarkers')
915 pullop.todosteps.remove('obsmarkers')
891 _pullbundle2extraprepare(pullop, kwargs)
916 _pullbundle2extraprepare(pullop, kwargs)
892 if kwargs.keys() == ['format']:
917 if kwargs.keys() == ['format']:
893 return # nothing to pull
918 return # nothing to pull
894 bundle = pullop.remote.getbundle('pull', **kwargs)
919 bundle = pullop.remote.getbundle('pull', **kwargs)
895 try:
920 try:
896 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
921 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
897 except error.BundleValueError, exc:
922 except error.BundleValueError, exc:
898 raise util.Abort('missing support for %s' % exc)
923 raise util.Abort('missing support for %s' % exc)
899
924
900 if pullop.fetch:
925 if pullop.fetch:
901 assert len(op.records['changegroup']) == 1
926 assert len(op.records['changegroup']) == 1
902 pullop.cgresult = op.records['changegroup'][0]['return']
927 pullop.cgresult = op.records['changegroup'][0]['return']
903
928
904 # processing phases change
929 # processing phases change
905 for namespace, value in op.records['listkeys']:
930 for namespace, value in op.records['listkeys']:
906 if namespace == 'phases':
931 if namespace == 'phases':
907 _pullapplyphases(pullop, value)
932 _pullapplyphases(pullop, value)
908
933
909 def _pullbundle2extraprepare(pullop, kwargs):
934 def _pullbundle2extraprepare(pullop, kwargs):
910 """hook function so that extensions can extend the getbundle call"""
935 """hook function so that extensions can extend the getbundle call"""
911 pass
936 pass
912
937
913 def _pullchangeset(pullop):
938 def _pullchangeset(pullop):
914 """pull changeset from unbundle into the local repo"""
939 """pull changeset from unbundle into the local repo"""
915 # We delay the open of the transaction as late as possible so we
940 # We delay the open of the transaction as late as possible so we
916 # don't open transaction for nothing or you break future useful
941 # don't open transaction for nothing or you break future useful
917 # rollback call
942 # rollback call
918 pullop.todosteps.remove('changegroup')
943 pullop.todosteps.remove('changegroup')
919 if not pullop.fetch:
944 if not pullop.fetch:
920 pullop.repo.ui.status(_("no changes found\n"))
945 pullop.repo.ui.status(_("no changes found\n"))
921 pullop.cgresult = 0
946 pullop.cgresult = 0
922 return
947 return
923 pullop.gettransaction()
948 pullop.gettransaction()
924 if pullop.heads is None and list(pullop.common) == [nullid]:
949 if pullop.heads is None and list(pullop.common) == [nullid]:
925 pullop.repo.ui.status(_("requesting all changes\n"))
950 pullop.repo.ui.status(_("requesting all changes\n"))
926 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
951 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
927 # issue1320, avoid a race if remote changed after discovery
952 # issue1320, avoid a race if remote changed after discovery
928 pullop.heads = pullop.rheads
953 pullop.heads = pullop.rheads
929
954
930 if pullop.remote.capable('getbundle'):
955 if pullop.remote.capable('getbundle'):
931 # TODO: get bundlecaps from remote
956 # TODO: get bundlecaps from remote
932 cg = pullop.remote.getbundle('pull', common=pullop.common,
957 cg = pullop.remote.getbundle('pull', common=pullop.common,
933 heads=pullop.heads or pullop.rheads)
958 heads=pullop.heads or pullop.rheads)
934 elif pullop.heads is None:
959 elif pullop.heads is None:
935 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
960 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
936 elif not pullop.remote.capable('changegroupsubset'):
961 elif not pullop.remote.capable('changegroupsubset'):
937 raise util.Abort(_("partial pull cannot be done because "
962 raise util.Abort(_("partial pull cannot be done because "
938 "other repository doesn't support "
963 "other repository doesn't support "
939 "changegroupsubset."))
964 "changegroupsubset."))
940 else:
965 else:
941 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
966 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
942 pullop.cgresult = changegroup.addchangegroup(pullop.repo, cg, 'pull',
967 pullop.cgresult = changegroup.addchangegroup(pullop.repo, cg, 'pull',
943 pullop.remote.url())
968 pullop.remote.url())
944
969
945 def _pullphase(pullop):
970 def _pullphase(pullop):
946 # Get remote phases data from remote
971 # Get remote phases data from remote
947 remotephases = pullop.remote.listkeys('phases')
972 remotephases = pullop.remote.listkeys('phases')
948 _pullapplyphases(pullop, remotephases)
973 _pullapplyphases(pullop, remotephases)
949
974
950 def _pullapplyphases(pullop, remotephases):
975 def _pullapplyphases(pullop, remotephases):
951 """apply phase movement from observed remote state"""
976 """apply phase movement from observed remote state"""
952 pullop.todosteps.remove('phases')
977 pullop.todosteps.remove('phases')
953 publishing = bool(remotephases.get('publishing', False))
978 publishing = bool(remotephases.get('publishing', False))
954 if remotephases and not publishing:
979 if remotephases and not publishing:
955 # remote is new and unpublishing
980 # remote is new and unpublishing
956 pheads, _dr = phases.analyzeremotephases(pullop.repo,
981 pheads, _dr = phases.analyzeremotephases(pullop.repo,
957 pullop.pulledsubset,
982 pullop.pulledsubset,
958 remotephases)
983 remotephases)
959 dheads = pullop.pulledsubset
984 dheads = pullop.pulledsubset
960 else:
985 else:
961 # Remote is old or publishing all common changesets
986 # Remote is old or publishing all common changesets
962 # should be seen as public
987 # should be seen as public
963 pheads = pullop.pulledsubset
988 pheads = pullop.pulledsubset
964 dheads = []
989 dheads = []
965 unfi = pullop.repo.unfiltered()
990 unfi = pullop.repo.unfiltered()
966 phase = unfi._phasecache.phase
991 phase = unfi._phasecache.phase
967 rev = unfi.changelog.nodemap.get
992 rev = unfi.changelog.nodemap.get
968 public = phases.public
993 public = phases.public
969 draft = phases.draft
994 draft = phases.draft
970
995
971 # exclude changesets already public locally and update the others
996 # exclude changesets already public locally and update the others
972 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
997 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
973 if pheads:
998 if pheads:
974 tr = pullop.gettransaction()
999 tr = pullop.gettransaction()
975 phases.advanceboundary(pullop.repo, tr, public, pheads)
1000 phases.advanceboundary(pullop.repo, tr, public, pheads)
976
1001
977 # exclude changesets already draft locally and update the others
1002 # exclude changesets already draft locally and update the others
978 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1003 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
979 if dheads:
1004 if dheads:
980 tr = pullop.gettransaction()
1005 tr = pullop.gettransaction()
981 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1006 phases.advanceboundary(pullop.repo, tr, draft, dheads)
982
1007
983 def _pullobsolete(pullop):
1008 def _pullobsolete(pullop):
984 """utility function to pull obsolete markers from a remote
1009 """utility function to pull obsolete markers from a remote
985
1010
986 The `gettransaction` is function that return the pull transaction, creating
1011 The `gettransaction` is function that return the pull transaction, creating
987 one if necessary. We return the transaction to inform the calling code that
1012 one if necessary. We return the transaction to inform the calling code that
988 a new transaction have been created (when applicable).
1013 a new transaction have been created (when applicable).
989
1014
990 Exists mostly to allow overriding for experimentation purpose"""
1015 Exists mostly to allow overriding for experimentation purpose"""
991 pullop.todosteps.remove('obsmarkers')
1016 pullop.todosteps.remove('obsmarkers')
992 tr = None
1017 tr = None
993 if obsolete._enabled:
1018 if obsolete._enabled:
994 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1019 pullop.repo.ui.debug('fetching remote obsolete markers\n')
995 remoteobs = pullop.remote.listkeys('obsolete')
1020 remoteobs = pullop.remote.listkeys('obsolete')
996 if 'dump0' in remoteobs:
1021 if 'dump0' in remoteobs:
997 tr = pullop.gettransaction()
1022 tr = pullop.gettransaction()
998 for key in sorted(remoteobs, reverse=True):
1023 for key in sorted(remoteobs, reverse=True):
999 if key.startswith('dump'):
1024 if key.startswith('dump'):
1000 data = base85.b85decode(remoteobs[key])
1025 data = base85.b85decode(remoteobs[key])
1001 pullop.repo.obsstore.mergemarkers(tr, data)
1026 pullop.repo.obsstore.mergemarkers(tr, data)
1002 pullop.repo.invalidatevolatilesets()
1027 pullop.repo.invalidatevolatilesets()
1003 return tr
1028 return tr
1004
1029
1005 def caps20to10(repo):
1030 def caps20to10(repo):
1006 """return a set with appropriate options to use bundle20 during getbundle"""
1031 """return a set with appropriate options to use bundle20 during getbundle"""
1007 caps = set(['HG2X'])
1032 caps = set(['HG2X'])
1008 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1033 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1009 caps.add('bundle2=' + urllib.quote(capsblob))
1034 caps.add('bundle2=' + urllib.quote(capsblob))
1010 return caps
1035 return caps
1011
1036
1012 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1037 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1013 getbundle2partsorder = []
1038 getbundle2partsorder = []
1014
1039
1015 # Mapping between step name and function
1040 # Mapping between step name and function
1016 #
1041 #
1017 # This exists to help extensions wrap steps if necessary
1042 # This exists to help extensions wrap steps if necessary
1018 getbundle2partsmapping = {}
1043 getbundle2partsmapping = {}
1019
1044
1020 def getbundle2partsgenerator(stepname):
1045 def getbundle2partsgenerator(stepname):
1021 """decorator for function generating bundle2 part for getbundle
1046 """decorator for function generating bundle2 part for getbundle
1022
1047
1023 The function is added to the step -> function mapping and appended to the
1048 The function is added to the step -> function mapping and appended to the
1024 list of steps. Beware that decorated functions will be added in order
1049 list of steps. Beware that decorated functions will be added in order
1025 (this may matter).
1050 (this may matter).
1026
1051
1027 You can only use this decorator for new steps, if you want to wrap a step
1052 You can only use this decorator for new steps, if you want to wrap a step
1028 from an extension, attack the getbundle2partsmapping dictionary directly."""
1053 from an extension, attack the getbundle2partsmapping dictionary directly."""
1029 def dec(func):
1054 def dec(func):
1030 assert stepname not in getbundle2partsmapping
1055 assert stepname not in getbundle2partsmapping
1031 getbundle2partsmapping[stepname] = func
1056 getbundle2partsmapping[stepname] = func
1032 getbundle2partsorder.append(stepname)
1057 getbundle2partsorder.append(stepname)
1033 return func
1058 return func
1034 return dec
1059 return dec
1035
1060
1036 def getbundle(repo, source, heads=None, common=None, bundlecaps=None,
1061 def getbundle(repo, source, heads=None, common=None, bundlecaps=None,
1037 **kwargs):
1062 **kwargs):
1038 """return a full bundle (with potentially multiple kind of parts)
1063 """return a full bundle (with potentially multiple kind of parts)
1039
1064
1040 Could be a bundle HG10 or a bundle HG2X depending on bundlecaps
1065 Could be a bundle HG10 or a bundle HG2X depending on bundlecaps
1041 passed. For now, the bundle can contain only changegroup, but this will
1066 passed. For now, the bundle can contain only changegroup, but this will
1042 changes when more part type will be available for bundle2.
1067 changes when more part type will be available for bundle2.
1043
1068
1044 This is different from changegroup.getchangegroup that only returns an HG10
1069 This is different from changegroup.getchangegroup that only returns an HG10
1045 changegroup bundle. They may eventually get reunited in the future when we
1070 changegroup bundle. They may eventually get reunited in the future when we
1046 have a clearer idea of the API we what to query different data.
1071 have a clearer idea of the API we what to query different data.
1047
1072
1048 The implementation is at a very early stage and will get massive rework
1073 The implementation is at a very early stage and will get massive rework
1049 when the API of bundle is refined.
1074 when the API of bundle is refined.
1050 """
1075 """
1051 # bundle10 case
1076 # bundle10 case
1052 if bundlecaps is None or 'HG2X' not in bundlecaps:
1077 if bundlecaps is None or 'HG2X' not in bundlecaps:
1053 if bundlecaps and not kwargs.get('cg', True):
1078 if bundlecaps and not kwargs.get('cg', True):
1054 raise ValueError(_('request for bundle10 must include changegroup'))
1079 raise ValueError(_('request for bundle10 must include changegroup'))
1055
1080
1056 if kwargs:
1081 if kwargs:
1057 raise ValueError(_('unsupported getbundle arguments: %s')
1082 raise ValueError(_('unsupported getbundle arguments: %s')
1058 % ', '.join(sorted(kwargs.keys())))
1083 % ', '.join(sorted(kwargs.keys())))
1059 return changegroup.getchangegroup(repo, source, heads=heads,
1084 return changegroup.getchangegroup(repo, source, heads=heads,
1060 common=common, bundlecaps=bundlecaps)
1085 common=common, bundlecaps=bundlecaps)
1061
1086
1062 # bundle20 case
1087 # bundle20 case
1063 b2caps = {}
1088 b2caps = {}
1064 for bcaps in bundlecaps:
1089 for bcaps in bundlecaps:
1065 if bcaps.startswith('bundle2='):
1090 if bcaps.startswith('bundle2='):
1066 blob = urllib.unquote(bcaps[len('bundle2='):])
1091 blob = urllib.unquote(bcaps[len('bundle2='):])
1067 b2caps.update(bundle2.decodecaps(blob))
1092 b2caps.update(bundle2.decodecaps(blob))
1068 bundler = bundle2.bundle20(repo.ui, b2caps)
1093 bundler = bundle2.bundle20(repo.ui, b2caps)
1069
1094
1070 for name in getbundle2partsorder:
1095 for name in getbundle2partsorder:
1071 func = getbundle2partsmapping[name]
1096 func = getbundle2partsmapping[name]
1072 kwargs['heads'] = heads
1097 kwargs['heads'] = heads
1073 kwargs['common'] = common
1098 kwargs['common'] = common
1074 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1099 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1075 **kwargs)
1100 **kwargs)
1076
1101
1077 return util.chunkbuffer(bundler.getchunks())
1102 return util.chunkbuffer(bundler.getchunks())
1078
1103
1079 @getbundle2partsgenerator('changegroup')
1104 @getbundle2partsgenerator('changegroup')
1080 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1105 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1081 b2caps=None, heads=None, common=None, **kwargs):
1106 b2caps=None, heads=None, common=None, **kwargs):
1082 """add a changegroup part to the requested bundle"""
1107 """add a changegroup part to the requested bundle"""
1083 cg = None
1108 cg = None
1084 if kwargs.get('cg', True):
1109 if kwargs.get('cg', True):
1085 # build changegroup bundle here.
1110 # build changegroup bundle here.
1086 cg = changegroup.getchangegroup(repo, source, heads=heads,
1111 cg = changegroup.getchangegroup(repo, source, heads=heads,
1087 common=common, bundlecaps=bundlecaps)
1112 common=common, bundlecaps=bundlecaps)
1088
1113
1089 if cg:
1114 if cg:
1090 bundler.newpart('b2x:changegroup', data=cg.getchunks())
1115 bundler.newpart('b2x:changegroup', data=cg.getchunks())
1091
1116
1092 @getbundle2partsgenerator('listkeys')
1117 @getbundle2partsgenerator('listkeys')
1093 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1118 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1094 b2caps=None, **kwargs):
1119 b2caps=None, **kwargs):
1095 """add parts containing listkeys namespaces to the requested bundle"""
1120 """add parts containing listkeys namespaces to the requested bundle"""
1096 listkeys = kwargs.get('listkeys', ())
1121 listkeys = kwargs.get('listkeys', ())
1097 for namespace in listkeys:
1122 for namespace in listkeys:
1098 part = bundler.newpart('b2x:listkeys')
1123 part = bundler.newpart('b2x:listkeys')
1099 part.addparam('namespace', namespace)
1124 part.addparam('namespace', namespace)
1100 keys = repo.listkeys(namespace).items()
1125 keys = repo.listkeys(namespace).items()
1101 part.data = pushkey.encodekeys(keys)
1126 part.data = pushkey.encodekeys(keys)
1102
1127
1103 @getbundle2partsgenerator('obsmarkers')
1128 @getbundle2partsgenerator('obsmarkers')
1104 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1129 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1105 b2caps=None, heads=None, **kwargs):
1130 b2caps=None, heads=None, **kwargs):
1106 """add an obsolescence markers part to the requested bundle"""
1131 """add an obsolescence markers part to the requested bundle"""
1107 if kwargs.get('obsmarkers', False):
1132 if kwargs.get('obsmarkers', False):
1108 if heads is None:
1133 if heads is None:
1109 heads = repo.heads()
1134 heads = repo.heads()
1110 subset = [c.node() for c in repo.set('::%ln', heads)]
1135 subset = [c.node() for c in repo.set('::%ln', heads)]
1111 markers = repo.obsstore.relevantmarkers(subset)
1136 markers = repo.obsstore.relevantmarkers(subset)
1112 buildobsmarkerspart(bundler, markers)
1137 buildobsmarkerspart(bundler, markers)
1113
1138
1114 @getbundle2partsgenerator('extra')
1139 @getbundle2partsgenerator('extra')
1115 def _getbundleextrapart(bundler, repo, source, bundlecaps=None,
1140 def _getbundleextrapart(bundler, repo, source, bundlecaps=None,
1116 b2caps=None, **kwargs):
1141 b2caps=None, **kwargs):
1117 """hook function to let extensions add parts to the requested bundle"""
1142 """hook function to let extensions add parts to the requested bundle"""
1118 pass
1143 pass
1119
1144
1120 def check_heads(repo, their_heads, context):
1145 def check_heads(repo, their_heads, context):
1121 """check if the heads of a repo have been modified
1146 """check if the heads of a repo have been modified
1122
1147
1123 Used by peer for unbundling.
1148 Used by peer for unbundling.
1124 """
1149 """
1125 heads = repo.heads()
1150 heads = repo.heads()
1126 heads_hash = util.sha1(''.join(sorted(heads))).digest()
1151 heads_hash = util.sha1(''.join(sorted(heads))).digest()
1127 if not (their_heads == ['force'] or their_heads == heads or
1152 if not (their_heads == ['force'] or their_heads == heads or
1128 their_heads == ['hashed', heads_hash]):
1153 their_heads == ['hashed', heads_hash]):
1129 # someone else committed/pushed/unbundled while we
1154 # someone else committed/pushed/unbundled while we
1130 # were transferring data
1155 # were transferring data
1131 raise error.PushRaced('repository changed while %s - '
1156 raise error.PushRaced('repository changed while %s - '
1132 'please try again' % context)
1157 'please try again' % context)
1133
1158
1134 def unbundle(repo, cg, heads, source, url):
1159 def unbundle(repo, cg, heads, source, url):
1135 """Apply a bundle to a repo.
1160 """Apply a bundle to a repo.
1136
1161
1137 this function makes sure the repo is locked during the application and have
1162 this function makes sure the repo is locked during the application and have
1138 mechanism to check that no push race occurred between the creation of the
1163 mechanism to check that no push race occurred between the creation of the
1139 bundle and its application.
1164 bundle and its application.
1140
1165
1141 If the push was raced as PushRaced exception is raised."""
1166 If the push was raced as PushRaced exception is raised."""
1142 r = 0
1167 r = 0
1143 # need a transaction when processing a bundle2 stream
1168 # need a transaction when processing a bundle2 stream
1144 tr = None
1169 tr = None
1145 lock = repo.lock()
1170 lock = repo.lock()
1146 try:
1171 try:
1147 check_heads(repo, heads, 'uploading changes')
1172 check_heads(repo, heads, 'uploading changes')
1148 # push can proceed
1173 # push can proceed
1149 if util.safehasattr(cg, 'params'):
1174 if util.safehasattr(cg, 'params'):
1150 try:
1175 try:
1151 tr = repo.transaction('unbundle')
1176 tr = repo.transaction('unbundle')
1152 tr.hookargs['bundle2-exp'] = '1'
1177 tr.hookargs['bundle2-exp'] = '1'
1153 r = bundle2.processbundle(repo, cg, lambda: tr).reply
1178 r = bundle2.processbundle(repo, cg, lambda: tr).reply
1154 cl = repo.unfiltered().changelog
1179 cl = repo.unfiltered().changelog
1155 p = cl.writepending() and repo.root or ""
1180 p = cl.writepending() and repo.root or ""
1156 repo.hook('b2x-pretransactionclose', throw=True, source=source,
1181 repo.hook('b2x-pretransactionclose', throw=True, source=source,
1157 url=url, pending=p, **tr.hookargs)
1182 url=url, pending=p, **tr.hookargs)
1158 tr.close()
1183 tr.close()
1159 repo.hook('b2x-transactionclose', source=source, url=url,
1184 repo.hook('b2x-transactionclose', source=source, url=url,
1160 **tr.hookargs)
1185 **tr.hookargs)
1161 except Exception, exc:
1186 except Exception, exc:
1162 exc.duringunbundle2 = True
1187 exc.duringunbundle2 = True
1163 raise
1188 raise
1164 else:
1189 else:
1165 r = changegroup.addchangegroup(repo, cg, source, url)
1190 r = changegroup.addchangegroup(repo, cg, source, url)
1166 finally:
1191 finally:
1167 if tr is not None:
1192 if tr is not None:
1168 tr.release()
1193 tr.release()
1169 lock.release()
1194 lock.release()
1170 return r
1195 return r
@@ -1,446 +1,446
1 #require serve
1 #require serve
2
2
3 $ cat << EOF >> $HGRCPATH
3 $ cat << EOF >> $HGRCPATH
4 > [ui]
4 > [ui]
5 > logtemplate={rev}:{node|short} {desc|firstline}
5 > logtemplate={rev}:{node|short} {desc|firstline}
6 > [phases]
6 > [phases]
7 > publish=False
7 > publish=False
8 > [extensions]
8 > [extensions]
9 > EOF
9 > EOF
10 $ cat > obs.py << EOF
10 $ cat > obs.py << EOF
11 > import mercurial.obsolete
11 > import mercurial.obsolete
12 > mercurial.obsolete._enabled = True
12 > mercurial.obsolete._enabled = True
13 > EOF
13 > EOF
14 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
14 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
15
15
16 initialize
16 initialize
17
17
18 $ hg init a
18 $ hg init a
19 $ cd a
19 $ cd a
20 $ echo 'test' > test
20 $ echo 'test' > test
21 $ hg commit -Am'test'
21 $ hg commit -Am'test'
22 adding test
22 adding test
23
23
24 set bookmarks
24 set bookmarks
25
25
26 $ hg bookmark X
26 $ hg bookmark X
27 $ hg bookmark Y
27 $ hg bookmark Y
28 $ hg bookmark Z
28 $ hg bookmark Z
29
29
30 import bookmark by name
30 import bookmark by name
31
31
32 $ hg init ../b
32 $ hg init ../b
33 $ cd ../b
33 $ cd ../b
34 $ hg book Y
34 $ hg book Y
35 $ hg book
35 $ hg book
36 * Y -1:000000000000
36 * Y -1:000000000000
37 $ hg pull ../a
37 $ hg pull ../a
38 pulling from ../a
38 pulling from ../a
39 requesting all changes
39 requesting all changes
40 adding changesets
40 adding changesets
41 adding manifests
41 adding manifests
42 adding file changes
42 adding file changes
43 added 1 changesets with 1 changes to 1 files
43 added 1 changesets with 1 changes to 1 files
44 adding remote bookmark X
44 adding remote bookmark X
45 updating bookmark Y
45 updating bookmark Y
46 adding remote bookmark Z
46 adding remote bookmark Z
47 (run 'hg update' to get a working copy)
47 (run 'hg update' to get a working copy)
48 $ hg bookmarks
48 $ hg bookmarks
49 X 0:4e3505fd9583
49 X 0:4e3505fd9583
50 * Y 0:4e3505fd9583
50 * Y 0:4e3505fd9583
51 Z 0:4e3505fd9583
51 Z 0:4e3505fd9583
52 $ hg debugpushkey ../a namespaces
52 $ hg debugpushkey ../a namespaces
53 bookmarks
53 bookmarks
54 namespaces
54 namespaces
55 obsolete
55 obsolete
56 phases
56 phases
57 $ hg debugpushkey ../a bookmarks
57 $ hg debugpushkey ../a bookmarks
58 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
58 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
59 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
59 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
60 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
60 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
61 $ hg pull -B X ../a
61 $ hg pull -B X ../a
62 pulling from ../a
62 pulling from ../a
63 no changes found
63 no changes found
64 importing bookmark X
64 importing bookmark X
65 $ hg bookmark
65 $ hg bookmark
66 X 0:4e3505fd9583
66 X 0:4e3505fd9583
67 * Y 0:4e3505fd9583
67 * Y 0:4e3505fd9583
68 Z 0:4e3505fd9583
68 Z 0:4e3505fd9583
69
69
70 export bookmark by name
70 export bookmark by name
71
71
72 $ hg bookmark W
72 $ hg bookmark W
73 $ hg bookmark foo
73 $ hg bookmark foo
74 $ hg bookmark foobar
74 $ hg bookmark foobar
75 $ hg push -B W ../a
75 $ hg push -B W ../a
76 pushing to ../a
76 pushing to ../a
77 searching for changes
77 searching for changes
78 no changes found
78 no changes found
79 exporting bookmark W
79 exporting bookmark W
80 [1]
80 [1]
81 $ hg -R ../a bookmarks
81 $ hg -R ../a bookmarks
82 W -1:000000000000
82 W -1:000000000000
83 X 0:4e3505fd9583
83 X 0:4e3505fd9583
84 Y 0:4e3505fd9583
84 Y 0:4e3505fd9583
85 * Z 0:4e3505fd9583
85 * Z 0:4e3505fd9583
86
86
87 delete a remote bookmark
87 delete a remote bookmark
88
88
89 $ hg book -d W
89 $ hg book -d W
90 $ hg push -B W ../a
90 $ hg push -B W ../a
91 pushing to ../a
91 pushing to ../a
92 searching for changes
92 searching for changes
93 no changes found
93 no changes found
94 deleting remote bookmark W
94 deleting remote bookmark W
95 [1]
95 [1]
96
96
97 push/pull name that doesn't exist
97 push/pull name that doesn't exist
98
98
99 $ hg push -B badname ../a
99 $ hg push -B badname ../a
100 pushing to ../a
100 pushing to ../a
101 searching for changes
101 searching for changes
102 bookmark badname does not exist on the local or remote repository!
102 no changes found
103 no changes found
103 bookmark badname does not exist on the local or remote repository!
104 [2]
104 [2]
105 $ hg pull -B anotherbadname ../a
105 $ hg pull -B anotherbadname ../a
106 pulling from ../a
106 pulling from ../a
107 abort: remote bookmark anotherbadname not found!
107 abort: remote bookmark anotherbadname not found!
108 [255]
108 [255]
109
109
110 divergent bookmarks
110 divergent bookmarks
111
111
112 $ cd ../a
112 $ cd ../a
113 $ echo c1 > f1
113 $ echo c1 > f1
114 $ hg ci -Am1
114 $ hg ci -Am1
115 adding f1
115 adding f1
116 $ hg book -f @
116 $ hg book -f @
117 $ hg book -f X
117 $ hg book -f X
118 $ hg book
118 $ hg book
119 @ 1:0d2164f0ce0d
119 @ 1:0d2164f0ce0d
120 * X 1:0d2164f0ce0d
120 * X 1:0d2164f0ce0d
121 Y 0:4e3505fd9583
121 Y 0:4e3505fd9583
122 Z 1:0d2164f0ce0d
122 Z 1:0d2164f0ce0d
123
123
124 $ cd ../b
124 $ cd ../b
125 $ hg up
125 $ hg up
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 updating bookmark foobar
127 updating bookmark foobar
128 $ echo c2 > f2
128 $ echo c2 > f2
129 $ hg ci -Am2
129 $ hg ci -Am2
130 adding f2
130 adding f2
131 $ hg book -if @
131 $ hg book -if @
132 $ hg book -if X
132 $ hg book -if X
133 $ hg book
133 $ hg book
134 @ 1:9b140be10808
134 @ 1:9b140be10808
135 X 1:9b140be10808
135 X 1:9b140be10808
136 Y 0:4e3505fd9583
136 Y 0:4e3505fd9583
137 Z 0:4e3505fd9583
137 Z 0:4e3505fd9583
138 foo -1:000000000000
138 foo -1:000000000000
139 * foobar 1:9b140be10808
139 * foobar 1:9b140be10808
140
140
141 $ hg pull --config paths.foo=../a foo
141 $ hg pull --config paths.foo=../a foo
142 pulling from $TESTTMP/a (glob)
142 pulling from $TESTTMP/a (glob)
143 searching for changes
143 searching for changes
144 adding changesets
144 adding changesets
145 adding manifests
145 adding manifests
146 adding file changes
146 adding file changes
147 added 1 changesets with 1 changes to 1 files (+1 heads)
147 added 1 changesets with 1 changes to 1 files (+1 heads)
148 divergent bookmark @ stored as @foo
148 divergent bookmark @ stored as @foo
149 divergent bookmark X stored as X@foo
149 divergent bookmark X stored as X@foo
150 updating bookmark Z
150 updating bookmark Z
151 (run 'hg heads' to see heads, 'hg merge' to merge)
151 (run 'hg heads' to see heads, 'hg merge' to merge)
152 $ hg book
152 $ hg book
153 @ 1:9b140be10808
153 @ 1:9b140be10808
154 @foo 2:0d2164f0ce0d
154 @foo 2:0d2164f0ce0d
155 X 1:9b140be10808
155 X 1:9b140be10808
156 X@foo 2:0d2164f0ce0d
156 X@foo 2:0d2164f0ce0d
157 Y 0:4e3505fd9583
157 Y 0:4e3505fd9583
158 Z 2:0d2164f0ce0d
158 Z 2:0d2164f0ce0d
159 foo -1:000000000000
159 foo -1:000000000000
160 * foobar 1:9b140be10808
160 * foobar 1:9b140be10808
161 $ hg push -f ../a
161 $ hg push -f ../a
162 pushing to ../a
162 pushing to ../a
163 searching for changes
163 searching for changes
164 adding changesets
164 adding changesets
165 adding manifests
165 adding manifests
166 adding file changes
166 adding file changes
167 added 1 changesets with 1 changes to 1 files (+1 heads)
167 added 1 changesets with 1 changes to 1 files (+1 heads)
168 $ hg -R ../a book
168 $ hg -R ../a book
169 @ 1:0d2164f0ce0d
169 @ 1:0d2164f0ce0d
170 * X 1:0d2164f0ce0d
170 * X 1:0d2164f0ce0d
171 Y 0:4e3505fd9583
171 Y 0:4e3505fd9583
172 Z 1:0d2164f0ce0d
172 Z 1:0d2164f0ce0d
173
173
174 revsets should not ignore divergent bookmarks
174 revsets should not ignore divergent bookmarks
175
175
176 $ hg bookmark -fr 1 Z
176 $ hg bookmark -fr 1 Z
177 $ hg log -r 'bookmark()' --template '{rev}:{node|short} {bookmarks}\n'
177 $ hg log -r 'bookmark()' --template '{rev}:{node|short} {bookmarks}\n'
178 0:4e3505fd9583 Y
178 0:4e3505fd9583 Y
179 1:9b140be10808 @ X Z foobar
179 1:9b140be10808 @ X Z foobar
180 2:0d2164f0ce0d @foo X@foo
180 2:0d2164f0ce0d @foo X@foo
181 $ hg log -r 'bookmark("X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
181 $ hg log -r 'bookmark("X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
182 2:0d2164f0ce0d @foo X@foo
182 2:0d2164f0ce0d @foo X@foo
183 $ hg log -r 'bookmark("re:X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
183 $ hg log -r 'bookmark("re:X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
184 2:0d2164f0ce0d @foo X@foo
184 2:0d2164f0ce0d @foo X@foo
185
185
186 update a remote bookmark from a non-head to a head
186 update a remote bookmark from a non-head to a head
187
187
188 $ hg up -q Y
188 $ hg up -q Y
189 $ echo c3 > f2
189 $ echo c3 > f2
190 $ hg ci -Am3
190 $ hg ci -Am3
191 adding f2
191 adding f2
192 created new head
192 created new head
193 $ hg push ../a
193 $ hg push ../a
194 pushing to ../a
194 pushing to ../a
195 searching for changes
195 searching for changes
196 adding changesets
196 adding changesets
197 adding manifests
197 adding manifests
198 adding file changes
198 adding file changes
199 added 1 changesets with 1 changes to 1 files (+1 heads)
199 added 1 changesets with 1 changes to 1 files (+1 heads)
200 updating bookmark Y
200 updating bookmark Y
201 $ hg -R ../a book
201 $ hg -R ../a book
202 @ 1:0d2164f0ce0d
202 @ 1:0d2164f0ce0d
203 * X 1:0d2164f0ce0d
203 * X 1:0d2164f0ce0d
204 Y 3:f6fc62dde3c0
204 Y 3:f6fc62dde3c0
205 Z 1:0d2164f0ce0d
205 Z 1:0d2164f0ce0d
206
206
207 update a bookmark in the middle of a client pulling changes
207 update a bookmark in the middle of a client pulling changes
208
208
209 $ cd ..
209 $ cd ..
210 $ hg clone -q a pull-race
210 $ hg clone -q a pull-race
211 $ hg clone -q pull-race pull-race2
211 $ hg clone -q pull-race pull-race2
212 $ cd pull-race
212 $ cd pull-race
213 $ hg up -q Y
213 $ hg up -q Y
214 $ echo c4 > f2
214 $ echo c4 > f2
215 $ hg ci -Am4
215 $ hg ci -Am4
216 $ echo c5 > f3
216 $ echo c5 > f3
217 $ cat <<EOF > .hg/hgrc
217 $ cat <<EOF > .hg/hgrc
218 > [hooks]
218 > [hooks]
219 > outgoing.makecommit = hg ci -Am5; echo committed in pull-race
219 > outgoing.makecommit = hg ci -Am5; echo committed in pull-race
220 > EOF
220 > EOF
221 $ cd ../pull-race2
221 $ cd ../pull-race2
222 $ hg pull
222 $ hg pull
223 pulling from $TESTTMP/pull-race (glob)
223 pulling from $TESTTMP/pull-race (glob)
224 searching for changes
224 searching for changes
225 adding changesets
225 adding changesets
226 adding f3
226 adding f3
227 committed in pull-race
227 committed in pull-race
228 adding manifests
228 adding manifests
229 adding file changes
229 adding file changes
230 added 1 changesets with 1 changes to 1 files
230 added 1 changesets with 1 changes to 1 files
231 updating bookmark Y
231 updating bookmark Y
232 (run 'hg update' to get a working copy)
232 (run 'hg update' to get a working copy)
233 $ hg book
233 $ hg book
234 * @ 1:0d2164f0ce0d
234 * @ 1:0d2164f0ce0d
235 X 1:0d2164f0ce0d
235 X 1:0d2164f0ce0d
236 Y 4:b0a5eff05604
236 Y 4:b0a5eff05604
237 Z 1:0d2164f0ce0d
237 Z 1:0d2164f0ce0d
238 $ cd ../b
238 $ cd ../b
239
239
240 diverging a remote bookmark fails
240 diverging a remote bookmark fails
241
241
242 $ hg up -q 4e3505fd9583
242 $ hg up -q 4e3505fd9583
243 $ echo c4 > f2
243 $ echo c4 > f2
244 $ hg ci -Am4
244 $ hg ci -Am4
245 adding f2
245 adding f2
246 created new head
246 created new head
247 $ echo c5 > f2
247 $ echo c5 > f2
248 $ hg ci -Am5
248 $ hg ci -Am5
249 $ hg log -G
249 $ hg log -G
250 @ 5:c922c0139ca0 5
250 @ 5:c922c0139ca0 5
251 |
251 |
252 o 4:4efff6d98829 4
252 o 4:4efff6d98829 4
253 |
253 |
254 | o 3:f6fc62dde3c0 3
254 | o 3:f6fc62dde3c0 3
255 |/
255 |/
256 | o 2:0d2164f0ce0d 1
256 | o 2:0d2164f0ce0d 1
257 |/
257 |/
258 | o 1:9b140be10808 2
258 | o 1:9b140be10808 2
259 |/
259 |/
260 o 0:4e3505fd9583 test
260 o 0:4e3505fd9583 test
261
261
262
262
263 $ hg book -f Y
263 $ hg book -f Y
264
264
265 $ cat <<EOF > ../a/.hg/hgrc
265 $ cat <<EOF > ../a/.hg/hgrc
266 > [web]
266 > [web]
267 > push_ssl = false
267 > push_ssl = false
268 > allow_push = *
268 > allow_push = *
269 > EOF
269 > EOF
270
270
271 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
271 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
272 $ cat ../hg2.pid >> $DAEMON_PIDS
272 $ cat ../hg2.pid >> $DAEMON_PIDS
273
273
274 $ hg push http://localhost:$HGPORT2/
274 $ hg push http://localhost:$HGPORT2/
275 pushing to http://localhost:$HGPORT2/
275 pushing to http://localhost:$HGPORT2/
276 searching for changes
276 searching for changes
277 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
277 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
278 (merge or see "hg help push" for details about pushing new heads)
278 (merge or see "hg help push" for details about pushing new heads)
279 [255]
279 [255]
280 $ hg -R ../a book
280 $ hg -R ../a book
281 @ 1:0d2164f0ce0d
281 @ 1:0d2164f0ce0d
282 * X 1:0d2164f0ce0d
282 * X 1:0d2164f0ce0d
283 Y 3:f6fc62dde3c0
283 Y 3:f6fc62dde3c0
284 Z 1:0d2164f0ce0d
284 Z 1:0d2164f0ce0d
285
285
286
286
287 Unrelated marker does not alter the decision
287 Unrelated marker does not alter the decision
288
288
289 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
289 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
290 $ hg push http://localhost:$HGPORT2/
290 $ hg push http://localhost:$HGPORT2/
291 pushing to http://localhost:$HGPORT2/
291 pushing to http://localhost:$HGPORT2/
292 searching for changes
292 searching for changes
293 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
293 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
294 (merge or see "hg help push" for details about pushing new heads)
294 (merge or see "hg help push" for details about pushing new heads)
295 [255]
295 [255]
296 $ hg -R ../a book
296 $ hg -R ../a book
297 @ 1:0d2164f0ce0d
297 @ 1:0d2164f0ce0d
298 * X 1:0d2164f0ce0d
298 * X 1:0d2164f0ce0d
299 Y 3:f6fc62dde3c0
299 Y 3:f6fc62dde3c0
300 Z 1:0d2164f0ce0d
300 Z 1:0d2164f0ce0d
301
301
302 Update to a successor works
302 Update to a successor works
303
303
304 $ hg id --debug -r 3
304 $ hg id --debug -r 3
305 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
305 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
306 $ hg id --debug -r 4
306 $ hg id --debug -r 4
307 4efff6d98829d9c824c621afd6e3f01865f5439f
307 4efff6d98829d9c824c621afd6e3f01865f5439f
308 $ hg id --debug -r 5
308 $ hg id --debug -r 5
309 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
309 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
310 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
310 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
311 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
311 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
312 $ hg push http://localhost:$HGPORT2/
312 $ hg push http://localhost:$HGPORT2/
313 pushing to http://localhost:$HGPORT2/
313 pushing to http://localhost:$HGPORT2/
314 searching for changes
314 searching for changes
315 remote: adding changesets
315 remote: adding changesets
316 remote: adding manifests
316 remote: adding manifests
317 remote: adding file changes
317 remote: adding file changes
318 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
318 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
319 updating bookmark Y
319 updating bookmark Y
320 $ hg -R ../a book
320 $ hg -R ../a book
321 @ 1:0d2164f0ce0d
321 @ 1:0d2164f0ce0d
322 * X 1:0d2164f0ce0d
322 * X 1:0d2164f0ce0d
323 Y 5:c922c0139ca0
323 Y 5:c922c0139ca0
324 Z 1:0d2164f0ce0d
324 Z 1:0d2164f0ce0d
325
325
326 hgweb
326 hgweb
327
327
328 $ cat <<EOF > .hg/hgrc
328 $ cat <<EOF > .hg/hgrc
329 > [web]
329 > [web]
330 > push_ssl = false
330 > push_ssl = false
331 > allow_push = *
331 > allow_push = *
332 > EOF
332 > EOF
333
333
334 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
334 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
335 $ cat ../hg.pid >> $DAEMON_PIDS
335 $ cat ../hg.pid >> $DAEMON_PIDS
336 $ cd ../a
336 $ cd ../a
337
337
338 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
338 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
339 bookmarks
339 bookmarks
340 namespaces
340 namespaces
341 obsolete
341 obsolete
342 phases
342 phases
343 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
343 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
344 @ 9b140be1080824d768c5a4691a564088eede71f9
344 @ 9b140be1080824d768c5a4691a564088eede71f9
345 X 9b140be1080824d768c5a4691a564088eede71f9
345 X 9b140be1080824d768c5a4691a564088eede71f9
346 Y c922c0139ca03858f655e4a2af4dd02796a63969
346 Y c922c0139ca03858f655e4a2af4dd02796a63969
347 Z 9b140be1080824d768c5a4691a564088eede71f9
347 Z 9b140be1080824d768c5a4691a564088eede71f9
348 foo 0000000000000000000000000000000000000000
348 foo 0000000000000000000000000000000000000000
349 foobar 9b140be1080824d768c5a4691a564088eede71f9
349 foobar 9b140be1080824d768c5a4691a564088eede71f9
350 $ hg out -B http://localhost:$HGPORT/
350 $ hg out -B http://localhost:$HGPORT/
351 comparing with http://localhost:$HGPORT/
351 comparing with http://localhost:$HGPORT/
352 searching for changed bookmarks
352 searching for changed bookmarks
353 no changed bookmarks found
353 no changed bookmarks found
354 [1]
354 [1]
355 $ hg push -B Z http://localhost:$HGPORT/
355 $ hg push -B Z http://localhost:$HGPORT/
356 pushing to http://localhost:$HGPORT/
356 pushing to http://localhost:$HGPORT/
357 searching for changes
357 searching for changes
358 no changes found
358 no changes found
359 exporting bookmark Z
359 updating bookmark Z
360 [1]
360 [1]
361 $ hg book -d Z
361 $ hg book -d Z
362 $ hg in -B http://localhost:$HGPORT/
362 $ hg in -B http://localhost:$HGPORT/
363 comparing with http://localhost:$HGPORT/
363 comparing with http://localhost:$HGPORT/
364 searching for changed bookmarks
364 searching for changed bookmarks
365 Z 0d2164f0ce0d
365 Z 0d2164f0ce0d
366 foo 000000000000
366 foo 000000000000
367 foobar 9b140be10808
367 foobar 9b140be10808
368 $ hg pull -B Z http://localhost:$HGPORT/
368 $ hg pull -B Z http://localhost:$HGPORT/
369 pulling from http://localhost:$HGPORT/
369 pulling from http://localhost:$HGPORT/
370 no changes found
370 no changes found
371 divergent bookmark @ stored as @1
371 divergent bookmark @ stored as @1
372 divergent bookmark X stored as X@1
372 divergent bookmark X stored as X@1
373 adding remote bookmark Z
373 adding remote bookmark Z
374 adding remote bookmark foo
374 adding remote bookmark foo
375 adding remote bookmark foobar
375 adding remote bookmark foobar
376 importing bookmark Z
376 importing bookmark Z
377 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
377 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
378 requesting all changes
378 requesting all changes
379 adding changesets
379 adding changesets
380 adding manifests
380 adding manifests
381 adding file changes
381 adding file changes
382 added 5 changesets with 5 changes to 3 files (+2 heads)
382 added 5 changesets with 5 changes to 3 files (+2 heads)
383 updating to bookmark @
383 updating to bookmark @
384 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
384 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
385 $ hg -R cloned-bookmarks bookmarks
385 $ hg -R cloned-bookmarks bookmarks
386 * @ 1:9b140be10808
386 * @ 1:9b140be10808
387 X 1:9b140be10808
387 X 1:9b140be10808
388 Y 4:c922c0139ca0
388 Y 4:c922c0139ca0
389 Z 2:0d2164f0ce0d
389 Z 2:0d2164f0ce0d
390 foo -1:000000000000
390 foo -1:000000000000
391 foobar 1:9b140be10808
391 foobar 1:9b140be10808
392
392
393 $ cd ..
393 $ cd ..
394
394
395 Pushing a bookmark should only push the changes required by that
395 Pushing a bookmark should only push the changes required by that
396 bookmark, not all outgoing changes:
396 bookmark, not all outgoing changes:
397 $ hg clone http://localhost:$HGPORT/ addmarks
397 $ hg clone http://localhost:$HGPORT/ addmarks
398 requesting all changes
398 requesting all changes
399 adding changesets
399 adding changesets
400 adding manifests
400 adding manifests
401 adding file changes
401 adding file changes
402 added 5 changesets with 5 changes to 3 files (+2 heads)
402 added 5 changesets with 5 changes to 3 files (+2 heads)
403 updating to bookmark @
403 updating to bookmark @
404 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
404 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
405 $ cd addmarks
405 $ cd addmarks
406 $ echo foo > foo
406 $ echo foo > foo
407 $ hg add foo
407 $ hg add foo
408 $ hg commit -m 'add foo'
408 $ hg commit -m 'add foo'
409 $ echo bar > bar
409 $ echo bar > bar
410 $ hg add bar
410 $ hg add bar
411 $ hg commit -m 'add bar'
411 $ hg commit -m 'add bar'
412 $ hg co "tip^"
412 $ hg co "tip^"
413 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
413 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
414 (leaving bookmark @)
414 (leaving bookmark @)
415 $ hg book add-foo
415 $ hg book add-foo
416 $ hg book -r tip add-bar
416 $ hg book -r tip add-bar
417 Note: this push *must* push only a single changeset, as that's the point
417 Note: this push *must* push only a single changeset, as that's the point
418 of this test.
418 of this test.
419 $ hg push -B add-foo --traceback
419 $ hg push -B add-foo --traceback
420 pushing to http://localhost:$HGPORT/
420 pushing to http://localhost:$HGPORT/
421 searching for changes
421 searching for changes
422 remote: adding changesets
422 remote: adding changesets
423 remote: adding manifests
423 remote: adding manifests
424 remote: adding file changes
424 remote: adding file changes
425 remote: added 1 changesets with 1 changes to 1 files
425 remote: added 1 changesets with 1 changes to 1 files
426 exporting bookmark add-foo
426 exporting bookmark add-foo
427
427
428 pushing a new bookmark on a new head does not require -f if -B is specified
428 pushing a new bookmark on a new head does not require -f if -B is specified
429
429
430 $ hg up -q X
430 $ hg up -q X
431 $ hg book W
431 $ hg book W
432 $ echo c5 > f2
432 $ echo c5 > f2
433 $ hg ci -Am5
433 $ hg ci -Am5
434 created new head
434 created new head
435 $ hg push -B W
435 $ hg push -B W
436 pushing to http://localhost:$HGPORT/
436 pushing to http://localhost:$HGPORT/
437 searching for changes
437 searching for changes
438 remote: adding changesets
438 remote: adding changesets
439 remote: adding manifests
439 remote: adding manifests
440 remote: adding file changes
440 remote: adding file changes
441 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
441 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
442 exporting bookmark W
442 exporting bookmark W
443 $ hg -R ../b id -r W
443 $ hg -R ../b id -r W
444 cc978a373a53 tip W
444 cc978a373a53 tip W
445
445
446 $ cd ..
446 $ cd ..
@@ -1,1198 +1,1195
1
1
2 $ getmainid() {
2 $ getmainid() {
3 > hg -R main log --template '{node}\n' --rev "$1"
3 > hg -R main log --template '{node}\n' --rev "$1"
4 > }
4 > }
5
5
6 Create an extension to test bundle2 API
6 Create an extension to test bundle2 API
7
7
8 $ cat > bundle2.py << EOF
8 $ cat > bundle2.py << EOF
9 > """A small extension to test bundle2 implementation
9 > """A small extension to test bundle2 implementation
10 >
10 >
11 > Current bundle2 implementation is far too limited to be used in any core
11 > Current bundle2 implementation is far too limited to be used in any core
12 > code. We still need to be able to test it while it grow up.
12 > code. We still need to be able to test it while it grow up.
13 > """
13 > """
14 >
14 >
15 > import sys, os
15 > import sys, os
16 > from mercurial import cmdutil
16 > from mercurial import cmdutil
17 > from mercurial import util
17 > from mercurial import util
18 > from mercurial import bundle2
18 > from mercurial import bundle2
19 > from mercurial import scmutil
19 > from mercurial import scmutil
20 > from mercurial import discovery
20 > from mercurial import discovery
21 > from mercurial import changegroup
21 > from mercurial import changegroup
22 > from mercurial import error
22 > from mercurial import error
23 > from mercurial import obsolete
23 > from mercurial import obsolete
24 >
24 >
25 > obsolete._enabled = True
25 > obsolete._enabled = True
26 >
26 >
27 > try:
27 > try:
28 > import msvcrt
28 > import msvcrt
29 > msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
29 > msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
30 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
30 > msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
31 > msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
31 > msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
32 > except ImportError:
32 > except ImportError:
33 > pass
33 > pass
34 >
34 >
35 > cmdtable = {}
35 > cmdtable = {}
36 > command = cmdutil.command(cmdtable)
36 > command = cmdutil.command(cmdtable)
37 >
37 >
38 > ELEPHANTSSONG = """Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
38 > ELEPHANTSSONG = """Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
39 > Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
39 > Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
40 > Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko."""
40 > Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko."""
41 > assert len(ELEPHANTSSONG) == 178 # future test say 178 bytes, trust it.
41 > assert len(ELEPHANTSSONG) == 178 # future test say 178 bytes, trust it.
42 >
42 >
43 > @bundle2.parthandler('test:song')
43 > @bundle2.parthandler('test:song')
44 > def songhandler(op, part):
44 > def songhandler(op, part):
45 > """handle a "test:song" bundle2 part, printing the lyrics on stdin"""
45 > """handle a "test:song" bundle2 part, printing the lyrics on stdin"""
46 > op.ui.write('The choir starts singing:\n')
46 > op.ui.write('The choir starts singing:\n')
47 > verses = 0
47 > verses = 0
48 > for line in part.read().split('\n'):
48 > for line in part.read().split('\n'):
49 > op.ui.write(' %s\n' % line)
49 > op.ui.write(' %s\n' % line)
50 > verses += 1
50 > verses += 1
51 > op.records.add('song', {'verses': verses})
51 > op.records.add('song', {'verses': verses})
52 >
52 >
53 > @bundle2.parthandler('test:ping')
53 > @bundle2.parthandler('test:ping')
54 > def pinghandler(op, part):
54 > def pinghandler(op, part):
55 > op.ui.write('received ping request (id %i)\n' % part.id)
55 > op.ui.write('received ping request (id %i)\n' % part.id)
56 > if op.reply is not None and 'ping-pong' in op.reply.capabilities:
56 > if op.reply is not None and 'ping-pong' in op.reply.capabilities:
57 > op.ui.write_err('replying to ping request (id %i)\n' % part.id)
57 > op.ui.write_err('replying to ping request (id %i)\n' % part.id)
58 > op.reply.newpart('test:pong', [('in-reply-to', str(part.id))])
58 > op.reply.newpart('test:pong', [('in-reply-to', str(part.id))])
59 >
59 >
60 > @bundle2.parthandler('test:debugreply')
60 > @bundle2.parthandler('test:debugreply')
61 > def debugreply(op, part):
61 > def debugreply(op, part):
62 > """print data about the capacity of the bundle reply"""
62 > """print data about the capacity of the bundle reply"""
63 > if op.reply is None:
63 > if op.reply is None:
64 > op.ui.write('debugreply: no reply\n')
64 > op.ui.write('debugreply: no reply\n')
65 > else:
65 > else:
66 > op.ui.write('debugreply: capabilities:\n')
66 > op.ui.write('debugreply: capabilities:\n')
67 > for cap in sorted(op.reply.capabilities):
67 > for cap in sorted(op.reply.capabilities):
68 > op.ui.write('debugreply: %r\n' % cap)
68 > op.ui.write('debugreply: %r\n' % cap)
69 > for val in op.reply.capabilities[cap]:
69 > for val in op.reply.capabilities[cap]:
70 > op.ui.write('debugreply: %r\n' % val)
70 > op.ui.write('debugreply: %r\n' % val)
71 >
71 >
72 > @command('bundle2',
72 > @command('bundle2',
73 > [('', 'param', [], 'stream level parameter'),
73 > [('', 'param', [], 'stream level parameter'),
74 > ('', 'unknown', False, 'include an unknown mandatory part in the bundle'),
74 > ('', 'unknown', False, 'include an unknown mandatory part in the bundle'),
75 > ('', 'unknownparams', False, 'include an unknown part parameters in the bundle'),
75 > ('', 'unknownparams', False, 'include an unknown part parameters in the bundle'),
76 > ('', 'parts', False, 'include some arbitrary parts to the bundle'),
76 > ('', 'parts', False, 'include some arbitrary parts to the bundle'),
77 > ('', 'reply', False, 'produce a reply bundle'),
77 > ('', 'reply', False, 'produce a reply bundle'),
78 > ('', 'pushrace', False, 'includes a check:head part with unknown nodes'),
78 > ('', 'pushrace', False, 'includes a check:head part with unknown nodes'),
79 > ('r', 'rev', [], 'includes those changeset in the bundle'),],
79 > ('r', 'rev', [], 'includes those changeset in the bundle'),],
80 > '[OUTPUTFILE]')
80 > '[OUTPUTFILE]')
81 > def cmdbundle2(ui, repo, path=None, **opts):
81 > def cmdbundle2(ui, repo, path=None, **opts):
82 > """write a bundle2 container on standard ouput"""
82 > """write a bundle2 container on standard ouput"""
83 > bundler = bundle2.bundle20(ui)
83 > bundler = bundle2.bundle20(ui)
84 > for p in opts['param']:
84 > for p in opts['param']:
85 > p = p.split('=', 1)
85 > p = p.split('=', 1)
86 > try:
86 > try:
87 > bundler.addparam(*p)
87 > bundler.addparam(*p)
88 > except ValueError, exc:
88 > except ValueError, exc:
89 > raise util.Abort('%s' % exc)
89 > raise util.Abort('%s' % exc)
90 >
90 >
91 > if opts['reply']:
91 > if opts['reply']:
92 > capsstring = 'ping-pong\nelephants=babar,celeste\ncity%3D%21=celeste%2Cville'
92 > capsstring = 'ping-pong\nelephants=babar,celeste\ncity%3D%21=celeste%2Cville'
93 > bundler.newpart('b2x:replycaps', data=capsstring)
93 > bundler.newpart('b2x:replycaps', data=capsstring)
94 >
94 >
95 > if opts['pushrace']:
95 > if opts['pushrace']:
96 > # also serve to test the assignement of data outside of init
96 > # also serve to test the assignement of data outside of init
97 > part = bundler.newpart('b2x:check:heads')
97 > part = bundler.newpart('b2x:check:heads')
98 > part.data = '01234567890123456789'
98 > part.data = '01234567890123456789'
99 >
99 >
100 > revs = opts['rev']
100 > revs = opts['rev']
101 > if 'rev' in opts:
101 > if 'rev' in opts:
102 > revs = scmutil.revrange(repo, opts['rev'])
102 > revs = scmutil.revrange(repo, opts['rev'])
103 > if revs:
103 > if revs:
104 > # very crude version of a changegroup part creation
104 > # very crude version of a changegroup part creation
105 > bundled = repo.revs('%ld::%ld', revs, revs)
105 > bundled = repo.revs('%ld::%ld', revs, revs)
106 > headmissing = [c.node() for c in repo.set('heads(%ld)', revs)]
106 > headmissing = [c.node() for c in repo.set('heads(%ld)', revs)]
107 > headcommon = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)]
107 > headcommon = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)]
108 > outgoing = discovery.outgoing(repo.changelog, headcommon, headmissing)
108 > outgoing = discovery.outgoing(repo.changelog, headcommon, headmissing)
109 > cg = changegroup.getlocalchangegroup(repo, 'test:bundle2', outgoing, None)
109 > cg = changegroup.getlocalchangegroup(repo, 'test:bundle2', outgoing, None)
110 > bundler.newpart('b2x:changegroup', data=cg.getchunks())
110 > bundler.newpart('b2x:changegroup', data=cg.getchunks())
111 >
111 >
112 > if opts['parts']:
112 > if opts['parts']:
113 > bundler.newpart('test:empty')
113 > bundler.newpart('test:empty')
114 > # add a second one to make sure we handle multiple parts
114 > # add a second one to make sure we handle multiple parts
115 > bundler.newpart('test:empty')
115 > bundler.newpart('test:empty')
116 > bundler.newpart('test:song', data=ELEPHANTSSONG)
116 > bundler.newpart('test:song', data=ELEPHANTSSONG)
117 > bundler.newpart('test:debugreply')
117 > bundler.newpart('test:debugreply')
118 > mathpart = bundler.newpart('test:math')
118 > mathpart = bundler.newpart('test:math')
119 > mathpart.addparam('pi', '3.14')
119 > mathpart.addparam('pi', '3.14')
120 > mathpart.addparam('e', '2.72')
120 > mathpart.addparam('e', '2.72')
121 > mathpart.addparam('cooking', 'raw', mandatory=False)
121 > mathpart.addparam('cooking', 'raw', mandatory=False)
122 > mathpart.data = '42'
122 > mathpart.data = '42'
123 > # advisory known part with unknown mandatory param
123 > # advisory known part with unknown mandatory param
124 > bundler.newpart('test:song', [('randomparam','')])
124 > bundler.newpart('test:song', [('randomparam','')])
125 > if opts['unknown']:
125 > if opts['unknown']:
126 > bundler.newpart('test:UNKNOWN', data='some random content')
126 > bundler.newpart('test:UNKNOWN', data='some random content')
127 > if opts['unknownparams']:
127 > if opts['unknownparams']:
128 > bundler.newpart('test:SONG', [('randomparams', '')])
128 > bundler.newpart('test:SONG', [('randomparams', '')])
129 > if opts['parts']:
129 > if opts['parts']:
130 > bundler.newpart('test:ping')
130 > bundler.newpart('test:ping')
131 >
131 >
132 > if path is None:
132 > if path is None:
133 > file = sys.stdout
133 > file = sys.stdout
134 > else:
134 > else:
135 > file = open(path, 'wb')
135 > file = open(path, 'wb')
136 >
136 >
137 > for chunk in bundler.getchunks():
137 > for chunk in bundler.getchunks():
138 > file.write(chunk)
138 > file.write(chunk)
139 >
139 >
140 > @command('unbundle2', [], '')
140 > @command('unbundle2', [], '')
141 > def cmdunbundle2(ui, repo, replypath=None):
141 > def cmdunbundle2(ui, repo, replypath=None):
142 > """process a bundle2 stream from stdin on the current repo"""
142 > """process a bundle2 stream from stdin on the current repo"""
143 > try:
143 > try:
144 > tr = None
144 > tr = None
145 > lock = repo.lock()
145 > lock = repo.lock()
146 > tr = repo.transaction('processbundle')
146 > tr = repo.transaction('processbundle')
147 > try:
147 > try:
148 > unbundler = bundle2.unbundle20(ui, sys.stdin)
148 > unbundler = bundle2.unbundle20(ui, sys.stdin)
149 > op = bundle2.processbundle(repo, unbundler, lambda: tr)
149 > op = bundle2.processbundle(repo, unbundler, lambda: tr)
150 > tr.close()
150 > tr.close()
151 > except error.BundleValueError, exc:
151 > except error.BundleValueError, exc:
152 > raise util.Abort('missing support for %s' % exc)
152 > raise util.Abort('missing support for %s' % exc)
153 > except error.PushRaced, exc:
153 > except error.PushRaced, exc:
154 > raise util.Abort('push race: %s' % exc)
154 > raise util.Abort('push race: %s' % exc)
155 > finally:
155 > finally:
156 > if tr is not None:
156 > if tr is not None:
157 > tr.release()
157 > tr.release()
158 > lock.release()
158 > lock.release()
159 > remains = sys.stdin.read()
159 > remains = sys.stdin.read()
160 > ui.write('%i unread bytes\n' % len(remains))
160 > ui.write('%i unread bytes\n' % len(remains))
161 > if op.records['song']:
161 > if op.records['song']:
162 > totalverses = sum(r['verses'] for r in op.records['song'])
162 > totalverses = sum(r['verses'] for r in op.records['song'])
163 > ui.write('%i total verses sung\n' % totalverses)
163 > ui.write('%i total verses sung\n' % totalverses)
164 > for rec in op.records['changegroup']:
164 > for rec in op.records['changegroup']:
165 > ui.write('addchangegroup return: %i\n' % rec['return'])
165 > ui.write('addchangegroup return: %i\n' % rec['return'])
166 > if op.reply is not None and replypath is not None:
166 > if op.reply is not None and replypath is not None:
167 > file = open(replypath, 'wb')
167 > file = open(replypath, 'wb')
168 > for chunk in op.reply.getchunks():
168 > for chunk in op.reply.getchunks():
169 > file.write(chunk)
169 > file.write(chunk)
170 >
170 >
171 > @command('statbundle2', [], '')
171 > @command('statbundle2', [], '')
172 > def cmdstatbundle2(ui, repo):
172 > def cmdstatbundle2(ui, repo):
173 > """print statistic on the bundle2 container read from stdin"""
173 > """print statistic on the bundle2 container read from stdin"""
174 > unbundler = bundle2.unbundle20(ui, sys.stdin)
174 > unbundler = bundle2.unbundle20(ui, sys.stdin)
175 > try:
175 > try:
176 > params = unbundler.params
176 > params = unbundler.params
177 > except error.BundleValueError, exc:
177 > except error.BundleValueError, exc:
178 > raise util.Abort('unknown parameters: %s' % exc)
178 > raise util.Abort('unknown parameters: %s' % exc)
179 > ui.write('options count: %i\n' % len(params))
179 > ui.write('options count: %i\n' % len(params))
180 > for key in sorted(params):
180 > for key in sorted(params):
181 > ui.write('- %s\n' % key)
181 > ui.write('- %s\n' % key)
182 > value = params[key]
182 > value = params[key]
183 > if value is not None:
183 > if value is not None:
184 > ui.write(' %s\n' % value)
184 > ui.write(' %s\n' % value)
185 > count = 0
185 > count = 0
186 > for p in unbundler.iterparts():
186 > for p in unbundler.iterparts():
187 > count += 1
187 > count += 1
188 > ui.write(' :%s:\n' % p.type)
188 > ui.write(' :%s:\n' % p.type)
189 > ui.write(' mandatory: %i\n' % len(p.mandatoryparams))
189 > ui.write(' mandatory: %i\n' % len(p.mandatoryparams))
190 > ui.write(' advisory: %i\n' % len(p.advisoryparams))
190 > ui.write(' advisory: %i\n' % len(p.advisoryparams))
191 > ui.write(' payload: %i bytes\n' % len(p.read()))
191 > ui.write(' payload: %i bytes\n' % len(p.read()))
192 > ui.write('parts count: %i\n' % count)
192 > ui.write('parts count: %i\n' % count)
193 > EOF
193 > EOF
194 $ cat >> $HGRCPATH << EOF
194 $ cat >> $HGRCPATH << EOF
195 > [extensions]
195 > [extensions]
196 > bundle2=$TESTTMP/bundle2.py
196 > bundle2=$TESTTMP/bundle2.py
197 > [experimental]
197 > [experimental]
198 > bundle2-exp=True
198 > bundle2-exp=True
199 > [ui]
199 > [ui]
200 > ssh=python "$TESTDIR/dummyssh"
200 > ssh=python "$TESTDIR/dummyssh"
201 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
201 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
202 > [web]
202 > [web]
203 > push_ssl = false
203 > push_ssl = false
204 > allow_push = *
204 > allow_push = *
205 > [phases]
205 > [phases]
206 > publish=False
206 > publish=False
207 > EOF
207 > EOF
208
208
209 The extension requires a repo (currently unused)
209 The extension requires a repo (currently unused)
210
210
211 $ hg init main
211 $ hg init main
212 $ cd main
212 $ cd main
213 $ touch a
213 $ touch a
214 $ hg add a
214 $ hg add a
215 $ hg commit -m 'a'
215 $ hg commit -m 'a'
216
216
217
217
218 Empty bundle
218 Empty bundle
219 =================
219 =================
220
220
221 - no option
221 - no option
222 - no parts
222 - no parts
223
223
224 Test bundling
224 Test bundling
225
225
226 $ hg bundle2
226 $ hg bundle2
227 HG2X\x00\x00\x00\x00 (no-eol) (esc)
227 HG2X\x00\x00\x00\x00 (no-eol) (esc)
228
228
229 Test unbundling
229 Test unbundling
230
230
231 $ hg bundle2 | hg statbundle2
231 $ hg bundle2 | hg statbundle2
232 options count: 0
232 options count: 0
233 parts count: 0
233 parts count: 0
234
234
235 Test old style bundle are detected and refused
235 Test old style bundle are detected and refused
236
236
237 $ hg bundle --all ../bundle.hg
237 $ hg bundle --all ../bundle.hg
238 1 changesets found
238 1 changesets found
239 $ hg statbundle2 < ../bundle.hg
239 $ hg statbundle2 < ../bundle.hg
240 abort: unknown bundle version 10
240 abort: unknown bundle version 10
241 [255]
241 [255]
242
242
243 Test parameters
243 Test parameters
244 =================
244 =================
245
245
246 - some options
246 - some options
247 - no parts
247 - no parts
248
248
249 advisory parameters, no value
249 advisory parameters, no value
250 -------------------------------
250 -------------------------------
251
251
252 Simplest possible parameters form
252 Simplest possible parameters form
253
253
254 Test generation simple option
254 Test generation simple option
255
255
256 $ hg bundle2 --param 'caution'
256 $ hg bundle2 --param 'caution'
257 HG2X\x00\x07caution\x00\x00 (no-eol) (esc)
257 HG2X\x00\x07caution\x00\x00 (no-eol) (esc)
258
258
259 Test unbundling
259 Test unbundling
260
260
261 $ hg bundle2 --param 'caution' | hg statbundle2
261 $ hg bundle2 --param 'caution' | hg statbundle2
262 options count: 1
262 options count: 1
263 - caution
263 - caution
264 parts count: 0
264 parts count: 0
265
265
266 Test generation multiple option
266 Test generation multiple option
267
267
268 $ hg bundle2 --param 'caution' --param 'meal'
268 $ hg bundle2 --param 'caution' --param 'meal'
269 HG2X\x00\x0ccaution meal\x00\x00 (no-eol) (esc)
269 HG2X\x00\x0ccaution meal\x00\x00 (no-eol) (esc)
270
270
271 Test unbundling
271 Test unbundling
272
272
273 $ hg bundle2 --param 'caution' --param 'meal' | hg statbundle2
273 $ hg bundle2 --param 'caution' --param 'meal' | hg statbundle2
274 options count: 2
274 options count: 2
275 - caution
275 - caution
276 - meal
276 - meal
277 parts count: 0
277 parts count: 0
278
278
279 advisory parameters, with value
279 advisory parameters, with value
280 -------------------------------
280 -------------------------------
281
281
282 Test generation
282 Test generation
283
283
284 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants'
284 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants'
285 HG2X\x00\x1ccaution meal=vegan elephants\x00\x00 (no-eol) (esc)
285 HG2X\x00\x1ccaution meal=vegan elephants\x00\x00 (no-eol) (esc)
286
286
287 Test unbundling
287 Test unbundling
288
288
289 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants' | hg statbundle2
289 $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants' | hg statbundle2
290 options count: 3
290 options count: 3
291 - caution
291 - caution
292 - elephants
292 - elephants
293 - meal
293 - meal
294 vegan
294 vegan
295 parts count: 0
295 parts count: 0
296
296
297 parameter with special char in value
297 parameter with special char in value
298 ---------------------------------------------------
298 ---------------------------------------------------
299
299
300 Test generation
300 Test generation
301
301
302 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple
302 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple
303 HG2X\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00 (no-eol) (esc)
303 HG2X\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00 (no-eol) (esc)
304
304
305 Test unbundling
305 Test unbundling
306
306
307 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple | hg statbundle2
307 $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple | hg statbundle2
308 options count: 2
308 options count: 2
309 - e|! 7/
309 - e|! 7/
310 babar%#==tutu
310 babar%#==tutu
311 - simple
311 - simple
312 parts count: 0
312 parts count: 0
313
313
314 Test unknown mandatory option
314 Test unknown mandatory option
315 ---------------------------------------------------
315 ---------------------------------------------------
316
316
317 $ hg bundle2 --param 'Gravity' | hg statbundle2
317 $ hg bundle2 --param 'Gravity' | hg statbundle2
318 abort: unknown parameters: Stream Parameter - Gravity
318 abort: unknown parameters: Stream Parameter - Gravity
319 [255]
319 [255]
320
320
321 Test debug output
321 Test debug output
322 ---------------------------------------------------
322 ---------------------------------------------------
323
323
324 bundling debug
324 bundling debug
325
325
326 $ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2
326 $ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2
327 start emission of HG2X stream
327 start emission of HG2X stream
328 bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
328 bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
329 start of parts
329 start of parts
330 end of bundle
330 end of bundle
331
331
332 file content is ok
332 file content is ok
333
333
334 $ cat ../out.hg2
334 $ cat ../out.hg2
335 HG2X\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00 (no-eol) (esc)
335 HG2X\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00 (no-eol) (esc)
336
336
337 unbundling debug
337 unbundling debug
338
338
339 $ hg statbundle2 --debug < ../out.hg2
339 $ hg statbundle2 --debug < ../out.hg2
340 start processing of HG2X stream
340 start processing of HG2X stream
341 reading bundle2 stream parameters
341 reading bundle2 stream parameters
342 ignoring unknown parameter 'e|! 7/'
342 ignoring unknown parameter 'e|! 7/'
343 ignoring unknown parameter 'simple'
343 ignoring unknown parameter 'simple'
344 options count: 2
344 options count: 2
345 - e|! 7/
345 - e|! 7/
346 babar%#==tutu
346 babar%#==tutu
347 - simple
347 - simple
348 start extraction of bundle2 parts
348 start extraction of bundle2 parts
349 part header size: 0
349 part header size: 0
350 end of bundle2 stream
350 end of bundle2 stream
351 parts count: 0
351 parts count: 0
352
352
353
353
354 Test buggy input
354 Test buggy input
355 ---------------------------------------------------
355 ---------------------------------------------------
356
356
357 empty parameter name
357 empty parameter name
358
358
359 $ hg bundle2 --param '' --quiet
359 $ hg bundle2 --param '' --quiet
360 abort: empty parameter name
360 abort: empty parameter name
361 [255]
361 [255]
362
362
363 bad parameter name
363 bad parameter name
364
364
365 $ hg bundle2 --param 42babar
365 $ hg bundle2 --param 42babar
366 abort: non letter first character: '42babar'
366 abort: non letter first character: '42babar'
367 [255]
367 [255]
368
368
369
369
370 Test part
370 Test part
371 =================
371 =================
372
372
373 $ hg bundle2 --parts ../parts.hg2 --debug
373 $ hg bundle2 --parts ../parts.hg2 --debug
374 start emission of HG2X stream
374 start emission of HG2X stream
375 bundle parameter:
375 bundle parameter:
376 start of parts
376 start of parts
377 bundle part: "test:empty"
377 bundle part: "test:empty"
378 bundle part: "test:empty"
378 bundle part: "test:empty"
379 bundle part: "test:song"
379 bundle part: "test:song"
380 bundle part: "test:debugreply"
380 bundle part: "test:debugreply"
381 bundle part: "test:math"
381 bundle part: "test:math"
382 bundle part: "test:song"
382 bundle part: "test:song"
383 bundle part: "test:ping"
383 bundle part: "test:ping"
384 end of bundle
384 end of bundle
385
385
386 $ cat ../parts.hg2
386 $ cat ../parts.hg2
387 HG2X\x00\x00\x00\x11 (esc)
387 HG2X\x00\x00\x00\x11 (esc)
388 test:empty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11 (esc)
388 test:empty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11 (esc)
389 test:empty\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10 test:song\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko (esc)
389 test:empty\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x10 test:song\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko (esc)
390 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
390 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
391 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00\x16\x0ftest:debugreply\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00+ test:math\x00\x00\x00\x04\x02\x01\x02\x04\x01\x04\x07\x03pi3.14e2.72cookingraw\x00\x00\x00\x0242\x00\x00\x00\x00\x00\x1d test:song\x00\x00\x00\x05\x01\x00\x0b\x00randomparam\x00\x00\x00\x00\x00\x10 test:ping\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
391 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00\x16\x0ftest:debugreply\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00+ test:math\x00\x00\x00\x04\x02\x01\x02\x04\x01\x04\x07\x03pi3.14e2.72cookingraw\x00\x00\x00\x0242\x00\x00\x00\x00\x00\x1d test:song\x00\x00\x00\x05\x01\x00\x0b\x00randomparam\x00\x00\x00\x00\x00\x10 test:ping\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
392
392
393
393
394 $ hg statbundle2 < ../parts.hg2
394 $ hg statbundle2 < ../parts.hg2
395 options count: 0
395 options count: 0
396 :test:empty:
396 :test:empty:
397 mandatory: 0
397 mandatory: 0
398 advisory: 0
398 advisory: 0
399 payload: 0 bytes
399 payload: 0 bytes
400 :test:empty:
400 :test:empty:
401 mandatory: 0
401 mandatory: 0
402 advisory: 0
402 advisory: 0
403 payload: 0 bytes
403 payload: 0 bytes
404 :test:song:
404 :test:song:
405 mandatory: 0
405 mandatory: 0
406 advisory: 0
406 advisory: 0
407 payload: 178 bytes
407 payload: 178 bytes
408 :test:debugreply:
408 :test:debugreply:
409 mandatory: 0
409 mandatory: 0
410 advisory: 0
410 advisory: 0
411 payload: 0 bytes
411 payload: 0 bytes
412 :test:math:
412 :test:math:
413 mandatory: 2
413 mandatory: 2
414 advisory: 1
414 advisory: 1
415 payload: 2 bytes
415 payload: 2 bytes
416 :test:song:
416 :test:song:
417 mandatory: 1
417 mandatory: 1
418 advisory: 0
418 advisory: 0
419 payload: 0 bytes
419 payload: 0 bytes
420 :test:ping:
420 :test:ping:
421 mandatory: 0
421 mandatory: 0
422 advisory: 0
422 advisory: 0
423 payload: 0 bytes
423 payload: 0 bytes
424 parts count: 7
424 parts count: 7
425
425
426 $ hg statbundle2 --debug < ../parts.hg2
426 $ hg statbundle2 --debug < ../parts.hg2
427 start processing of HG2X stream
427 start processing of HG2X stream
428 reading bundle2 stream parameters
428 reading bundle2 stream parameters
429 options count: 0
429 options count: 0
430 start extraction of bundle2 parts
430 start extraction of bundle2 parts
431 part header size: 17
431 part header size: 17
432 part type: "test:empty"
432 part type: "test:empty"
433 part id: "0"
433 part id: "0"
434 part parameters: 0
434 part parameters: 0
435 :test:empty:
435 :test:empty:
436 mandatory: 0
436 mandatory: 0
437 advisory: 0
437 advisory: 0
438 payload chunk size: 0
438 payload chunk size: 0
439 payload: 0 bytes
439 payload: 0 bytes
440 part header size: 17
440 part header size: 17
441 part type: "test:empty"
441 part type: "test:empty"
442 part id: "1"
442 part id: "1"
443 part parameters: 0
443 part parameters: 0
444 :test:empty:
444 :test:empty:
445 mandatory: 0
445 mandatory: 0
446 advisory: 0
446 advisory: 0
447 payload chunk size: 0
447 payload chunk size: 0
448 payload: 0 bytes
448 payload: 0 bytes
449 part header size: 16
449 part header size: 16
450 part type: "test:song"
450 part type: "test:song"
451 part id: "2"
451 part id: "2"
452 part parameters: 0
452 part parameters: 0
453 :test:song:
453 :test:song:
454 mandatory: 0
454 mandatory: 0
455 advisory: 0
455 advisory: 0
456 payload chunk size: 178
456 payload chunk size: 178
457 payload chunk size: 0
457 payload chunk size: 0
458 payload: 178 bytes
458 payload: 178 bytes
459 part header size: 22
459 part header size: 22
460 part type: "test:debugreply"
460 part type: "test:debugreply"
461 part id: "3"
461 part id: "3"
462 part parameters: 0
462 part parameters: 0
463 :test:debugreply:
463 :test:debugreply:
464 mandatory: 0
464 mandatory: 0
465 advisory: 0
465 advisory: 0
466 payload chunk size: 0
466 payload chunk size: 0
467 payload: 0 bytes
467 payload: 0 bytes
468 part header size: 43
468 part header size: 43
469 part type: "test:math"
469 part type: "test:math"
470 part id: "4"
470 part id: "4"
471 part parameters: 3
471 part parameters: 3
472 :test:math:
472 :test:math:
473 mandatory: 2
473 mandatory: 2
474 advisory: 1
474 advisory: 1
475 payload chunk size: 2
475 payload chunk size: 2
476 payload chunk size: 0
476 payload chunk size: 0
477 payload: 2 bytes
477 payload: 2 bytes
478 part header size: 29
478 part header size: 29
479 part type: "test:song"
479 part type: "test:song"
480 part id: "5"
480 part id: "5"
481 part parameters: 1
481 part parameters: 1
482 :test:song:
482 :test:song:
483 mandatory: 1
483 mandatory: 1
484 advisory: 0
484 advisory: 0
485 payload chunk size: 0
485 payload chunk size: 0
486 payload: 0 bytes
486 payload: 0 bytes
487 part header size: 16
487 part header size: 16
488 part type: "test:ping"
488 part type: "test:ping"
489 part id: "6"
489 part id: "6"
490 part parameters: 0
490 part parameters: 0
491 :test:ping:
491 :test:ping:
492 mandatory: 0
492 mandatory: 0
493 advisory: 0
493 advisory: 0
494 payload chunk size: 0
494 payload chunk size: 0
495 payload: 0 bytes
495 payload: 0 bytes
496 part header size: 0
496 part header size: 0
497 end of bundle2 stream
497 end of bundle2 stream
498 parts count: 7
498 parts count: 7
499
499
500 Test actual unbundling of test part
500 Test actual unbundling of test part
501 =======================================
501 =======================================
502
502
503 Process the bundle
503 Process the bundle
504
504
505 $ hg unbundle2 --debug < ../parts.hg2
505 $ hg unbundle2 --debug < ../parts.hg2
506 start processing of HG2X stream
506 start processing of HG2X stream
507 reading bundle2 stream parameters
507 reading bundle2 stream parameters
508 start extraction of bundle2 parts
508 start extraction of bundle2 parts
509 part header size: 17
509 part header size: 17
510 part type: "test:empty"
510 part type: "test:empty"
511 part id: "0"
511 part id: "0"
512 part parameters: 0
512 part parameters: 0
513 ignoring unsupported advisory part test:empty
513 ignoring unsupported advisory part test:empty
514 payload chunk size: 0
514 payload chunk size: 0
515 part header size: 17
515 part header size: 17
516 part type: "test:empty"
516 part type: "test:empty"
517 part id: "1"
517 part id: "1"
518 part parameters: 0
518 part parameters: 0
519 ignoring unsupported advisory part test:empty
519 ignoring unsupported advisory part test:empty
520 payload chunk size: 0
520 payload chunk size: 0
521 part header size: 16
521 part header size: 16
522 part type: "test:song"
522 part type: "test:song"
523 part id: "2"
523 part id: "2"
524 part parameters: 0
524 part parameters: 0
525 found a handler for part 'test:song'
525 found a handler for part 'test:song'
526 The choir starts singing:
526 The choir starts singing:
527 payload chunk size: 178
527 payload chunk size: 178
528 payload chunk size: 0
528 payload chunk size: 0
529 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
529 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
530 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
530 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
531 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
531 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
532 part header size: 22
532 part header size: 22
533 part type: "test:debugreply"
533 part type: "test:debugreply"
534 part id: "3"
534 part id: "3"
535 part parameters: 0
535 part parameters: 0
536 found a handler for part 'test:debugreply'
536 found a handler for part 'test:debugreply'
537 debugreply: no reply
537 debugreply: no reply
538 payload chunk size: 0
538 payload chunk size: 0
539 part header size: 43
539 part header size: 43
540 part type: "test:math"
540 part type: "test:math"
541 part id: "4"
541 part id: "4"
542 part parameters: 3
542 part parameters: 3
543 ignoring unsupported advisory part test:math
543 ignoring unsupported advisory part test:math
544 payload chunk size: 2
544 payload chunk size: 2
545 payload chunk size: 0
545 payload chunk size: 0
546 part header size: 29
546 part header size: 29
547 part type: "test:song"
547 part type: "test:song"
548 part id: "5"
548 part id: "5"
549 part parameters: 1
549 part parameters: 1
550 found a handler for part 'test:song'
550 found a handler for part 'test:song'
551 ignoring unsupported advisory part test:song - randomparam
551 ignoring unsupported advisory part test:song - randomparam
552 payload chunk size: 0
552 payload chunk size: 0
553 part header size: 16
553 part header size: 16
554 part type: "test:ping"
554 part type: "test:ping"
555 part id: "6"
555 part id: "6"
556 part parameters: 0
556 part parameters: 0
557 found a handler for part 'test:ping'
557 found a handler for part 'test:ping'
558 received ping request (id 6)
558 received ping request (id 6)
559 payload chunk size: 0
559 payload chunk size: 0
560 part header size: 0
560 part header size: 0
561 end of bundle2 stream
561 end of bundle2 stream
562 0 unread bytes
562 0 unread bytes
563 3 total verses sung
563 3 total verses sung
564
564
565 Unbundle with an unknown mandatory part
565 Unbundle with an unknown mandatory part
566 (should abort)
566 (should abort)
567
567
568 $ hg bundle2 --parts --unknown ../unknown.hg2
568 $ hg bundle2 --parts --unknown ../unknown.hg2
569
569
570 $ hg unbundle2 < ../unknown.hg2
570 $ hg unbundle2 < ../unknown.hg2
571 The choir starts singing:
571 The choir starts singing:
572 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
572 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
573 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
573 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
574 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
574 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
575 debugreply: no reply
575 debugreply: no reply
576 0 unread bytes
576 0 unread bytes
577 abort: missing support for test:unknown
577 abort: missing support for test:unknown
578 [255]
578 [255]
579
579
580 Unbundle with an unknown mandatory part parameters
580 Unbundle with an unknown mandatory part parameters
581 (should abort)
581 (should abort)
582
582
583 $ hg bundle2 --unknownparams ../unknown.hg2
583 $ hg bundle2 --unknownparams ../unknown.hg2
584
584
585 $ hg unbundle2 < ../unknown.hg2
585 $ hg unbundle2 < ../unknown.hg2
586 0 unread bytes
586 0 unread bytes
587 abort: missing support for test:song - randomparams
587 abort: missing support for test:song - randomparams
588 [255]
588 [255]
589
589
590 unbundle with a reply
590 unbundle with a reply
591
591
592 $ hg bundle2 --parts --reply ../parts-reply.hg2
592 $ hg bundle2 --parts --reply ../parts-reply.hg2
593 $ hg unbundle2 ../reply.hg2 < ../parts-reply.hg2
593 $ hg unbundle2 ../reply.hg2 < ../parts-reply.hg2
594 0 unread bytes
594 0 unread bytes
595 3 total verses sung
595 3 total verses sung
596
596
597 The reply is a bundle
597 The reply is a bundle
598
598
599 $ cat ../reply.hg2
599 $ cat ../reply.hg2
600 HG2X\x00\x00\x00\x1f (esc)
600 HG2X\x00\x00\x00\x1f (esc)
601 b2x:output\x00\x00\x00\x00\x00\x01\x0b\x01in-reply-to3\x00\x00\x00\xd9The choir starts singing: (esc)
601 b2x:output\x00\x00\x00\x00\x00\x01\x0b\x01in-reply-to3\x00\x00\x00\xd9The choir starts singing: (esc)
602 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
602 Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
603 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
603 Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
604 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
604 Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
605 \x00\x00\x00\x00\x00\x1f (esc)
605 \x00\x00\x00\x00\x00\x1f (esc)
606 b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to4\x00\x00\x00\xc9debugreply: capabilities: (esc)
606 b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to4\x00\x00\x00\xc9debugreply: capabilities: (esc)
607 debugreply: 'city=!'
607 debugreply: 'city=!'
608 debugreply: 'celeste,ville'
608 debugreply: 'celeste,ville'
609 debugreply: 'elephants'
609 debugreply: 'elephants'
610 debugreply: 'babar'
610 debugreply: 'babar'
611 debugreply: 'celeste'
611 debugreply: 'celeste'
612 debugreply: 'ping-pong'
612 debugreply: 'ping-pong'
613 \x00\x00\x00\x00\x00\x1e test:pong\x00\x00\x00\x02\x01\x00\x0b\x01in-reply-to7\x00\x00\x00\x00\x00\x1f (esc)
613 \x00\x00\x00\x00\x00\x1e test:pong\x00\x00\x00\x02\x01\x00\x0b\x01in-reply-to7\x00\x00\x00\x00\x00\x1f (esc)
614 b2x:output\x00\x00\x00\x03\x00\x01\x0b\x01in-reply-to7\x00\x00\x00=received ping request (id 7) (esc)
614 b2x:output\x00\x00\x00\x03\x00\x01\x0b\x01in-reply-to7\x00\x00\x00=received ping request (id 7) (esc)
615 replying to ping request (id 7)
615 replying to ping request (id 7)
616 \x00\x00\x00\x00\x00\x00 (no-eol) (esc)
616 \x00\x00\x00\x00\x00\x00 (no-eol) (esc)
617
617
618 The reply is valid
618 The reply is valid
619
619
620 $ hg statbundle2 < ../reply.hg2
620 $ hg statbundle2 < ../reply.hg2
621 options count: 0
621 options count: 0
622 :b2x:output:
622 :b2x:output:
623 mandatory: 0
623 mandatory: 0
624 advisory: 1
624 advisory: 1
625 payload: 217 bytes
625 payload: 217 bytes
626 :b2x:output:
626 :b2x:output:
627 mandatory: 0
627 mandatory: 0
628 advisory: 1
628 advisory: 1
629 payload: 201 bytes
629 payload: 201 bytes
630 :test:pong:
630 :test:pong:
631 mandatory: 1
631 mandatory: 1
632 advisory: 0
632 advisory: 0
633 payload: 0 bytes
633 payload: 0 bytes
634 :b2x:output:
634 :b2x:output:
635 mandatory: 0
635 mandatory: 0
636 advisory: 1
636 advisory: 1
637 payload: 61 bytes
637 payload: 61 bytes
638 parts count: 4
638 parts count: 4
639
639
640 Unbundle the reply to get the output:
640 Unbundle the reply to get the output:
641
641
642 $ hg unbundle2 < ../reply.hg2
642 $ hg unbundle2 < ../reply.hg2
643 remote: The choir starts singing:
643 remote: The choir starts singing:
644 remote: Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
644 remote: Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
645 remote: Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
645 remote: Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
646 remote: Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
646 remote: Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
647 remote: debugreply: capabilities:
647 remote: debugreply: capabilities:
648 remote: debugreply: 'city=!'
648 remote: debugreply: 'city=!'
649 remote: debugreply: 'celeste,ville'
649 remote: debugreply: 'celeste,ville'
650 remote: debugreply: 'elephants'
650 remote: debugreply: 'elephants'
651 remote: debugreply: 'babar'
651 remote: debugreply: 'babar'
652 remote: debugreply: 'celeste'
652 remote: debugreply: 'celeste'
653 remote: debugreply: 'ping-pong'
653 remote: debugreply: 'ping-pong'
654 remote: received ping request (id 7)
654 remote: received ping request (id 7)
655 remote: replying to ping request (id 7)
655 remote: replying to ping request (id 7)
656 0 unread bytes
656 0 unread bytes
657
657
658 Test push race detection
658 Test push race detection
659
659
660 $ hg bundle2 --pushrace ../part-race.hg2
660 $ hg bundle2 --pushrace ../part-race.hg2
661
661
662 $ hg unbundle2 < ../part-race.hg2
662 $ hg unbundle2 < ../part-race.hg2
663 0 unread bytes
663 0 unread bytes
664 abort: push race: repository changed while pushing - please try again
664 abort: push race: repository changed while pushing - please try again
665 [255]
665 [255]
666
666
667 Support for changegroup
667 Support for changegroup
668 ===================================
668 ===================================
669
669
670 $ hg unbundle $TESTDIR/bundles/rebase.hg
670 $ hg unbundle $TESTDIR/bundles/rebase.hg
671 adding changesets
671 adding changesets
672 adding manifests
672 adding manifests
673 adding file changes
673 adding file changes
674 added 8 changesets with 7 changes to 7 files (+3 heads)
674 added 8 changesets with 7 changes to 7 files (+3 heads)
675 (run 'hg heads' to see heads, 'hg merge' to merge)
675 (run 'hg heads' to see heads, 'hg merge' to merge)
676
676
677 $ hg log -G
677 $ hg log -G
678 o 8:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H
678 o 8:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H
679 |
679 |
680 | o 7:eea13746799a draft Nicolas Dumazet <nicdumz.commits@gmail.com> G
680 | o 7:eea13746799a draft Nicolas Dumazet <nicdumz.commits@gmail.com> G
681 |/|
681 |/|
682 o | 6:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
682 o | 6:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
683 | |
683 | |
684 | o 5:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
684 | o 5:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
685 |/
685 |/
686 | o 4:32af7686d403 draft Nicolas Dumazet <nicdumz.commits@gmail.com> D
686 | o 4:32af7686d403 draft Nicolas Dumazet <nicdumz.commits@gmail.com> D
687 | |
687 | |
688 | o 3:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> C
688 | o 3:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> C
689 | |
689 | |
690 | o 2:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> B
690 | o 2:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> B
691 |/
691 |/
692 o 1:cd010b8cd998 draft Nicolas Dumazet <nicdumz.commits@gmail.com> A
692 o 1:cd010b8cd998 draft Nicolas Dumazet <nicdumz.commits@gmail.com> A
693
693
694 @ 0:3903775176ed draft test a
694 @ 0:3903775176ed draft test a
695
695
696
696
697 $ hg bundle2 --debug --rev '8+7+5+4' ../rev.hg2
697 $ hg bundle2 --debug --rev '8+7+5+4' ../rev.hg2
698 4 changesets found
698 4 changesets found
699 list of changesets:
699 list of changesets:
700 32af7686d403cf45b5d95f2d70cebea587ac806a
700 32af7686d403cf45b5d95f2d70cebea587ac806a
701 9520eea781bcca16c1e15acc0ba14335a0e8e5ba
701 9520eea781bcca16c1e15acc0ba14335a0e8e5ba
702 eea13746799a9e0bfd88f29d3c2e9dc9389f524f
702 eea13746799a9e0bfd88f29d3c2e9dc9389f524f
703 02de42196ebee42ef284b6780a87cdc96e8eaab6
703 02de42196ebee42ef284b6780a87cdc96e8eaab6
704 start emission of HG2X stream
704 start emission of HG2X stream
705 bundle parameter:
705 bundle parameter:
706 start of parts
706 start of parts
707 bundle part: "b2x:changegroup"
707 bundle part: "b2x:changegroup"
708 bundling: 1/4 changesets (25.00%)
708 bundling: 1/4 changesets (25.00%)
709 bundling: 2/4 changesets (50.00%)
709 bundling: 2/4 changesets (50.00%)
710 bundling: 3/4 changesets (75.00%)
710 bundling: 3/4 changesets (75.00%)
711 bundling: 4/4 changesets (100.00%)
711 bundling: 4/4 changesets (100.00%)
712 bundling: 1/4 manifests (25.00%)
712 bundling: 1/4 manifests (25.00%)
713 bundling: 2/4 manifests (50.00%)
713 bundling: 2/4 manifests (50.00%)
714 bundling: 3/4 manifests (75.00%)
714 bundling: 3/4 manifests (75.00%)
715 bundling: 4/4 manifests (100.00%)
715 bundling: 4/4 manifests (100.00%)
716 bundling: D 1/3 files (33.33%)
716 bundling: D 1/3 files (33.33%)
717 bundling: E 2/3 files (66.67%)
717 bundling: E 2/3 files (66.67%)
718 bundling: H 3/3 files (100.00%)
718 bundling: H 3/3 files (100.00%)
719 end of bundle
719 end of bundle
720
720
721 $ cat ../rev.hg2
721 $ cat ../rev.hg2
722 HG2X\x00\x00\x00\x16\x0fb2x:changegroup\x00\x00\x00\x00\x00\x00\x00\x00\x06\x13\x00\x00\x00\xa42\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j_\xdd\xd9\x89W\xc8\xa5JMCm\xfe\x1d\xa9\xd8\x7f!\xa1\xb9{\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c (esc)
722 HG2X\x00\x00\x00\x16\x0fb2x:changegroup\x00\x00\x00\x00\x00\x00\x00\x00\x06\x13\x00\x00\x00\xa42\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j_\xdd\xd9\x89W\xc8\xa5JMCm\xfe\x1d\xa9\xd8\x7f!\xa1\xb9{\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c (esc)
723 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02D (esc)
723 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02D (esc)
724 \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01D\x00\x00\x00\xa4\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xcd\x01\x0b\x8c\xd9\x98\xf3\x98\x1aZ\x81\x15\xf9O\x8d\xa4\xabP`\x89\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)4dece9c826f69490507b98c6383a3009b295837d (esc)
724 \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01D\x00\x00\x00\xa4\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xcd\x01\x0b\x8c\xd9\x98\xf3\x98\x1aZ\x81\x15\xf9O\x8d\xa4\xabP`\x89\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)4dece9c826f69490507b98c6383a3009b295837d (esc)
725 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02E (esc)
725 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02E (esc)
726 \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01E\x00\x00\x00\xa2\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)365b93d57fdf4814e2b5911d6bacff2b12014441 (esc)
726 \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01E\x00\x00\x00\xa2\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)365b93d57fdf4814e2b5911d6bacff2b12014441 (esc)
727 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x00\x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01G\x00\x00\x00\xa4\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
727 \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x00\x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01G\x00\x00\x00\xa4\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
728 \x87\xcd\xc9n\x8e\xaa\xb6$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
728 \x87\xcd\xc9n\x8e\xaa\xb6$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
729 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)8bee48edc7318541fc0013ee41b089276a8c24bf (esc)
729 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)8bee48edc7318541fc0013ee41b089276a8c24bf (esc)
730 \x00\x00\x00f\x00\x00\x00f\x00\x00\x00\x02H (esc)
730 \x00\x00\x00f\x00\x00\x00f\x00\x00\x00\x02H (esc)
731 \x00\x00\x00g\x00\x00\x00h\x00\x00\x00\x01H\x00\x00\x00\x00\x00\x00\x00\x8bn\x1fLG\xec\xb53\xff\xd0\xc8\xe5,\xdc\x88\xaf\xb6\xcd9\xe2\x0cf\xa5\xa0\x18\x17\xfd\xf5#\x9c'8\x02\xb5\xb7a\x8d\x05\x1c\x89\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+D\x00c3f1ca2924c16a19b0656a84900e504e5b0aec2d (esc)
731 \x00\x00\x00g\x00\x00\x00h\x00\x00\x00\x01H\x00\x00\x00\x00\x00\x00\x00\x8bn\x1fLG\xec\xb53\xff\xd0\xc8\xe5,\xdc\x88\xaf\xb6\xcd9\xe2\x0cf\xa5\xa0\x18\x17\xfd\xf5#\x9c'8\x02\xb5\xb7a\x8d\x05\x1c\x89\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+D\x00c3f1ca2924c16a19b0656a84900e504e5b0aec2d (esc)
732 \x00\x00\x00\x8bM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0 \xb2\x95\x83}\x00}\x8c\x9d\x88\x84\x13%\xf5\xc6\xb0cq\xb3[N\x8a+\x1a\x83\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00+\x00\x00\x00\xac\x00\x00\x00+E\x009c6fd0350a6c0d0c49d4a9c5017cf07043f54e58 (esc)
732 \x00\x00\x00\x8bM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0 \xb2\x95\x83}\x00}\x8c\x9d\x88\x84\x13%\xf5\xc6\xb0cq\xb3[N\x8a+\x1a\x83\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00+\x00\x00\x00\xac\x00\x00\x00+E\x009c6fd0350a6c0d0c49d4a9c5017cf07043f54e58 (esc)
733 \x00\x00\x00\x8b6[\x93\xd5\x7f\xdfH\x14\xe2\xb5\x91\x1dk\xac\xff+\x12\x01DA(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xceM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0 \xb2\x95\x83}\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00V\x00\x00\x00V\x00\x00\x00+F\x0022bfcfd62a21a3287edbd4d656218d0f525ed76a (esc)
733 \x00\x00\x00\x8b6[\x93\xd5\x7f\xdfH\x14\xe2\xb5\x91\x1dk\xac\xff+\x12\x01DA(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xceM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0 \xb2\x95\x83}\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00V\x00\x00\x00V\x00\x00\x00+F\x0022bfcfd62a21a3287edbd4d656218d0f525ed76a (esc)
734 \x00\x00\x00\x97\x8b\xeeH\xed\xc71\x85A\xfc\x00\x13\xeeA\xb0\x89'j\x8c$\xbf(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xce\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
734 \x00\x00\x00\x97\x8b\xeeH\xed\xc71\x85A\xfc\x00\x13\xeeA\xb0\x89'j\x8c$\xbf(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xce\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
735 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00+\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+H\x008500189e74a9e0475e822093bc7db0d631aeb0b4 (esc)
735 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00+\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+H\x008500189e74a9e0475e822093bc7db0d631aeb0b4 (esc)
736 \x00\x00\x00\x00\x00\x00\x00\x05D\x00\x00\x00b\xc3\xf1\xca)$\xc1j\x19\xb0ej\x84\x90\x0ePN[ (esc)
736 \x00\x00\x00\x00\x00\x00\x00\x05D\x00\x00\x00b\xc3\xf1\xca)$\xc1j\x19\xb0ej\x84\x90\x0ePN[ (esc)
737 \xec-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02D (esc)
737 \xec-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02D (esc)
738 \x00\x00\x00\x00\x00\x00\x00\x05E\x00\x00\x00b\x9co\xd05 (esc)
738 \x00\x00\x00\x00\x00\x00\x00\x05E\x00\x00\x00b\x9co\xd05 (esc)
739 l\r (no-eol) (esc)
739 l\r (no-eol) (esc)
740 \x0cI\xd4\xa9\xc5\x01|\xf0pC\xf5NX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02E (esc)
740 \x0cI\xd4\xa9\xc5\x01|\xf0pC\xf5NX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02E (esc)
741 \x00\x00\x00\x00\x00\x00\x00\x05H\x00\x00\x00b\x85\x00\x18\x9et\xa9\xe0G^\x82 \x93\xbc}\xb0\xd61\xae\xb0\xb4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
741 \x00\x00\x00\x00\x00\x00\x00\x05H\x00\x00\x00b\x85\x00\x18\x9et\xa9\xe0G^\x82 \x93\xbc}\xb0\xd61\xae\xb0\xb4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
742 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02H (esc)
742 \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02H (esc)
743 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
743 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
744
744
745 $ hg unbundle2 < ../rev.hg2
745 $ hg unbundle2 < ../rev.hg2
746 adding changesets
746 adding changesets
747 adding manifests
747 adding manifests
748 adding file changes
748 adding file changes
749 added 0 changesets with 0 changes to 3 files
749 added 0 changesets with 0 changes to 3 files
750 0 unread bytes
750 0 unread bytes
751 addchangegroup return: 1
751 addchangegroup return: 1
752
752
753 with reply
753 with reply
754
754
755 $ hg bundle2 --rev '8+7+5+4' --reply ../rev-rr.hg2
755 $ hg bundle2 --rev '8+7+5+4' --reply ../rev-rr.hg2
756 $ hg unbundle2 ../rev-reply.hg2 < ../rev-rr.hg2
756 $ hg unbundle2 ../rev-reply.hg2 < ../rev-rr.hg2
757 0 unread bytes
757 0 unread bytes
758 addchangegroup return: 1
758 addchangegroup return: 1
759
759
760 $ cat ../rev-reply.hg2
760 $ cat ../rev-reply.hg2
761 HG2X\x00\x00\x003\x15b2x:reply:changegroup\x00\x00\x00\x00\x00\x02\x0b\x01\x06\x01in-reply-to1return1\x00\x00\x00\x00\x00\x1f (esc)
761 HG2X\x00\x00\x003\x15b2x:reply:changegroup\x00\x00\x00\x00\x00\x02\x0b\x01\x06\x01in-reply-to1return1\x00\x00\x00\x00\x00\x1f (esc)
762 b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to1\x00\x00\x00dadding changesets (esc)
762 b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to1\x00\x00\x00dadding changesets (esc)
763 adding manifests
763 adding manifests
764 adding file changes
764 adding file changes
765 added 0 changesets with 0 changes to 3 files
765 added 0 changesets with 0 changes to 3 files
766 \x00\x00\x00\x00\x00\x00 (no-eol) (esc)
766 \x00\x00\x00\x00\x00\x00 (no-eol) (esc)
767
767
768 $ cd ..
768 $ cd ..
769
769
770 Real world exchange
770 Real world exchange
771 =====================
771 =====================
772
772
773 Add more obsolescence information
773 Add more obsolescence information
774
774
775 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
775 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
776 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
776 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
777
777
778 clone --pull
778 clone --pull
779
779
780 $ hg -R main phase --public cd010b8cd998
780 $ hg -R main phase --public cd010b8cd998
781 $ hg clone main other --pull --rev 9520eea781bc
781 $ hg clone main other --pull --rev 9520eea781bc
782 adding changesets
782 adding changesets
783 adding manifests
783 adding manifests
784 adding file changes
784 adding file changes
785 added 2 changesets with 2 changes to 2 files
785 added 2 changesets with 2 changes to 2 files
786 1 new obsolescence markers
786 1 new obsolescence markers
787 updating to branch default
787 updating to branch default
788 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
788 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
789 $ hg -R other log -G
789 $ hg -R other log -G
790 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
790 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
791 |
791 |
792 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
792 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
793
793
794 $ hg -R other debugobsolete
794 $ hg -R other debugobsolete
795 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
795 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
796
796
797 pull
797 pull
798
798
799 $ hg -R main phase --public 9520eea781bc
799 $ hg -R main phase --public 9520eea781bc
800 $ hg -R other pull -r 24b6387c8c8c
800 $ hg -R other pull -r 24b6387c8c8c
801 pulling from $TESTTMP/main (glob)
801 pulling from $TESTTMP/main (glob)
802 searching for changes
802 searching for changes
803 adding changesets
803 adding changesets
804 adding manifests
804 adding manifests
805 adding file changes
805 adding file changes
806 added 1 changesets with 1 changes to 1 files (+1 heads)
806 added 1 changesets with 1 changes to 1 files (+1 heads)
807 1 new obsolescence markers
807 1 new obsolescence markers
808 (run 'hg heads' to see heads, 'hg merge' to merge)
808 (run 'hg heads' to see heads, 'hg merge' to merge)
809 $ hg -R other log -G
809 $ hg -R other log -G
810 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
810 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
811 |
811 |
812 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
812 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
813 |/
813 |/
814 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
814 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
815
815
816 $ hg -R other debugobsolete
816 $ hg -R other debugobsolete
817 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
817 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
818 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
818 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
819
819
820 pull empty (with phase movement)
820 pull empty (with phase movement)
821
821
822 $ hg -R main phase --public 24b6387c8c8c
822 $ hg -R main phase --public 24b6387c8c8c
823 $ hg -R other pull -r 24b6387c8c8c
823 $ hg -R other pull -r 24b6387c8c8c
824 pulling from $TESTTMP/main (glob)
824 pulling from $TESTTMP/main (glob)
825 no changes found
825 no changes found
826 $ hg -R other log -G
826 $ hg -R other log -G
827 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
827 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
828 |
828 |
829 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
829 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
830 |/
830 |/
831 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
831 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
832
832
833 $ hg -R other debugobsolete
833 $ hg -R other debugobsolete
834 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
834 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
835 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
835 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
836
836
837 pull empty
837 pull empty
838
838
839 $ hg -R other pull -r 24b6387c8c8c
839 $ hg -R other pull -r 24b6387c8c8c
840 pulling from $TESTTMP/main (glob)
840 pulling from $TESTTMP/main (glob)
841 no changes found
841 no changes found
842 $ hg -R other log -G
842 $ hg -R other log -G
843 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
843 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
844 |
844 |
845 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
845 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
846 |/
846 |/
847 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
847 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
848
848
849 $ hg -R other debugobsolete
849 $ hg -R other debugobsolete
850 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
850 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
851 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
851 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
852
852
853 add extra data to test their exchange during push
853 add extra data to test their exchange during push
854
854
855 $ hg -R main bookmark --rev eea13746799a book_eea1
855 $ hg -R main bookmark --rev eea13746799a book_eea1
856 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
856 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
857 $ hg -R main bookmark --rev 02de42196ebe book_02de
857 $ hg -R main bookmark --rev 02de42196ebe book_02de
858 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
858 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
859 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
859 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
860 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
860 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
861 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
861 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
862 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
862 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
863 $ hg -R main bookmark --rev 32af7686d403 book_32af
863 $ hg -R main bookmark --rev 32af7686d403 book_32af
864 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
864 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
865
865
866 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
866 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
867 $ hg -R other bookmark --rev cd010b8cd998 book_02de
867 $ hg -R other bookmark --rev cd010b8cd998 book_02de
868 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
868 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
869 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
869 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
870 $ hg -R other bookmark --rev cd010b8cd998 book_32af
870 $ hg -R other bookmark --rev cd010b8cd998 book_32af
871
871
872 $ hg -R main phase --public eea13746799a
872 $ hg -R main phase --public eea13746799a
873
873
874 push
874 push
875 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
875 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
876 pushing to other
876 pushing to other
877 searching for changes
877 searching for changes
878 remote: adding changesets
878 remote: adding changesets
879 remote: adding manifests
879 remote: adding manifests
880 remote: adding file changes
880 remote: adding file changes
881 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
881 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
882 remote: 1 new obsolescence markers
882 remote: 1 new obsolescence markers
883 updating bookmark book_eea1
883 updating bookmark book_eea1
884 exporting bookmark book_eea1
885 $ hg -R other log -G
884 $ hg -R other log -G
886 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
885 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
887 |\
886 |\
888 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
887 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
889 | |
888 | |
890 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
889 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
891 |/
890 |/
892 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
891 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
893
892
894 $ hg -R other debugobsolete
893 $ hg -R other debugobsolete
895 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
894 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
896 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
895 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
897 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
896 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
898
897
899 pull over ssh
898 pull over ssh
900
899
901 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
900 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
902 pulling from ssh://user@dummy/main
901 pulling from ssh://user@dummy/main
903 searching for changes
902 searching for changes
904 adding changesets
903 adding changesets
905 adding manifests
904 adding manifests
906 adding file changes
905 adding file changes
907 added 1 changesets with 1 changes to 1 files (+1 heads)
906 added 1 changesets with 1 changes to 1 files (+1 heads)
908 1 new obsolescence markers
907 1 new obsolescence markers
909 updating bookmark book_02de
908 updating bookmark book_02de
910 importing bookmark book_02de
909 importing bookmark book_02de
911 (run 'hg heads' to see heads, 'hg merge' to merge)
910 (run 'hg heads' to see heads, 'hg merge' to merge)
912 $ hg -R other debugobsolete
911 $ hg -R other debugobsolete
913 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
912 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
914 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
913 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
915 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
914 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
916 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
915 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
917
916
918 pull over http
917 pull over http
919
918
920 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
919 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
921 $ cat main.pid >> $DAEMON_PIDS
920 $ cat main.pid >> $DAEMON_PIDS
922
921
923 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
922 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
924 pulling from http://localhost:$HGPORT/
923 pulling from http://localhost:$HGPORT/
925 searching for changes
924 searching for changes
926 adding changesets
925 adding changesets
927 adding manifests
926 adding manifests
928 adding file changes
927 adding file changes
929 added 1 changesets with 1 changes to 1 files (+1 heads)
928 added 1 changesets with 1 changes to 1 files (+1 heads)
930 1 new obsolescence markers
929 1 new obsolescence markers
931 updating bookmark book_42cc
930 updating bookmark book_42cc
932 importing bookmark book_42cc
931 importing bookmark book_42cc
933 (run 'hg heads .' to see heads, 'hg merge' to merge)
932 (run 'hg heads .' to see heads, 'hg merge' to merge)
934 $ cat main-error.log
933 $ cat main-error.log
935 $ hg -R other debugobsolete
934 $ hg -R other debugobsolete
936 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
935 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
937 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
936 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
938 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
937 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
939 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
938 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
940 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
939 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
941
940
942 push over ssh
941 push over ssh
943
942
944 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
943 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
945 pushing to ssh://user@dummy/other
944 pushing to ssh://user@dummy/other
946 searching for changes
945 searching for changes
947 remote: adding changesets
946 remote: adding changesets
948 remote: adding manifests
947 remote: adding manifests
949 remote: adding file changes
948 remote: adding file changes
950 remote: added 1 changesets with 1 changes to 1 files
949 remote: added 1 changesets with 1 changes to 1 files
951 remote: 1 new obsolescence markers
950 remote: 1 new obsolescence markers
952 updating bookmark book_5fdd
951 updating bookmark book_5fdd
953 exporting bookmark book_5fdd
954 $ hg -R other log -G
952 $ hg -R other log -G
955 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
953 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
956 |
954 |
957 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
955 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
958 |
956 |
959 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
957 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
960 | |
958 | |
961 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
959 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
962 | |/|
960 | |/|
963 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
961 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
964 |/ /
962 |/ /
965 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
963 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
966 |/
964 |/
967 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
965 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
968
966
969 $ hg -R other debugobsolete
967 $ hg -R other debugobsolete
970 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
968 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
971 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
969 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
972 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
970 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
973 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
971 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
974 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
972 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
975 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
973 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
976
974
977 push over http
975 push over http
978
976
979 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
977 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
980 $ cat other.pid >> $DAEMON_PIDS
978 $ cat other.pid >> $DAEMON_PIDS
981
979
982 $ hg -R main phase --public 32af7686d403
980 $ hg -R main phase --public 32af7686d403
983 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
981 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
984 pushing to http://localhost:$HGPORT2/
982 pushing to http://localhost:$HGPORT2/
985 searching for changes
983 searching for changes
986 remote: adding changesets
984 remote: adding changesets
987 remote: adding manifests
985 remote: adding manifests
988 remote: adding file changes
986 remote: adding file changes
989 remote: added 1 changesets with 1 changes to 1 files
987 remote: added 1 changesets with 1 changes to 1 files
990 remote: 1 new obsolescence markers
988 remote: 1 new obsolescence markers
991 updating bookmark book_32af
989 updating bookmark book_32af
992 exporting bookmark book_32af
993 $ cat other-error.log
990 $ cat other-error.log
994
991
995 Check final content.
992 Check final content.
996
993
997 $ hg -R other log -G
994 $ hg -R other log -G
998 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
995 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
999 |
996 |
1000 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
997 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
1001 |
998 |
1002 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
999 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
1003 |
1000 |
1004 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
1001 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
1005 | |
1002 | |
1006 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
1003 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
1007 | |/|
1004 | |/|
1008 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
1005 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
1009 |/ /
1006 |/ /
1010 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
1007 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
1011 |/
1008 |/
1012 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
1009 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
1013
1010
1014 $ hg -R other debugobsolete
1011 $ hg -R other debugobsolete
1015 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1012 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1016 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1013 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1017 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1014 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1018 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1015 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1019 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1016 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1020 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1017 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1021 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1018 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1022
1019
1023 Error Handling
1020 Error Handling
1024 ==============
1021 ==============
1025
1022
1026 Check that errors are properly returned to the client during push.
1023 Check that errors are properly returned to the client during push.
1027
1024
1028 Setting up
1025 Setting up
1029
1026
1030 $ cat > failpush.py << EOF
1027 $ cat > failpush.py << EOF
1031 > """A small extension that makes push fails when using bundle2
1028 > """A small extension that makes push fails when using bundle2
1032 >
1029 >
1033 > used to test error handling in bundle2
1030 > used to test error handling in bundle2
1034 > """
1031 > """
1035 >
1032 >
1036 > from mercurial import util
1033 > from mercurial import util
1037 > from mercurial import bundle2
1034 > from mercurial import bundle2
1038 > from mercurial import exchange
1035 > from mercurial import exchange
1039 > from mercurial import extensions
1036 > from mercurial import extensions
1040 >
1037 >
1041 > def _pushbundle2failpart(pushop, bundler):
1038 > def _pushbundle2failpart(pushop, bundler):
1042 > reason = pushop.ui.config('failpush', 'reason', None)
1039 > reason = pushop.ui.config('failpush', 'reason', None)
1043 > part = None
1040 > part = None
1044 > if reason == 'abort':
1041 > if reason == 'abort':
1045 > bundler.newpart('test:abort')
1042 > bundler.newpart('test:abort')
1046 > if reason == 'unknown':
1043 > if reason == 'unknown':
1047 > bundler.newpart('TEST:UNKNOWN')
1044 > bundler.newpart('TEST:UNKNOWN')
1048 > if reason == 'race':
1045 > if reason == 'race':
1049 > # 20 Bytes of crap
1046 > # 20 Bytes of crap
1050 > bundler.newpart('b2x:check:heads', data='01234567890123456789')
1047 > bundler.newpart('b2x:check:heads', data='01234567890123456789')
1051 >
1048 >
1052 > @bundle2.parthandler("test:abort")
1049 > @bundle2.parthandler("test:abort")
1053 > def handleabort(op, part):
1050 > def handleabort(op, part):
1054 > raise util.Abort('Abandon ship!', hint="don't panic")
1051 > raise util.Abort('Abandon ship!', hint="don't panic")
1055 >
1052 >
1056 > def uisetup(ui):
1053 > def uisetup(ui):
1057 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
1054 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
1058 > exchange.b2partsgenorder.insert(0, 'failpart')
1055 > exchange.b2partsgenorder.insert(0, 'failpart')
1059 >
1056 >
1060 > EOF
1057 > EOF
1061
1058
1062 $ cd main
1059 $ cd main
1063 $ hg up tip
1060 $ hg up tip
1064 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
1061 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
1065 $ echo 'I' > I
1062 $ echo 'I' > I
1066 $ hg add I
1063 $ hg add I
1067 $ hg ci -m 'I'
1064 $ hg ci -m 'I'
1068 $ hg id
1065 $ hg id
1069 e7ec4e813ba6 tip
1066 e7ec4e813ba6 tip
1070 $ cd ..
1067 $ cd ..
1071
1068
1072 $ cat << EOF >> $HGRCPATH
1069 $ cat << EOF >> $HGRCPATH
1073 > [extensions]
1070 > [extensions]
1074 > failpush=$TESTTMP/failpush.py
1071 > failpush=$TESTTMP/failpush.py
1075 > EOF
1072 > EOF
1076
1073
1077 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1074 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1078 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
1075 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
1079 $ cat other.pid >> $DAEMON_PIDS
1076 $ cat other.pid >> $DAEMON_PIDS
1080
1077
1081 Doing the actual push: Abort error
1078 Doing the actual push: Abort error
1082
1079
1083 $ cat << EOF >> $HGRCPATH
1080 $ cat << EOF >> $HGRCPATH
1084 > [failpush]
1081 > [failpush]
1085 > reason = abort
1082 > reason = abort
1086 > EOF
1083 > EOF
1087
1084
1088 $ hg -R main push other -r e7ec4e813ba6
1085 $ hg -R main push other -r e7ec4e813ba6
1089 pushing to other
1086 pushing to other
1090 searching for changes
1087 searching for changes
1091 abort: Abandon ship!
1088 abort: Abandon ship!
1092 (don't panic)
1089 (don't panic)
1093 [255]
1090 [255]
1094
1091
1095 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1092 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1096 pushing to ssh://user@dummy/other
1093 pushing to ssh://user@dummy/other
1097 searching for changes
1094 searching for changes
1098 abort: Abandon ship!
1095 abort: Abandon ship!
1099 (don't panic)
1096 (don't panic)
1100 [255]
1097 [255]
1101
1098
1102 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1099 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1103 pushing to http://localhost:$HGPORT2/
1100 pushing to http://localhost:$HGPORT2/
1104 searching for changes
1101 searching for changes
1105 abort: Abandon ship!
1102 abort: Abandon ship!
1106 (don't panic)
1103 (don't panic)
1107 [255]
1104 [255]
1108
1105
1109
1106
1110 Doing the actual push: unknown mandatory parts
1107 Doing the actual push: unknown mandatory parts
1111
1108
1112 $ cat << EOF >> $HGRCPATH
1109 $ cat << EOF >> $HGRCPATH
1113 > [failpush]
1110 > [failpush]
1114 > reason = unknown
1111 > reason = unknown
1115 > EOF
1112 > EOF
1116
1113
1117 $ hg -R main push other -r e7ec4e813ba6
1114 $ hg -R main push other -r e7ec4e813ba6
1118 pushing to other
1115 pushing to other
1119 searching for changes
1116 searching for changes
1120 abort: missing support for test:unknown
1117 abort: missing support for test:unknown
1121 [255]
1118 [255]
1122
1119
1123 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1120 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1124 pushing to ssh://user@dummy/other
1121 pushing to ssh://user@dummy/other
1125 searching for changes
1122 searching for changes
1126 abort: missing support for test:unknown
1123 abort: missing support for test:unknown
1127 [255]
1124 [255]
1128
1125
1129 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1126 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1130 pushing to http://localhost:$HGPORT2/
1127 pushing to http://localhost:$HGPORT2/
1131 searching for changes
1128 searching for changes
1132 abort: missing support for test:unknown
1129 abort: missing support for test:unknown
1133 [255]
1130 [255]
1134
1131
1135 Doing the actual push: race
1132 Doing the actual push: race
1136
1133
1137 $ cat << EOF >> $HGRCPATH
1134 $ cat << EOF >> $HGRCPATH
1138 > [failpush]
1135 > [failpush]
1139 > reason = race
1136 > reason = race
1140 > EOF
1137 > EOF
1141
1138
1142 $ hg -R main push other -r e7ec4e813ba6
1139 $ hg -R main push other -r e7ec4e813ba6
1143 pushing to other
1140 pushing to other
1144 searching for changes
1141 searching for changes
1145 abort: push failed:
1142 abort: push failed:
1146 'repository changed while pushing - please try again'
1143 'repository changed while pushing - please try again'
1147 [255]
1144 [255]
1148
1145
1149 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1146 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1150 pushing to ssh://user@dummy/other
1147 pushing to ssh://user@dummy/other
1151 searching for changes
1148 searching for changes
1152 abort: push failed:
1149 abort: push failed:
1153 'repository changed while pushing - please try again'
1150 'repository changed while pushing - please try again'
1154 [255]
1151 [255]
1155
1152
1156 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1153 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1157 pushing to http://localhost:$HGPORT2/
1154 pushing to http://localhost:$HGPORT2/
1158 searching for changes
1155 searching for changes
1159 abort: push failed:
1156 abort: push failed:
1160 'repository changed while pushing - please try again'
1157 'repository changed while pushing - please try again'
1161 [255]
1158 [255]
1162
1159
1163 Doing the actual push: hook abort
1160 Doing the actual push: hook abort
1164
1161
1165 $ cat << EOF >> $HGRCPATH
1162 $ cat << EOF >> $HGRCPATH
1166 > [failpush]
1163 > [failpush]
1167 > reason =
1164 > reason =
1168 > [hooks]
1165 > [hooks]
1169 > b2x-pretransactionclose.failpush = false
1166 > b2x-pretransactionclose.failpush = false
1170 > EOF
1167 > EOF
1171
1168
1172 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1169 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1173 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
1170 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
1174 $ cat other.pid >> $DAEMON_PIDS
1171 $ cat other.pid >> $DAEMON_PIDS
1175
1172
1176 $ hg -R main push other -r e7ec4e813ba6
1173 $ hg -R main push other -r e7ec4e813ba6
1177 pushing to other
1174 pushing to other
1178 searching for changes
1175 searching for changes
1179 transaction abort!
1176 transaction abort!
1180 rollback completed
1177 rollback completed
1181 abort: b2x-pretransactionclose.failpush hook exited with status 1
1178 abort: b2x-pretransactionclose.failpush hook exited with status 1
1182 [255]
1179 [255]
1183
1180
1184 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1181 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
1185 pushing to ssh://user@dummy/other
1182 pushing to ssh://user@dummy/other
1186 searching for changes
1183 searching for changes
1187 abort: b2x-pretransactionclose.failpush hook exited with status 1
1184 abort: b2x-pretransactionclose.failpush hook exited with status 1
1188 remote: transaction abort!
1185 remote: transaction abort!
1189 remote: rollback completed
1186 remote: rollback completed
1190 [255]
1187 [255]
1191
1188
1192 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1189 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
1193 pushing to http://localhost:$HGPORT2/
1190 pushing to http://localhost:$HGPORT2/
1194 searching for changes
1191 searching for changes
1195 abort: b2x-pretransactionclose.failpush hook exited with status 1
1192 abort: b2x-pretransactionclose.failpush hook exited with status 1
1196 [255]
1193 [255]
1197
1194
1198
1195
@@ -1,646 +1,644
1 commit hooks can see env vars
1 commit hooks can see env vars
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ cat > .hg/hgrc <<EOF
5 $ cat > .hg/hgrc <<EOF
6 > [hooks]
6 > [hooks]
7 > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
7 > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
8 > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
8 > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
9 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
9 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
10 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
10 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
11 > pretxncommit.tip = hg -q tip
11 > pretxncommit.tip = hg -q tip
12 > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
12 > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
13 > pre-cat = python "$TESTDIR/printenv.py" pre-cat
13 > pre-cat = python "$TESTDIR/printenv.py" pre-cat
14 > post-cat = python "$TESTDIR/printenv.py" post-cat
14 > post-cat = python "$TESTDIR/printenv.py" post-cat
15 > EOF
15 > EOF
16 $ echo a > a
16 $ echo a > a
17 $ hg add a
17 $ hg add a
18 $ hg commit -m a
18 $ hg commit -m a
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
21 0:cb9a9f314b8b
21 0:cb9a9f314b8b
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
24
24
25 $ hg clone . ../b
25 $ hg clone . ../b
26 updating to branch default
26 updating to branch default
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ cd ../b
28 $ cd ../b
29
29
30 changegroup hooks can see env vars
30 changegroup hooks can see env vars
31
31
32 $ cat > .hg/hgrc <<EOF
32 $ cat > .hg/hgrc <<EOF
33 > [hooks]
33 > [hooks]
34 > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
34 > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
35 > changegroup = python "$TESTDIR/printenv.py" changegroup
35 > changegroup = python "$TESTDIR/printenv.py" changegroup
36 > incoming = python "$TESTDIR/printenv.py" incoming
36 > incoming = python "$TESTDIR/printenv.py" incoming
37 > EOF
37 > EOF
38
38
39 pretxncommit and commit hooks can see both parents of merge
39 pretxncommit and commit hooks can see both parents of merge
40
40
41 $ cd ../a
41 $ cd ../a
42 $ echo b >> a
42 $ echo b >> a
43 $ hg commit -m a1 -d "1 0"
43 $ hg commit -m a1 -d "1 0"
44 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
44 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
45 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
45 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
46 1:ab228980c14d
46 1:ab228980c14d
47 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
47 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
48 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
48 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
49 $ hg update -C 0
49 $ hg update -C 0
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 $ echo b > b
51 $ echo b > b
52 $ hg add b
52 $ hg add b
53 $ hg commit -m b -d '1 0'
53 $ hg commit -m b -d '1 0'
54 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
54 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
55 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
55 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
56 2:ee9deb46ab31
56 2:ee9deb46ab31
57 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
57 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
58 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
58 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
59 created new head
59 created new head
60 $ hg merge 1
60 $ hg merge 1
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 (branch merge, don't forget to commit)
62 (branch merge, don't forget to commit)
63 $ hg commit -m merge -d '2 0'
63 $ hg commit -m merge -d '2 0'
64 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
64 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
65 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
65 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
66 3:07f3376c1e65
66 3:07f3376c1e65
67 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
67 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
68 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
68 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
69
69
70 test generic hooks
70 test generic hooks
71
71
72 $ hg id
72 $ hg id
73 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
73 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
74 abort: pre-identify hook exited with status 1
74 abort: pre-identify hook exited with status 1
75 [255]
75 [255]
76 $ hg cat b
76 $ hg cat b
77 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
77 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
78 b
78 b
79 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
79 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
80
80
81 $ cd ../b
81 $ cd ../b
82 $ hg pull ../a
82 $ hg pull ../a
83 pulling from ../a
83 pulling from ../a
84 searching for changes
84 searching for changes
85 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
85 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
86 adding changesets
86 adding changesets
87 adding manifests
87 adding manifests
88 adding file changes
88 adding file changes
89 added 3 changesets with 2 changes to 2 files
89 added 3 changesets with 2 changes to 2 files
90 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
90 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
92 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
92 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
93 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
93 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
94 (run 'hg update' to get a working copy)
94 (run 'hg update' to get a working copy)
95
95
96 tag hooks can see env vars
96 tag hooks can see env vars
97
97
98 $ cd ../a
98 $ cd ../a
99 $ cat >> .hg/hgrc <<EOF
99 $ cat >> .hg/hgrc <<EOF
100 > pretag = python "$TESTDIR/printenv.py" pretag
100 > pretag = python "$TESTDIR/printenv.py" pretag
101 > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
101 > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
102 > EOF
102 > EOF
103 $ hg tag -d '3 0' a
103 $ hg tag -d '3 0' a
104 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
104 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
105 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
105 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
106 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
106 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
107 4:539e4b31b6dc
107 4:539e4b31b6dc
108 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
108 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
109 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
109 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
110 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
110 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
111 $ hg tag -l la
111 $ hg tag -l la
112 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
112 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
113 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
113 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
114
114
115 pretag hook can forbid tagging
115 pretag hook can forbid tagging
116
116
117 $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
117 $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
118 $ hg tag -d '4 0' fa
118 $ hg tag -d '4 0' fa
119 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
119 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
120 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
120 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
121 abort: pretag.forbid hook exited with status 1
121 abort: pretag.forbid hook exited with status 1
122 [255]
122 [255]
123 $ hg tag -l fla
123 $ hg tag -l fla
124 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
124 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
125 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
125 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
126 abort: pretag.forbid hook exited with status 1
126 abort: pretag.forbid hook exited with status 1
127 [255]
127 [255]
128
128
129 pretxncommit hook can see changeset, can roll back txn, changeset no
129 pretxncommit hook can see changeset, can roll back txn, changeset no
130 more there after
130 more there after
131
131
132 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
132 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
133 $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
133 $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
134 $ echo z > z
134 $ echo z > z
135 $ hg add z
135 $ hg add z
136 $ hg -q tip
136 $ hg -q tip
137 4:539e4b31b6dc
137 4:539e4b31b6dc
138 $ hg commit -m 'fail' -d '4 0'
138 $ hg commit -m 'fail' -d '4 0'
139 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
139 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
140 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
140 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
141 5:6f611f8018c1
141 5:6f611f8018c1
142 5:6f611f8018c1
142 5:6f611f8018c1
143 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
143 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
144 transaction abort!
144 transaction abort!
145 rollback completed
145 rollback completed
146 abort: pretxncommit.forbid1 hook exited with status 1
146 abort: pretxncommit.forbid1 hook exited with status 1
147 [255]
147 [255]
148 $ hg -q tip
148 $ hg -q tip
149 4:539e4b31b6dc
149 4:539e4b31b6dc
150
150
151 precommit hook can prevent commit
151 precommit hook can prevent commit
152
152
153 $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
153 $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
154 $ hg commit -m 'fail' -d '4 0'
154 $ hg commit -m 'fail' -d '4 0'
155 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
155 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
156 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
156 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
157 abort: precommit.forbid hook exited with status 1
157 abort: precommit.forbid hook exited with status 1
158 [255]
158 [255]
159 $ hg -q tip
159 $ hg -q tip
160 4:539e4b31b6dc
160 4:539e4b31b6dc
161
161
162 preupdate hook can prevent update
162 preupdate hook can prevent update
163
163
164 $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
164 $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
165 $ hg update 1
165 $ hg update 1
166 preupdate hook: HG_PARENT1=ab228980c14d
166 preupdate hook: HG_PARENT1=ab228980c14d
167 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
167 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
168
168
169 update hook
169 update hook
170
170
171 $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
171 $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
172 $ hg update
172 $ hg update
173 preupdate hook: HG_PARENT1=539e4b31b6dc
173 preupdate hook: HG_PARENT1=539e4b31b6dc
174 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
174 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
175 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
176
176
177 pushkey hook
177 pushkey hook
178
178
179 $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
179 $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
180 $ cd ../b
180 $ cd ../b
181 $ hg bookmark -r null foo
181 $ hg bookmark -r null foo
182 $ hg push -B foo ../a
182 $ hg push -B foo ../a
183 pushing to ../a
183 pushing to ../a
184 searching for changes
184 searching for changes
185 no changes found
185 no changes found
186 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
186 exporting bookmark foo
187 exporting bookmark foo
187 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
188 [1]
188 [1]
189 $ cd ../a
189 $ cd ../a
190
190
191 listkeys hook
191 listkeys hook
192
192
193 $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
193 $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
194 $ hg bookmark -r null bar
194 $ hg bookmark -r null bar
195 $ cd ../b
195 $ cd ../b
196 $ hg pull -B bar ../a
196 $ hg pull -B bar ../a
197 pulling from ../a
197 pulling from ../a
198 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
198 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
199 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
199 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
200 no changes found
200 no changes found
201 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
201 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
202 adding remote bookmark bar
202 adding remote bookmark bar
203 importing bookmark bar
203 importing bookmark bar
204 $ cd ../a
204 $ cd ../a
205
205
206 test that prepushkey can prevent incoming keys
206 test that prepushkey can prevent incoming keys
207
207
208 $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
208 $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
209 $ cd ../b
209 $ cd ../b
210 $ hg bookmark -r null baz
210 $ hg bookmark -r null baz
211 $ hg push -B baz ../a
211 $ hg push -B baz ../a
212 pushing to ../a
212 pushing to ../a
213 searching for changes
213 searching for changes
214 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
214 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
215 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
215 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
216 no changes found
216 no changes found
217 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
217 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
218 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
219 exporting bookmark baz
220 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
218 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
221 abort: prepushkey hook exited with status 1
219 abort: prepushkey hook exited with status 1
222 [255]
220 [255]
223 $ cd ../a
221 $ cd ../a
224
222
225 test that prelistkeys can prevent listing keys
223 test that prelistkeys can prevent listing keys
226
224
227 $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
225 $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
228 $ hg bookmark -r null quux
226 $ hg bookmark -r null quux
229 $ cd ../b
227 $ cd ../b
230 $ hg pull -B quux ../a
228 $ hg pull -B quux ../a
231 pulling from ../a
229 pulling from ../a
232 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
230 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
233 abort: prelistkeys hook exited with status 1
231 abort: prelistkeys hook exited with status 1
234 [255]
232 [255]
235 $ cd ../a
233 $ cd ../a
236 $ rm .hg/hgrc
234 $ rm .hg/hgrc
237
235
238 prechangegroup hook can prevent incoming changes
236 prechangegroup hook can prevent incoming changes
239
237
240 $ cd ../b
238 $ cd ../b
241 $ hg -q tip
239 $ hg -q tip
242 3:07f3376c1e65
240 3:07f3376c1e65
243 $ cat > .hg/hgrc <<EOF
241 $ cat > .hg/hgrc <<EOF
244 > [hooks]
242 > [hooks]
245 > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
243 > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
246 > EOF
244 > EOF
247 $ hg pull ../a
245 $ hg pull ../a
248 pulling from ../a
246 pulling from ../a
249 searching for changes
247 searching for changes
250 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
248 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
251 abort: prechangegroup.forbid hook exited with status 1
249 abort: prechangegroup.forbid hook exited with status 1
252 [255]
250 [255]
253
251
254 pretxnchangegroup hook can see incoming changes, can roll back txn,
252 pretxnchangegroup hook can see incoming changes, can roll back txn,
255 incoming changes no longer there after
253 incoming changes no longer there after
256
254
257 $ cat > .hg/hgrc <<EOF
255 $ cat > .hg/hgrc <<EOF
258 > [hooks]
256 > [hooks]
259 > pretxnchangegroup.forbid0 = hg tip -q
257 > pretxnchangegroup.forbid0 = hg tip -q
260 > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
258 > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
261 > EOF
259 > EOF
262 $ hg pull ../a
260 $ hg pull ../a
263 pulling from ../a
261 pulling from ../a
264 searching for changes
262 searching for changes
265 adding changesets
263 adding changesets
266 adding manifests
264 adding manifests
267 adding file changes
265 adding file changes
268 added 1 changesets with 1 changes to 1 files
266 added 1 changesets with 1 changes to 1 files
269 4:539e4b31b6dc
267 4:539e4b31b6dc
270 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
268 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
271 transaction abort!
269 transaction abort!
272 rollback completed
270 rollback completed
273 abort: pretxnchangegroup.forbid1 hook exited with status 1
271 abort: pretxnchangegroup.forbid1 hook exited with status 1
274 [255]
272 [255]
275 $ hg -q tip
273 $ hg -q tip
276 3:07f3376c1e65
274 3:07f3376c1e65
277
275
278 outgoing hooks can see env vars
276 outgoing hooks can see env vars
279
277
280 $ rm .hg/hgrc
278 $ rm .hg/hgrc
281 $ cat > ../a/.hg/hgrc <<EOF
279 $ cat > ../a/.hg/hgrc <<EOF
282 > [hooks]
280 > [hooks]
283 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
281 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
284 > outgoing = python "$TESTDIR/printenv.py" outgoing
282 > outgoing = python "$TESTDIR/printenv.py" outgoing
285 > EOF
283 > EOF
286 $ hg pull ../a
284 $ hg pull ../a
287 pulling from ../a
285 pulling from ../a
288 searching for changes
286 searching for changes
289 preoutgoing hook: HG_SOURCE=pull
287 preoutgoing hook: HG_SOURCE=pull
290 adding changesets
288 adding changesets
291 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
289 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
292 adding manifests
290 adding manifests
293 adding file changes
291 adding file changes
294 added 1 changesets with 1 changes to 1 files
292 added 1 changesets with 1 changes to 1 files
295 adding remote bookmark quux
293 adding remote bookmark quux
296 (run 'hg update' to get a working copy)
294 (run 'hg update' to get a working copy)
297 $ hg rollback
295 $ hg rollback
298 repository tip rolled back to revision 3 (undo pull)
296 repository tip rolled back to revision 3 (undo pull)
299
297
300 preoutgoing hook can prevent outgoing changes
298 preoutgoing hook can prevent outgoing changes
301
299
302 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
300 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
303 $ hg pull ../a
301 $ hg pull ../a
304 pulling from ../a
302 pulling from ../a
305 searching for changes
303 searching for changes
306 preoutgoing hook: HG_SOURCE=pull
304 preoutgoing hook: HG_SOURCE=pull
307 preoutgoing.forbid hook: HG_SOURCE=pull
305 preoutgoing.forbid hook: HG_SOURCE=pull
308 abort: preoutgoing.forbid hook exited with status 1
306 abort: preoutgoing.forbid hook exited with status 1
309 [255]
307 [255]
310
308
311 outgoing hooks work for local clones
309 outgoing hooks work for local clones
312
310
313 $ cd ..
311 $ cd ..
314 $ cat > a/.hg/hgrc <<EOF
312 $ cat > a/.hg/hgrc <<EOF
315 > [hooks]
313 > [hooks]
316 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
314 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
317 > outgoing = python "$TESTDIR/printenv.py" outgoing
315 > outgoing = python "$TESTDIR/printenv.py" outgoing
318 > EOF
316 > EOF
319 $ hg clone a c
317 $ hg clone a c
320 preoutgoing hook: HG_SOURCE=clone
318 preoutgoing hook: HG_SOURCE=clone
321 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
319 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
322 updating to branch default
320 updating to branch default
323 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
321 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 $ rm -rf c
322 $ rm -rf c
325
323
326 preoutgoing hook can prevent outgoing changes for local clones
324 preoutgoing hook can prevent outgoing changes for local clones
327
325
328 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
326 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
329 $ hg clone a zzz
327 $ hg clone a zzz
330 preoutgoing hook: HG_SOURCE=clone
328 preoutgoing hook: HG_SOURCE=clone
331 preoutgoing.forbid hook: HG_SOURCE=clone
329 preoutgoing.forbid hook: HG_SOURCE=clone
332 abort: preoutgoing.forbid hook exited with status 1
330 abort: preoutgoing.forbid hook exited with status 1
333 [255]
331 [255]
334
332
335 $ cd "$TESTTMP/b"
333 $ cd "$TESTTMP/b"
336
334
337 $ cat > hooktests.py <<EOF
335 $ cat > hooktests.py <<EOF
338 > from mercurial import util
336 > from mercurial import util
339 >
337 >
340 > uncallable = 0
338 > uncallable = 0
341 >
339 >
342 > def printargs(args):
340 > def printargs(args):
343 > args.pop('ui', None)
341 > args.pop('ui', None)
344 > args.pop('repo', None)
342 > args.pop('repo', None)
345 > a = list(args.items())
343 > a = list(args.items())
346 > a.sort()
344 > a.sort()
347 > print 'hook args:'
345 > print 'hook args:'
348 > for k, v in a:
346 > for k, v in a:
349 > print ' ', k, v
347 > print ' ', k, v
350 >
348 >
351 > def passhook(**args):
349 > def passhook(**args):
352 > printargs(args)
350 > printargs(args)
353 >
351 >
354 > def failhook(**args):
352 > def failhook(**args):
355 > printargs(args)
353 > printargs(args)
356 > return True
354 > return True
357 >
355 >
358 > class LocalException(Exception):
356 > class LocalException(Exception):
359 > pass
357 > pass
360 >
358 >
361 > def raisehook(**args):
359 > def raisehook(**args):
362 > raise LocalException('exception from hook')
360 > raise LocalException('exception from hook')
363 >
361 >
364 > def aborthook(**args):
362 > def aborthook(**args):
365 > raise util.Abort('raise abort from hook')
363 > raise util.Abort('raise abort from hook')
366 >
364 >
367 > def brokenhook(**args):
365 > def brokenhook(**args):
368 > return 1 + {}
366 > return 1 + {}
369 >
367 >
370 > def verbosehook(ui, **args):
368 > def verbosehook(ui, **args):
371 > ui.note('verbose output from hook\n')
369 > ui.note('verbose output from hook\n')
372 >
370 >
373 > def printtags(ui, repo, **args):
371 > def printtags(ui, repo, **args):
374 > print sorted(repo.tags())
372 > print sorted(repo.tags())
375 >
373 >
376 > class container:
374 > class container:
377 > unreachable = 1
375 > unreachable = 1
378 > EOF
376 > EOF
379
377
380 test python hooks
378 test python hooks
381
379
382 #if windows
380 #if windows
383 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
381 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
384 #else
382 #else
385 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
383 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
386 #endif
384 #endif
387 $ export PYTHONPATH
385 $ export PYTHONPATH
388
386
389 $ echo '[hooks]' > ../a/.hg/hgrc
387 $ echo '[hooks]' > ../a/.hg/hgrc
390 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
388 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
391 $ hg pull ../a 2>&1 | grep 'raised an exception'
389 $ hg pull ../a 2>&1 | grep 'raised an exception'
392 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
390 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
393
391
394 $ echo '[hooks]' > ../a/.hg/hgrc
392 $ echo '[hooks]' > ../a/.hg/hgrc
395 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
393 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
396 $ hg pull ../a 2>&1 | grep 'raised an exception'
394 $ hg pull ../a 2>&1 | grep 'raised an exception'
397 error: preoutgoing.raise hook raised an exception: exception from hook
395 error: preoutgoing.raise hook raised an exception: exception from hook
398
396
399 $ echo '[hooks]' > ../a/.hg/hgrc
397 $ echo '[hooks]' > ../a/.hg/hgrc
400 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
398 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
401 $ hg pull ../a
399 $ hg pull ../a
402 pulling from ../a
400 pulling from ../a
403 searching for changes
401 searching for changes
404 error: preoutgoing.abort hook failed: raise abort from hook
402 error: preoutgoing.abort hook failed: raise abort from hook
405 abort: raise abort from hook
403 abort: raise abort from hook
406 [255]
404 [255]
407
405
408 $ echo '[hooks]' > ../a/.hg/hgrc
406 $ echo '[hooks]' > ../a/.hg/hgrc
409 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
407 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
410 $ hg pull ../a
408 $ hg pull ../a
411 pulling from ../a
409 pulling from ../a
412 searching for changes
410 searching for changes
413 hook args:
411 hook args:
414 hooktype preoutgoing
412 hooktype preoutgoing
415 source pull
413 source pull
416 abort: preoutgoing.fail hook failed
414 abort: preoutgoing.fail hook failed
417 [255]
415 [255]
418
416
419 $ echo '[hooks]' > ../a/.hg/hgrc
417 $ echo '[hooks]' > ../a/.hg/hgrc
420 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
418 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
421 $ hg pull ../a
419 $ hg pull ../a
422 pulling from ../a
420 pulling from ../a
423 searching for changes
421 searching for changes
424 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
422 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
425 [255]
423 [255]
426
424
427 $ echo '[hooks]' > ../a/.hg/hgrc
425 $ echo '[hooks]' > ../a/.hg/hgrc
428 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
426 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
429 $ hg pull ../a
427 $ hg pull ../a
430 pulling from ../a
428 pulling from ../a
431 searching for changes
429 searching for changes
432 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
430 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
433 [255]
431 [255]
434
432
435 $ echo '[hooks]' > ../a/.hg/hgrc
433 $ echo '[hooks]' > ../a/.hg/hgrc
436 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
434 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
437 $ hg pull ../a
435 $ hg pull ../a
438 pulling from ../a
436 pulling from ../a
439 searching for changes
437 searching for changes
440 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
438 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
441 [255]
439 [255]
442
440
443 $ echo '[hooks]' > ../a/.hg/hgrc
441 $ echo '[hooks]' > ../a/.hg/hgrc
444 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
442 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
445 $ hg pull ../a
443 $ hg pull ../a
446 pulling from ../a
444 pulling from ../a
447 searching for changes
445 searching for changes
448 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
446 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
449 [255]
447 [255]
450
448
451 $ echo '[hooks]' > ../a/.hg/hgrc
449 $ echo '[hooks]' > ../a/.hg/hgrc
452 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
450 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
453 $ hg pull ../a
451 $ hg pull ../a
454 pulling from ../a
452 pulling from ../a
455 searching for changes
453 searching for changes
456 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
454 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
457 [255]
455 [255]
458
456
459 $ echo '[hooks]' > ../a/.hg/hgrc
457 $ echo '[hooks]' > ../a/.hg/hgrc
460 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
458 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
461 $ hg pull ../a
459 $ hg pull ../a
462 pulling from ../a
460 pulling from ../a
463 searching for changes
461 searching for changes
464 hook args:
462 hook args:
465 hooktype preoutgoing
463 hooktype preoutgoing
466 source pull
464 source pull
467 adding changesets
465 adding changesets
468 adding manifests
466 adding manifests
469 adding file changes
467 adding file changes
470 added 1 changesets with 1 changes to 1 files
468 added 1 changesets with 1 changes to 1 files
471 adding remote bookmark quux
469 adding remote bookmark quux
472 (run 'hg update' to get a working copy)
470 (run 'hg update' to get a working copy)
473
471
474 make sure --traceback works
472 make sure --traceback works
475
473
476 $ echo '[hooks]' > .hg/hgrc
474 $ echo '[hooks]' > .hg/hgrc
477 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
475 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
478
476
479 $ echo aa > a
477 $ echo aa > a
480 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
478 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
481 Traceback (most recent call last):
479 Traceback (most recent call last):
482
480
483 $ cd ..
481 $ cd ..
484 $ hg init c
482 $ hg init c
485 $ cd c
483 $ cd c
486
484
487 $ cat > hookext.py <<EOF
485 $ cat > hookext.py <<EOF
488 > def autohook(**args):
486 > def autohook(**args):
489 > print "Automatically installed hook"
487 > print "Automatically installed hook"
490 >
488 >
491 > def reposetup(ui, repo):
489 > def reposetup(ui, repo):
492 > repo.ui.setconfig("hooks", "commit.auto", autohook)
490 > repo.ui.setconfig("hooks", "commit.auto", autohook)
493 > EOF
491 > EOF
494 $ echo '[extensions]' >> .hg/hgrc
492 $ echo '[extensions]' >> .hg/hgrc
495 $ echo 'hookext = hookext.py' >> .hg/hgrc
493 $ echo 'hookext = hookext.py' >> .hg/hgrc
496
494
497 $ touch foo
495 $ touch foo
498 $ hg add foo
496 $ hg add foo
499 $ hg ci -d '0 0' -m 'add foo'
497 $ hg ci -d '0 0' -m 'add foo'
500 Automatically installed hook
498 Automatically installed hook
501 $ echo >> foo
499 $ echo >> foo
502 $ hg ci --debug -d '0 0' -m 'change foo'
500 $ hg ci --debug -d '0 0' -m 'change foo'
503 foo
501 foo
504 calling hook commit.auto: hgext_hookext.autohook
502 calling hook commit.auto: hgext_hookext.autohook
505 Automatically installed hook
503 Automatically installed hook
506 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
504 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
507
505
508 $ hg showconfig hooks
506 $ hg showconfig hooks
509 hooks.commit.auto=<function autohook at *> (glob)
507 hooks.commit.auto=<function autohook at *> (glob)
510
508
511 test python hook configured with python:[file]:[hook] syntax
509 test python hook configured with python:[file]:[hook] syntax
512
510
513 $ cd ..
511 $ cd ..
514 $ mkdir d
512 $ mkdir d
515 $ cd d
513 $ cd d
516 $ hg init repo
514 $ hg init repo
517 $ mkdir hooks
515 $ mkdir hooks
518
516
519 $ cd hooks
517 $ cd hooks
520 $ cat > testhooks.py <<EOF
518 $ cat > testhooks.py <<EOF
521 > def testhook(**args):
519 > def testhook(**args):
522 > print 'hook works'
520 > print 'hook works'
523 > EOF
521 > EOF
524 $ echo '[hooks]' > ../repo/.hg/hgrc
522 $ echo '[hooks]' > ../repo/.hg/hgrc
525 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
523 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
526
524
527 $ cd ../repo
525 $ cd ../repo
528 $ hg commit -d '0 0'
526 $ hg commit -d '0 0'
529 hook works
527 hook works
530 nothing changed
528 nothing changed
531 [1]
529 [1]
532
530
533 $ echo '[hooks]' > .hg/hgrc
531 $ echo '[hooks]' > .hg/hgrc
534 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
532 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
535 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
533 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
536
534
537 $ hg up null
535 $ hg up null
538 loading update.ne hook failed:
536 loading update.ne hook failed:
539 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
537 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
540 [255]
538 [255]
541
539
542 $ hg id
540 $ hg id
543 loading pre-identify.npmd hook failed:
541 loading pre-identify.npmd hook failed:
544 abort: No module named repo!
542 abort: No module named repo!
545 [255]
543 [255]
546
544
547 $ cd ../../b
545 $ cd ../../b
548
546
549 make sure --traceback works on hook import failure
547 make sure --traceback works on hook import failure
550
548
551 $ cat > importfail.py <<EOF
549 $ cat > importfail.py <<EOF
552 > import somebogusmodule
550 > import somebogusmodule
553 > # dereference something in the module to force demandimport to load it
551 > # dereference something in the module to force demandimport to load it
554 > somebogusmodule.whatever
552 > somebogusmodule.whatever
555 > EOF
553 > EOF
556
554
557 $ echo '[hooks]' > .hg/hgrc
555 $ echo '[hooks]' > .hg/hgrc
558 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
556 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
559
557
560 $ echo a >> a
558 $ echo a >> a
561 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
559 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
562 exception from first failed import attempt:
560 exception from first failed import attempt:
563 Traceback (most recent call last):
561 Traceback (most recent call last):
564 ImportError: No module named somebogusmodule
562 ImportError: No module named somebogusmodule
565 exception from second failed import attempt:
563 exception from second failed import attempt:
566 Traceback (most recent call last):
564 Traceback (most recent call last):
567 ImportError: No module named hgext_importfail
565 ImportError: No module named hgext_importfail
568 Traceback (most recent call last):
566 Traceback (most recent call last):
569 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
567 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
570 abort: precommit.importfail hook is invalid (import of "importfail" failed)
568 abort: precommit.importfail hook is invalid (import of "importfail" failed)
571
569
572 Issue1827: Hooks Update & Commit not completely post operation
570 Issue1827: Hooks Update & Commit not completely post operation
573
571
574 commit and update hooks should run after command completion
572 commit and update hooks should run after command completion
575
573
576 $ echo '[hooks]' > .hg/hgrc
574 $ echo '[hooks]' > .hg/hgrc
577 $ echo 'commit = hg id' >> .hg/hgrc
575 $ echo 'commit = hg id' >> .hg/hgrc
578 $ echo 'update = hg id' >> .hg/hgrc
576 $ echo 'update = hg id' >> .hg/hgrc
579 $ echo bb > a
577 $ echo bb > a
580 $ hg ci -ma
578 $ hg ci -ma
581 223eafe2750c tip
579 223eafe2750c tip
582 $ hg up 0
580 $ hg up 0
583 cb9a9f314b8b
581 cb9a9f314b8b
584 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
585
583
586 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
584 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
587 that is passed to pre/post hooks
585 that is passed to pre/post hooks
588
586
589 $ echo '[hooks]' > .hg/hgrc
587 $ echo '[hooks]' > .hg/hgrc
590 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
588 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
591 $ hg id
589 $ hg id
592 cb9a9f314b8b
590 cb9a9f314b8b
593 $ hg id --verbose
591 $ hg id --verbose
594 calling hook pre-identify: hooktests.verbosehook
592 calling hook pre-identify: hooktests.verbosehook
595 verbose output from hook
593 verbose output from hook
596 cb9a9f314b8b
594 cb9a9f314b8b
597
595
598 Ensure hooks can be prioritized
596 Ensure hooks can be prioritized
599
597
600 $ echo '[hooks]' > .hg/hgrc
598 $ echo '[hooks]' > .hg/hgrc
601 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
599 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
602 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
600 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
603 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
601 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
604 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
602 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
605 $ hg id --verbose
603 $ hg id --verbose
606 calling hook pre-identify.b: hooktests.verbosehook
604 calling hook pre-identify.b: hooktests.verbosehook
607 verbose output from hook
605 verbose output from hook
608 calling hook pre-identify.a: hooktests.verbosehook
606 calling hook pre-identify.a: hooktests.verbosehook
609 verbose output from hook
607 verbose output from hook
610 calling hook pre-identify.c: hooktests.verbosehook
608 calling hook pre-identify.c: hooktests.verbosehook
611 verbose output from hook
609 verbose output from hook
612 cb9a9f314b8b
610 cb9a9f314b8b
613
611
614 new tags must be visible in pretxncommit (issue3210)
612 new tags must be visible in pretxncommit (issue3210)
615
613
616 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
614 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
617 $ hg tag -f foo
615 $ hg tag -f foo
618 ['a', 'foo', 'tip']
616 ['a', 'foo', 'tip']
619
617
620 new commits must be visible in pretxnchangegroup (issue3428)
618 new commits must be visible in pretxnchangegroup (issue3428)
621
619
622 $ cd ..
620 $ cd ..
623 $ hg init to
621 $ hg init to
624 $ echo '[hooks]' >> to/.hg/hgrc
622 $ echo '[hooks]' >> to/.hg/hgrc
625 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
623 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
626 $ echo a >> to/a
624 $ echo a >> to/a
627 $ hg --cwd to ci -Ama
625 $ hg --cwd to ci -Ama
628 adding a
626 adding a
629 $ hg clone to from
627 $ hg clone to from
630 updating to branch default
628 updating to branch default
631 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
629 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
632 $ echo aa >> from/a
630 $ echo aa >> from/a
633 $ hg --cwd from ci -mb
631 $ hg --cwd from ci -mb
634 $ hg --cwd from push
632 $ hg --cwd from push
635 pushing to $TESTTMP/to (glob)
633 pushing to $TESTTMP/to (glob)
636 searching for changes
634 searching for changes
637 adding changesets
635 adding changesets
638 adding manifests
636 adding manifests
639 adding file changes
637 adding file changes
640 added 1 changesets with 1 changes to 1 files
638 added 1 changesets with 1 changes to 1 files
641 changeset: 1:9836a07b9b9d
639 changeset: 1:9836a07b9b9d
642 tag: tip
640 tag: tip
643 user: test
641 user: test
644 date: Thu Jan 01 00:00:00 1970 +0000
642 date: Thu Jan 01 00:00:00 1970 +0000
645 summary: b
643 summary: b
646
644
General Comments 0
You need to be logged in to leave comments. Login now