##// END OF EJS Templates
phase: use a binary phase part to push through bundle2 (BC)...
Boris Feld -
r34837:537de0b1 default
parent child Browse files
Show More
@@ -1,2109 +1,2126
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import errno
11 import errno
12 import hashlib
12 import hashlib
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 hex,
16 hex,
17 nullid,
17 nullid,
18 )
18 )
19 from . import (
19 from . import (
20 bookmarks as bookmod,
20 bookmarks as bookmod,
21 bundle2,
21 bundle2,
22 changegroup,
22 changegroup,
23 discovery,
23 discovery,
24 error,
24 error,
25 lock as lockmod,
25 lock as lockmod,
26 obsolete,
26 obsolete,
27 phases,
27 phases,
28 pushkey,
28 pushkey,
29 pycompat,
29 pycompat,
30 scmutil,
30 scmutil,
31 sslutil,
31 sslutil,
32 streamclone,
32 streamclone,
33 url as urlmod,
33 url as urlmod,
34 util,
34 util,
35 )
35 )
36
36
37 urlerr = util.urlerr
37 urlerr = util.urlerr
38 urlreq = util.urlreq
38 urlreq = util.urlreq
39
39
40 # Maps bundle version human names to changegroup versions.
40 # Maps bundle version human names to changegroup versions.
41 _bundlespeccgversions = {'v1': '01',
41 _bundlespeccgversions = {'v1': '01',
42 'v2': '02',
42 'v2': '02',
43 'packed1': 's1',
43 'packed1': 's1',
44 'bundle2': '02', #legacy
44 'bundle2': '02', #legacy
45 }
45 }
46
46
47 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
47 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
48 _bundlespecv1compengines = {'gzip', 'bzip2', 'none'}
48 _bundlespecv1compengines = {'gzip', 'bzip2', 'none'}
49
49
50 def parsebundlespec(repo, spec, strict=True, externalnames=False):
50 def parsebundlespec(repo, spec, strict=True, externalnames=False):
51 """Parse a bundle string specification into parts.
51 """Parse a bundle string specification into parts.
52
52
53 Bundle specifications denote a well-defined bundle/exchange format.
53 Bundle specifications denote a well-defined bundle/exchange format.
54 The content of a given specification should not change over time in
54 The content of a given specification should not change over time in
55 order to ensure that bundles produced by a newer version of Mercurial are
55 order to ensure that bundles produced by a newer version of Mercurial are
56 readable from an older version.
56 readable from an older version.
57
57
58 The string currently has the form:
58 The string currently has the form:
59
59
60 <compression>-<type>[;<parameter0>[;<parameter1>]]
60 <compression>-<type>[;<parameter0>[;<parameter1>]]
61
61
62 Where <compression> is one of the supported compression formats
62 Where <compression> is one of the supported compression formats
63 and <type> is (currently) a version string. A ";" can follow the type and
63 and <type> is (currently) a version string. A ";" can follow the type and
64 all text afterwards is interpreted as URI encoded, ";" delimited key=value
64 all text afterwards is interpreted as URI encoded, ";" delimited key=value
65 pairs.
65 pairs.
66
66
67 If ``strict`` is True (the default) <compression> is required. Otherwise,
67 If ``strict`` is True (the default) <compression> is required. Otherwise,
68 it is optional.
68 it is optional.
69
69
70 If ``externalnames`` is False (the default), the human-centric names will
70 If ``externalnames`` is False (the default), the human-centric names will
71 be converted to their internal representation.
71 be converted to their internal representation.
72
72
73 Returns a 3-tuple of (compression, version, parameters). Compression will
73 Returns a 3-tuple of (compression, version, parameters). Compression will
74 be ``None`` if not in strict mode and a compression isn't defined.
74 be ``None`` if not in strict mode and a compression isn't defined.
75
75
76 An ``InvalidBundleSpecification`` is raised when the specification is
76 An ``InvalidBundleSpecification`` is raised when the specification is
77 not syntactically well formed.
77 not syntactically well formed.
78
78
79 An ``UnsupportedBundleSpecification`` is raised when the compression or
79 An ``UnsupportedBundleSpecification`` is raised when the compression or
80 bundle type/version is not recognized.
80 bundle type/version is not recognized.
81
81
82 Note: this function will likely eventually return a more complex data
82 Note: this function will likely eventually return a more complex data
83 structure, including bundle2 part information.
83 structure, including bundle2 part information.
84 """
84 """
85 def parseparams(s):
85 def parseparams(s):
86 if ';' not in s:
86 if ';' not in s:
87 return s, {}
87 return s, {}
88
88
89 params = {}
89 params = {}
90 version, paramstr = s.split(';', 1)
90 version, paramstr = s.split(';', 1)
91
91
92 for p in paramstr.split(';'):
92 for p in paramstr.split(';'):
93 if '=' not in p:
93 if '=' not in p:
94 raise error.InvalidBundleSpecification(
94 raise error.InvalidBundleSpecification(
95 _('invalid bundle specification: '
95 _('invalid bundle specification: '
96 'missing "=" in parameter: %s') % p)
96 'missing "=" in parameter: %s') % p)
97
97
98 key, value = p.split('=', 1)
98 key, value = p.split('=', 1)
99 key = urlreq.unquote(key)
99 key = urlreq.unquote(key)
100 value = urlreq.unquote(value)
100 value = urlreq.unquote(value)
101 params[key] = value
101 params[key] = value
102
102
103 return version, params
103 return version, params
104
104
105
105
106 if strict and '-' not in spec:
106 if strict and '-' not in spec:
107 raise error.InvalidBundleSpecification(
107 raise error.InvalidBundleSpecification(
108 _('invalid bundle specification; '
108 _('invalid bundle specification; '
109 'must be prefixed with compression: %s') % spec)
109 'must be prefixed with compression: %s') % spec)
110
110
111 if '-' in spec:
111 if '-' in spec:
112 compression, version = spec.split('-', 1)
112 compression, version = spec.split('-', 1)
113
113
114 if compression not in util.compengines.supportedbundlenames:
114 if compression not in util.compengines.supportedbundlenames:
115 raise error.UnsupportedBundleSpecification(
115 raise error.UnsupportedBundleSpecification(
116 _('%s compression is not supported') % compression)
116 _('%s compression is not supported') % compression)
117
117
118 version, params = parseparams(version)
118 version, params = parseparams(version)
119
119
120 if version not in _bundlespeccgversions:
120 if version not in _bundlespeccgversions:
121 raise error.UnsupportedBundleSpecification(
121 raise error.UnsupportedBundleSpecification(
122 _('%s is not a recognized bundle version') % version)
122 _('%s is not a recognized bundle version') % version)
123 else:
123 else:
124 # Value could be just the compression or just the version, in which
124 # Value could be just the compression or just the version, in which
125 # case some defaults are assumed (but only when not in strict mode).
125 # case some defaults are assumed (but only when not in strict mode).
126 assert not strict
126 assert not strict
127
127
128 spec, params = parseparams(spec)
128 spec, params = parseparams(spec)
129
129
130 if spec in util.compengines.supportedbundlenames:
130 if spec in util.compengines.supportedbundlenames:
131 compression = spec
131 compression = spec
132 version = 'v1'
132 version = 'v1'
133 # Generaldelta repos require v2.
133 # Generaldelta repos require v2.
134 if 'generaldelta' in repo.requirements:
134 if 'generaldelta' in repo.requirements:
135 version = 'v2'
135 version = 'v2'
136 # Modern compression engines require v2.
136 # Modern compression engines require v2.
137 if compression not in _bundlespecv1compengines:
137 if compression not in _bundlespecv1compengines:
138 version = 'v2'
138 version = 'v2'
139 elif spec in _bundlespeccgversions:
139 elif spec in _bundlespeccgversions:
140 if spec == 'packed1':
140 if spec == 'packed1':
141 compression = 'none'
141 compression = 'none'
142 else:
142 else:
143 compression = 'bzip2'
143 compression = 'bzip2'
144 version = spec
144 version = spec
145 else:
145 else:
146 raise error.UnsupportedBundleSpecification(
146 raise error.UnsupportedBundleSpecification(
147 _('%s is not a recognized bundle specification') % spec)
147 _('%s is not a recognized bundle specification') % spec)
148
148
149 # Bundle version 1 only supports a known set of compression engines.
149 # Bundle version 1 only supports a known set of compression engines.
150 if version == 'v1' and compression not in _bundlespecv1compengines:
150 if version == 'v1' and compression not in _bundlespecv1compengines:
151 raise error.UnsupportedBundleSpecification(
151 raise error.UnsupportedBundleSpecification(
152 _('compression engine %s is not supported on v1 bundles') %
152 _('compression engine %s is not supported on v1 bundles') %
153 compression)
153 compression)
154
154
155 # The specification for packed1 can optionally declare the data formats
155 # The specification for packed1 can optionally declare the data formats
156 # required to apply it. If we see this metadata, compare against what the
156 # required to apply it. If we see this metadata, compare against what the
157 # repo supports and error if the bundle isn't compatible.
157 # repo supports and error if the bundle isn't compatible.
158 if version == 'packed1' and 'requirements' in params:
158 if version == 'packed1' and 'requirements' in params:
159 requirements = set(params['requirements'].split(','))
159 requirements = set(params['requirements'].split(','))
160 missingreqs = requirements - repo.supportedformats
160 missingreqs = requirements - repo.supportedformats
161 if missingreqs:
161 if missingreqs:
162 raise error.UnsupportedBundleSpecification(
162 raise error.UnsupportedBundleSpecification(
163 _('missing support for repository features: %s') %
163 _('missing support for repository features: %s') %
164 ', '.join(sorted(missingreqs)))
164 ', '.join(sorted(missingreqs)))
165
165
166 if not externalnames:
166 if not externalnames:
167 engine = util.compengines.forbundlename(compression)
167 engine = util.compengines.forbundlename(compression)
168 compression = engine.bundletype()[1]
168 compression = engine.bundletype()[1]
169 version = _bundlespeccgversions[version]
169 version = _bundlespeccgversions[version]
170 return compression, version, params
170 return compression, version, params
171
171
172 def readbundle(ui, fh, fname, vfs=None):
172 def readbundle(ui, fh, fname, vfs=None):
173 header = changegroup.readexactly(fh, 4)
173 header = changegroup.readexactly(fh, 4)
174
174
175 alg = None
175 alg = None
176 if not fname:
176 if not fname:
177 fname = "stream"
177 fname = "stream"
178 if not header.startswith('HG') and header.startswith('\0'):
178 if not header.startswith('HG') and header.startswith('\0'):
179 fh = changegroup.headerlessfixup(fh, header)
179 fh = changegroup.headerlessfixup(fh, header)
180 header = "HG10"
180 header = "HG10"
181 alg = 'UN'
181 alg = 'UN'
182 elif vfs:
182 elif vfs:
183 fname = vfs.join(fname)
183 fname = vfs.join(fname)
184
184
185 magic, version = header[0:2], header[2:4]
185 magic, version = header[0:2], header[2:4]
186
186
187 if magic != 'HG':
187 if magic != 'HG':
188 raise error.Abort(_('%s: not a Mercurial bundle') % fname)
188 raise error.Abort(_('%s: not a Mercurial bundle') % fname)
189 if version == '10':
189 if version == '10':
190 if alg is None:
190 if alg is None:
191 alg = changegroup.readexactly(fh, 2)
191 alg = changegroup.readexactly(fh, 2)
192 return changegroup.cg1unpacker(fh, alg)
192 return changegroup.cg1unpacker(fh, alg)
193 elif version.startswith('2'):
193 elif version.startswith('2'):
194 return bundle2.getunbundler(ui, fh, magicstring=magic + version)
194 return bundle2.getunbundler(ui, fh, magicstring=magic + version)
195 elif version == 'S1':
195 elif version == 'S1':
196 return streamclone.streamcloneapplier(fh)
196 return streamclone.streamcloneapplier(fh)
197 else:
197 else:
198 raise error.Abort(_('%s: unknown bundle version %s') % (fname, version))
198 raise error.Abort(_('%s: unknown bundle version %s') % (fname, version))
199
199
200 def getbundlespec(ui, fh):
200 def getbundlespec(ui, fh):
201 """Infer the bundlespec from a bundle file handle.
201 """Infer the bundlespec from a bundle file handle.
202
202
203 The input file handle is seeked and the original seek position is not
203 The input file handle is seeked and the original seek position is not
204 restored.
204 restored.
205 """
205 """
206 def speccompression(alg):
206 def speccompression(alg):
207 try:
207 try:
208 return util.compengines.forbundletype(alg).bundletype()[0]
208 return util.compengines.forbundletype(alg).bundletype()[0]
209 except KeyError:
209 except KeyError:
210 return None
210 return None
211
211
212 b = readbundle(ui, fh, None)
212 b = readbundle(ui, fh, None)
213 if isinstance(b, changegroup.cg1unpacker):
213 if isinstance(b, changegroup.cg1unpacker):
214 alg = b._type
214 alg = b._type
215 if alg == '_truncatedBZ':
215 if alg == '_truncatedBZ':
216 alg = 'BZ'
216 alg = 'BZ'
217 comp = speccompression(alg)
217 comp = speccompression(alg)
218 if not comp:
218 if not comp:
219 raise error.Abort(_('unknown compression algorithm: %s') % alg)
219 raise error.Abort(_('unknown compression algorithm: %s') % alg)
220 return '%s-v1' % comp
220 return '%s-v1' % comp
221 elif isinstance(b, bundle2.unbundle20):
221 elif isinstance(b, bundle2.unbundle20):
222 if 'Compression' in b.params:
222 if 'Compression' in b.params:
223 comp = speccompression(b.params['Compression'])
223 comp = speccompression(b.params['Compression'])
224 if not comp:
224 if not comp:
225 raise error.Abort(_('unknown compression algorithm: %s') % comp)
225 raise error.Abort(_('unknown compression algorithm: %s') % comp)
226 else:
226 else:
227 comp = 'none'
227 comp = 'none'
228
228
229 version = None
229 version = None
230 for part in b.iterparts():
230 for part in b.iterparts():
231 if part.type == 'changegroup':
231 if part.type == 'changegroup':
232 version = part.params['version']
232 version = part.params['version']
233 if version in ('01', '02'):
233 if version in ('01', '02'):
234 version = 'v2'
234 version = 'v2'
235 else:
235 else:
236 raise error.Abort(_('changegroup version %s does not have '
236 raise error.Abort(_('changegroup version %s does not have '
237 'a known bundlespec') % version,
237 'a known bundlespec') % version,
238 hint=_('try upgrading your Mercurial '
238 hint=_('try upgrading your Mercurial '
239 'client'))
239 'client'))
240
240
241 if not version:
241 if not version:
242 raise error.Abort(_('could not identify changegroup version in '
242 raise error.Abort(_('could not identify changegroup version in '
243 'bundle'))
243 'bundle'))
244
244
245 return '%s-%s' % (comp, version)
245 return '%s-%s' % (comp, version)
246 elif isinstance(b, streamclone.streamcloneapplier):
246 elif isinstance(b, streamclone.streamcloneapplier):
247 requirements = streamclone.readbundle1header(fh)[2]
247 requirements = streamclone.readbundle1header(fh)[2]
248 params = 'requirements=%s' % ','.join(sorted(requirements))
248 params = 'requirements=%s' % ','.join(sorted(requirements))
249 return 'none-packed1;%s' % urlreq.quote(params)
249 return 'none-packed1;%s' % urlreq.quote(params)
250 else:
250 else:
251 raise error.Abort(_('unknown bundle type: %s') % b)
251 raise error.Abort(_('unknown bundle type: %s') % b)
252
252
253 def _computeoutgoing(repo, heads, common):
253 def _computeoutgoing(repo, heads, common):
254 """Computes which revs are outgoing given a set of common
254 """Computes which revs are outgoing given a set of common
255 and a set of heads.
255 and a set of heads.
256
256
257 This is a separate function so extensions can have access to
257 This is a separate function so extensions can have access to
258 the logic.
258 the logic.
259
259
260 Returns a discovery.outgoing object.
260 Returns a discovery.outgoing object.
261 """
261 """
262 cl = repo.changelog
262 cl = repo.changelog
263 if common:
263 if common:
264 hasnode = cl.hasnode
264 hasnode = cl.hasnode
265 common = [n for n in common if hasnode(n)]
265 common = [n for n in common if hasnode(n)]
266 else:
266 else:
267 common = [nullid]
267 common = [nullid]
268 if not heads:
268 if not heads:
269 heads = cl.heads()
269 heads = cl.heads()
270 return discovery.outgoing(repo, common, heads)
270 return discovery.outgoing(repo, common, heads)
271
271
272 def _forcebundle1(op):
272 def _forcebundle1(op):
273 """return true if a pull/push must use bundle1
273 """return true if a pull/push must use bundle1
274
274
275 This function is used to allow testing of the older bundle version"""
275 This function is used to allow testing of the older bundle version"""
276 ui = op.repo.ui
276 ui = op.repo.ui
277 forcebundle1 = False
277 forcebundle1 = False
278 # The goal is this config is to allow developer to choose the bundle
278 # The goal is this config is to allow developer to choose the bundle
279 # version used during exchanged. This is especially handy during test.
279 # version used during exchanged. This is especially handy during test.
280 # Value is a list of bundle version to be picked from, highest version
280 # Value is a list of bundle version to be picked from, highest version
281 # should be used.
281 # should be used.
282 #
282 #
283 # developer config: devel.legacy.exchange
283 # developer config: devel.legacy.exchange
284 exchange = ui.configlist('devel', 'legacy.exchange')
284 exchange = ui.configlist('devel', 'legacy.exchange')
285 forcebundle1 = 'bundle2' not in exchange and 'bundle1' in exchange
285 forcebundle1 = 'bundle2' not in exchange and 'bundle1' in exchange
286 return forcebundle1 or not op.remote.capable('bundle2')
286 return forcebundle1 or not op.remote.capable('bundle2')
287
287
288 class pushoperation(object):
288 class pushoperation(object):
289 """A object that represent a single push operation
289 """A object that represent a single push operation
290
290
291 Its purpose is to carry push related state and very common operations.
291 Its purpose is to carry push related state and very common operations.
292
292
293 A new pushoperation should be created at the beginning of each push and
293 A new pushoperation should be created at the beginning of each push and
294 discarded afterward.
294 discarded afterward.
295 """
295 """
296
296
297 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
297 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
298 bookmarks=(), pushvars=None):
298 bookmarks=(), pushvars=None):
299 # repo we push from
299 # repo we push from
300 self.repo = repo
300 self.repo = repo
301 self.ui = repo.ui
301 self.ui = repo.ui
302 # repo we push to
302 # repo we push to
303 self.remote = remote
303 self.remote = remote
304 # force option provided
304 # force option provided
305 self.force = force
305 self.force = force
306 # revs to be pushed (None is "all")
306 # revs to be pushed (None is "all")
307 self.revs = revs
307 self.revs = revs
308 # bookmark explicitly pushed
308 # bookmark explicitly pushed
309 self.bookmarks = bookmarks
309 self.bookmarks = bookmarks
310 # allow push of new branch
310 # allow push of new branch
311 self.newbranch = newbranch
311 self.newbranch = newbranch
312 # step already performed
312 # step already performed
313 # (used to check what steps have been already performed through bundle2)
313 # (used to check what steps have been already performed through bundle2)
314 self.stepsdone = set()
314 self.stepsdone = set()
315 # Integer version of the changegroup push result
315 # Integer version of the changegroup push result
316 # - None means nothing to push
316 # - None means nothing to push
317 # - 0 means HTTP error
317 # - 0 means HTTP error
318 # - 1 means we pushed and remote head count is unchanged *or*
318 # - 1 means we pushed and remote head count is unchanged *or*
319 # we have outgoing changesets but refused to push
319 # we have outgoing changesets but refused to push
320 # - other values as described by addchangegroup()
320 # - other values as described by addchangegroup()
321 self.cgresult = None
321 self.cgresult = None
322 # Boolean value for the bookmark push
322 # Boolean value for the bookmark push
323 self.bkresult = None
323 self.bkresult = None
324 # discover.outgoing object (contains common and outgoing data)
324 # discover.outgoing object (contains common and outgoing data)
325 self.outgoing = None
325 self.outgoing = None
326 # all remote topological heads before the push
326 # all remote topological heads before the push
327 self.remoteheads = None
327 self.remoteheads = None
328 # Details of the remote branch pre and post push
328 # Details of the remote branch pre and post push
329 #
329 #
330 # mapping: {'branch': ([remoteheads],
330 # mapping: {'branch': ([remoteheads],
331 # [newheads],
331 # [newheads],
332 # [unsyncedheads],
332 # [unsyncedheads],
333 # [discardedheads])}
333 # [discardedheads])}
334 # - branch: the branch name
334 # - branch: the branch name
335 # - remoteheads: the list of remote heads known locally
335 # - remoteheads: the list of remote heads known locally
336 # None if the branch is new
336 # None if the branch is new
337 # - newheads: the new remote heads (known locally) with outgoing pushed
337 # - newheads: the new remote heads (known locally) with outgoing pushed
338 # - unsyncedheads: the list of remote heads unknown locally.
338 # - unsyncedheads: the list of remote heads unknown locally.
339 # - discardedheads: the list of remote heads made obsolete by the push
339 # - discardedheads: the list of remote heads made obsolete by the push
340 self.pushbranchmap = None
340 self.pushbranchmap = None
341 # testable as a boolean indicating if any nodes are missing locally.
341 # testable as a boolean indicating if any nodes are missing locally.
342 self.incoming = None
342 self.incoming = None
343 # summary of the remote phase situation
343 # summary of the remote phase situation
344 self.remotephases = None
344 self.remotephases = None
345 # phases changes that must be pushed along side the changesets
345 # phases changes that must be pushed along side the changesets
346 self.outdatedphases = None
346 self.outdatedphases = None
347 # phases changes that must be pushed if changeset push fails
347 # phases changes that must be pushed if changeset push fails
348 self.fallbackoutdatedphases = None
348 self.fallbackoutdatedphases = None
349 # outgoing obsmarkers
349 # outgoing obsmarkers
350 self.outobsmarkers = set()
350 self.outobsmarkers = set()
351 # outgoing bookmarks
351 # outgoing bookmarks
352 self.outbookmarks = []
352 self.outbookmarks = []
353 # transaction manager
353 # transaction manager
354 self.trmanager = None
354 self.trmanager = None
355 # map { pushkey partid -> callback handling failure}
355 # map { pushkey partid -> callback handling failure}
356 # used to handle exception from mandatory pushkey part failure
356 # used to handle exception from mandatory pushkey part failure
357 self.pkfailcb = {}
357 self.pkfailcb = {}
358 # an iterable of pushvars or None
358 # an iterable of pushvars or None
359 self.pushvars = pushvars
359 self.pushvars = pushvars
360
360
361 @util.propertycache
361 @util.propertycache
362 def futureheads(self):
362 def futureheads(self):
363 """future remote heads if the changeset push succeeds"""
363 """future remote heads if the changeset push succeeds"""
364 return self.outgoing.missingheads
364 return self.outgoing.missingheads
365
365
366 @util.propertycache
366 @util.propertycache
367 def fallbackheads(self):
367 def fallbackheads(self):
368 """future remote heads if the changeset push fails"""
368 """future remote heads if the changeset push fails"""
369 if self.revs is None:
369 if self.revs is None:
370 # not target to push, all common are relevant
370 # not target to push, all common are relevant
371 return self.outgoing.commonheads
371 return self.outgoing.commonheads
372 unfi = self.repo.unfiltered()
372 unfi = self.repo.unfiltered()
373 # I want cheads = heads(::missingheads and ::commonheads)
373 # I want cheads = heads(::missingheads and ::commonheads)
374 # (missingheads is revs with secret changeset filtered out)
374 # (missingheads is revs with secret changeset filtered out)
375 #
375 #
376 # This can be expressed as:
376 # This can be expressed as:
377 # cheads = ( (missingheads and ::commonheads)
377 # cheads = ( (missingheads and ::commonheads)
378 # + (commonheads and ::missingheads))"
378 # + (commonheads and ::missingheads))"
379 # )
379 # )
380 #
380 #
381 # while trying to push we already computed the following:
381 # while trying to push we already computed the following:
382 # common = (::commonheads)
382 # common = (::commonheads)
383 # missing = ((commonheads::missingheads) - commonheads)
383 # missing = ((commonheads::missingheads) - commonheads)
384 #
384 #
385 # We can pick:
385 # We can pick:
386 # * missingheads part of common (::commonheads)
386 # * missingheads part of common (::commonheads)
387 common = self.outgoing.common
387 common = self.outgoing.common
388 nm = self.repo.changelog.nodemap
388 nm = self.repo.changelog.nodemap
389 cheads = [node for node in self.revs if nm[node] in common]
389 cheads = [node for node in self.revs if nm[node] in common]
390 # and
390 # and
391 # * commonheads parents on missing
391 # * commonheads parents on missing
392 revset = unfi.set('%ln and parents(roots(%ln))',
392 revset = unfi.set('%ln and parents(roots(%ln))',
393 self.outgoing.commonheads,
393 self.outgoing.commonheads,
394 self.outgoing.missing)
394 self.outgoing.missing)
395 cheads.extend(c.node() for c in revset)
395 cheads.extend(c.node() for c in revset)
396 return cheads
396 return cheads
397
397
398 @property
398 @property
399 def commonheads(self):
399 def commonheads(self):
400 """set of all common heads after changeset bundle push"""
400 """set of all common heads after changeset bundle push"""
401 if self.cgresult:
401 if self.cgresult:
402 return self.futureheads
402 return self.futureheads
403 else:
403 else:
404 return self.fallbackheads
404 return self.fallbackheads
405
405
406 # mapping of message used when pushing bookmark
406 # mapping of message used when pushing bookmark
407 bookmsgmap = {'update': (_("updating bookmark %s\n"),
407 bookmsgmap = {'update': (_("updating bookmark %s\n"),
408 _('updating bookmark %s failed!\n')),
408 _('updating bookmark %s failed!\n')),
409 'export': (_("exporting bookmark %s\n"),
409 'export': (_("exporting bookmark %s\n"),
410 _('exporting bookmark %s failed!\n')),
410 _('exporting bookmark %s failed!\n')),
411 'delete': (_("deleting remote bookmark %s\n"),
411 'delete': (_("deleting remote bookmark %s\n"),
412 _('deleting remote bookmark %s failed!\n')),
412 _('deleting remote bookmark %s failed!\n')),
413 }
413 }
414
414
415
415
416 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=(),
416 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=(),
417 opargs=None):
417 opargs=None):
418 '''Push outgoing changesets (limited by revs) from a local
418 '''Push outgoing changesets (limited by revs) from a local
419 repository to remote. Return an integer:
419 repository to remote. Return an integer:
420 - None means nothing to push
420 - None means nothing to push
421 - 0 means HTTP error
421 - 0 means HTTP error
422 - 1 means we pushed and remote head count is unchanged *or*
422 - 1 means we pushed and remote head count is unchanged *or*
423 we have outgoing changesets but refused to push
423 we have outgoing changesets but refused to push
424 - other values as described by addchangegroup()
424 - other values as described by addchangegroup()
425 '''
425 '''
426 if opargs is None:
426 if opargs is None:
427 opargs = {}
427 opargs = {}
428 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks,
428 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks,
429 **pycompat.strkwargs(opargs))
429 **pycompat.strkwargs(opargs))
430 if pushop.remote.local():
430 if pushop.remote.local():
431 missing = (set(pushop.repo.requirements)
431 missing = (set(pushop.repo.requirements)
432 - pushop.remote.local().supported)
432 - pushop.remote.local().supported)
433 if missing:
433 if missing:
434 msg = _("required features are not"
434 msg = _("required features are not"
435 " supported in the destination:"
435 " supported in the destination:"
436 " %s") % (', '.join(sorted(missing)))
436 " %s") % (', '.join(sorted(missing)))
437 raise error.Abort(msg)
437 raise error.Abort(msg)
438
438
439 if not pushop.remote.canpush():
439 if not pushop.remote.canpush():
440 raise error.Abort(_("destination does not support push"))
440 raise error.Abort(_("destination does not support push"))
441
441
442 if not pushop.remote.capable('unbundle'):
442 if not pushop.remote.capable('unbundle'):
443 raise error.Abort(_('cannot push: destination does not support the '
443 raise error.Abort(_('cannot push: destination does not support the '
444 'unbundle wire protocol command'))
444 'unbundle wire protocol command'))
445
445
446 # get lock as we might write phase data
446 # get lock as we might write phase data
447 wlock = lock = None
447 wlock = lock = None
448 try:
448 try:
449 # bundle2 push may receive a reply bundle touching bookmarks or other
449 # bundle2 push may receive a reply bundle touching bookmarks or other
450 # things requiring the wlock. Take it now to ensure proper ordering.
450 # things requiring the wlock. Take it now to ensure proper ordering.
451 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
451 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
452 if (not _forcebundle1(pushop)) and maypushback:
452 if (not _forcebundle1(pushop)) and maypushback:
453 wlock = pushop.repo.wlock()
453 wlock = pushop.repo.wlock()
454 lock = pushop.repo.lock()
454 lock = pushop.repo.lock()
455 pushop.trmanager = transactionmanager(pushop.repo,
455 pushop.trmanager = transactionmanager(pushop.repo,
456 'push-response',
456 'push-response',
457 pushop.remote.url())
457 pushop.remote.url())
458 except IOError as err:
458 except IOError as err:
459 if err.errno != errno.EACCES:
459 if err.errno != errno.EACCES:
460 raise
460 raise
461 # source repo cannot be locked.
461 # source repo cannot be locked.
462 # We do not abort the push, but just disable the local phase
462 # We do not abort the push, but just disable the local phase
463 # synchronisation.
463 # synchronisation.
464 msg = 'cannot lock source repository: %s\n' % err
464 msg = 'cannot lock source repository: %s\n' % err
465 pushop.ui.debug(msg)
465 pushop.ui.debug(msg)
466
466
467 with wlock or util.nullcontextmanager(), \
467 with wlock or util.nullcontextmanager(), \
468 lock or util.nullcontextmanager(), \
468 lock or util.nullcontextmanager(), \
469 pushop.trmanager or util.nullcontextmanager():
469 pushop.trmanager or util.nullcontextmanager():
470 pushop.repo.checkpush(pushop)
470 pushop.repo.checkpush(pushop)
471 _pushdiscovery(pushop)
471 _pushdiscovery(pushop)
472 if not _forcebundle1(pushop):
472 if not _forcebundle1(pushop):
473 _pushbundle2(pushop)
473 _pushbundle2(pushop)
474 _pushchangeset(pushop)
474 _pushchangeset(pushop)
475 _pushsyncphase(pushop)
475 _pushsyncphase(pushop)
476 _pushobsolete(pushop)
476 _pushobsolete(pushop)
477 _pushbookmark(pushop)
477 _pushbookmark(pushop)
478
478
479 return pushop
479 return pushop
480
480
481 # list of steps to perform discovery before push
481 # list of steps to perform discovery before push
482 pushdiscoveryorder = []
482 pushdiscoveryorder = []
483
483
484 # Mapping between step name and function
484 # Mapping between step name and function
485 #
485 #
486 # This exists to help extensions wrap steps if necessary
486 # This exists to help extensions wrap steps if necessary
487 pushdiscoverymapping = {}
487 pushdiscoverymapping = {}
488
488
489 def pushdiscovery(stepname):
489 def pushdiscovery(stepname):
490 """decorator for function performing discovery before push
490 """decorator for function performing discovery before push
491
491
492 The function is added to the step -> function mapping and appended to the
492 The function is added to the step -> function mapping and appended to the
493 list of steps. Beware that decorated function will be added in order (this
493 list of steps. Beware that decorated function will be added in order (this
494 may matter).
494 may matter).
495
495
496 You can only use this decorator for a new step, if you want to wrap a step
496 You can only use this decorator for a new step, if you want to wrap a step
497 from an extension, change the pushdiscovery dictionary directly."""
497 from an extension, change the pushdiscovery dictionary directly."""
498 def dec(func):
498 def dec(func):
499 assert stepname not in pushdiscoverymapping
499 assert stepname not in pushdiscoverymapping
500 pushdiscoverymapping[stepname] = func
500 pushdiscoverymapping[stepname] = func
501 pushdiscoveryorder.append(stepname)
501 pushdiscoveryorder.append(stepname)
502 return func
502 return func
503 return dec
503 return dec
504
504
505 def _pushdiscovery(pushop):
505 def _pushdiscovery(pushop):
506 """Run all discovery steps"""
506 """Run all discovery steps"""
507 for stepname in pushdiscoveryorder:
507 for stepname in pushdiscoveryorder:
508 step = pushdiscoverymapping[stepname]
508 step = pushdiscoverymapping[stepname]
509 step(pushop)
509 step(pushop)
510
510
511 @pushdiscovery('changeset')
511 @pushdiscovery('changeset')
512 def _pushdiscoverychangeset(pushop):
512 def _pushdiscoverychangeset(pushop):
513 """discover the changeset that need to be pushed"""
513 """discover the changeset that need to be pushed"""
514 fci = discovery.findcommonincoming
514 fci = discovery.findcommonincoming
515 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
515 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
516 common, inc, remoteheads = commoninc
516 common, inc, remoteheads = commoninc
517 fco = discovery.findcommonoutgoing
517 fco = discovery.findcommonoutgoing
518 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
518 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
519 commoninc=commoninc, force=pushop.force)
519 commoninc=commoninc, force=pushop.force)
520 pushop.outgoing = outgoing
520 pushop.outgoing = outgoing
521 pushop.remoteheads = remoteheads
521 pushop.remoteheads = remoteheads
522 pushop.incoming = inc
522 pushop.incoming = inc
523
523
524 @pushdiscovery('phase')
524 @pushdiscovery('phase')
525 def _pushdiscoveryphase(pushop):
525 def _pushdiscoveryphase(pushop):
526 """discover the phase that needs to be pushed
526 """discover the phase that needs to be pushed
527
527
528 (computed for both success and failure case for changesets push)"""
528 (computed for both success and failure case for changesets push)"""
529 outgoing = pushop.outgoing
529 outgoing = pushop.outgoing
530 unfi = pushop.repo.unfiltered()
530 unfi = pushop.repo.unfiltered()
531 remotephases = pushop.remote.listkeys('phases')
531 remotephases = pushop.remote.listkeys('phases')
532 if (pushop.ui.configbool('ui', '_usedassubrepo')
532 if (pushop.ui.configbool('ui', '_usedassubrepo')
533 and remotephases # server supports phases
533 and remotephases # server supports phases
534 and not pushop.outgoing.missing # no changesets to be pushed
534 and not pushop.outgoing.missing # no changesets to be pushed
535 and remotephases.get('publishing', False)):
535 and remotephases.get('publishing', False)):
536 # When:
536 # When:
537 # - this is a subrepo push
537 # - this is a subrepo push
538 # - and remote support phase
538 # - and remote support phase
539 # - and no changeset are to be pushed
539 # - and no changeset are to be pushed
540 # - and remote is publishing
540 # - and remote is publishing
541 # We may be in issue 3781 case!
541 # We may be in issue 3781 case!
542 # We drop the possible phase synchronisation done by
542 # We drop the possible phase synchronisation done by
543 # courtesy to publish changesets possibly locally draft
543 # courtesy to publish changesets possibly locally draft
544 # on the remote.
544 # on the remote.
545 pushop.outdatedphases = []
545 pushop.outdatedphases = []
546 pushop.fallbackoutdatedphases = []
546 pushop.fallbackoutdatedphases = []
547 return
547 return
548
548
549 pushop.remotephases = phases.remotephasessummary(pushop.repo,
549 pushop.remotephases = phases.remotephasessummary(pushop.repo,
550 pushop.fallbackheads,
550 pushop.fallbackheads,
551 remotephases)
551 remotephases)
552 droots = pushop.remotephases.draftroots
552 droots = pushop.remotephases.draftroots
553
553
554 extracond = ''
554 extracond = ''
555 if not pushop.remotephases.publishing:
555 if not pushop.remotephases.publishing:
556 extracond = ' and public()'
556 extracond = ' and public()'
557 revset = 'heads((%%ln::%%ln) %s)' % extracond
557 revset = 'heads((%%ln::%%ln) %s)' % extracond
558 # Get the list of all revs draft on remote by public here.
558 # Get the list of all revs draft on remote by public here.
559 # XXX Beware that revset break if droots is not strictly
559 # XXX Beware that revset break if droots is not strictly
560 # XXX root we may want to ensure it is but it is costly
560 # XXX root we may want to ensure it is but it is costly
561 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
561 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
562 if not outgoing.missing:
562 if not outgoing.missing:
563 future = fallback
563 future = fallback
564 else:
564 else:
565 # adds changeset we are going to push as draft
565 # adds changeset we are going to push as draft
566 #
566 #
567 # should not be necessary for publishing server, but because of an
567 # should not be necessary for publishing server, but because of an
568 # issue fixed in xxxxx we have to do it anyway.
568 # issue fixed in xxxxx we have to do it anyway.
569 fdroots = list(unfi.set('roots(%ln + %ln::)',
569 fdroots = list(unfi.set('roots(%ln + %ln::)',
570 outgoing.missing, droots))
570 outgoing.missing, droots))
571 fdroots = [f.node() for f in fdroots]
571 fdroots = [f.node() for f in fdroots]
572 future = list(unfi.set(revset, fdroots, pushop.futureheads))
572 future = list(unfi.set(revset, fdroots, pushop.futureheads))
573 pushop.outdatedphases = future
573 pushop.outdatedphases = future
574 pushop.fallbackoutdatedphases = fallback
574 pushop.fallbackoutdatedphases = fallback
575
575
576 @pushdiscovery('obsmarker')
576 @pushdiscovery('obsmarker')
577 def _pushdiscoveryobsmarkers(pushop):
577 def _pushdiscoveryobsmarkers(pushop):
578 if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
578 if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
579 and pushop.repo.obsstore
579 and pushop.repo.obsstore
580 and 'obsolete' in pushop.remote.listkeys('namespaces')):
580 and 'obsolete' in pushop.remote.listkeys('namespaces')):
581 repo = pushop.repo
581 repo = pushop.repo
582 # very naive computation, that can be quite expensive on big repo.
582 # very naive computation, that can be quite expensive on big repo.
583 # However: evolution is currently slow on them anyway.
583 # However: evolution is currently slow on them anyway.
584 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
584 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
585 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
585 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
586
586
587 @pushdiscovery('bookmarks')
587 @pushdiscovery('bookmarks')
588 def _pushdiscoverybookmarks(pushop):
588 def _pushdiscoverybookmarks(pushop):
589 ui = pushop.ui
589 ui = pushop.ui
590 repo = pushop.repo.unfiltered()
590 repo = pushop.repo.unfiltered()
591 remote = pushop.remote
591 remote = pushop.remote
592 ui.debug("checking for updated bookmarks\n")
592 ui.debug("checking for updated bookmarks\n")
593 ancestors = ()
593 ancestors = ()
594 if pushop.revs:
594 if pushop.revs:
595 revnums = map(repo.changelog.rev, pushop.revs)
595 revnums = map(repo.changelog.rev, pushop.revs)
596 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
596 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
597 remotebookmark = remote.listkeys('bookmarks')
597 remotebookmark = remote.listkeys('bookmarks')
598
598
599 explicit = set([repo._bookmarks.expandname(bookmark)
599 explicit = set([repo._bookmarks.expandname(bookmark)
600 for bookmark in pushop.bookmarks])
600 for bookmark in pushop.bookmarks])
601
601
602 remotebookmark = bookmod.unhexlifybookmarks(remotebookmark)
602 remotebookmark = bookmod.unhexlifybookmarks(remotebookmark)
603 comp = bookmod.comparebookmarks(repo, repo._bookmarks, remotebookmark)
603 comp = bookmod.comparebookmarks(repo, repo._bookmarks, remotebookmark)
604
604
605 def safehex(x):
605 def safehex(x):
606 if x is None:
606 if x is None:
607 return x
607 return x
608 return hex(x)
608 return hex(x)
609
609
610 def hexifycompbookmarks(bookmarks):
610 def hexifycompbookmarks(bookmarks):
611 for b, scid, dcid in bookmarks:
611 for b, scid, dcid in bookmarks:
612 yield b, safehex(scid), safehex(dcid)
612 yield b, safehex(scid), safehex(dcid)
613
613
614 comp = [hexifycompbookmarks(marks) for marks in comp]
614 comp = [hexifycompbookmarks(marks) for marks in comp]
615 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
615 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
616
616
617 for b, scid, dcid in advsrc:
617 for b, scid, dcid in advsrc:
618 if b in explicit:
618 if b in explicit:
619 explicit.remove(b)
619 explicit.remove(b)
620 if not ancestors or repo[scid].rev() in ancestors:
620 if not ancestors or repo[scid].rev() in ancestors:
621 pushop.outbookmarks.append((b, dcid, scid))
621 pushop.outbookmarks.append((b, dcid, scid))
622 # search added bookmark
622 # search added bookmark
623 for b, scid, dcid in addsrc:
623 for b, scid, dcid in addsrc:
624 if b in explicit:
624 if b in explicit:
625 explicit.remove(b)
625 explicit.remove(b)
626 pushop.outbookmarks.append((b, '', scid))
626 pushop.outbookmarks.append((b, '', scid))
627 # search for overwritten bookmark
627 # search for overwritten bookmark
628 for b, scid, dcid in list(advdst) + list(diverge) + list(differ):
628 for b, scid, dcid in list(advdst) + list(diverge) + list(differ):
629 if b in explicit:
629 if b in explicit:
630 explicit.remove(b)
630 explicit.remove(b)
631 pushop.outbookmarks.append((b, dcid, scid))
631 pushop.outbookmarks.append((b, dcid, scid))
632 # search for bookmark to delete
632 # search for bookmark to delete
633 for b, scid, dcid in adddst:
633 for b, scid, dcid in adddst:
634 if b in explicit:
634 if b in explicit:
635 explicit.remove(b)
635 explicit.remove(b)
636 # treat as "deleted locally"
636 # treat as "deleted locally"
637 pushop.outbookmarks.append((b, dcid, ''))
637 pushop.outbookmarks.append((b, dcid, ''))
638 # identical bookmarks shouldn't get reported
638 # identical bookmarks shouldn't get reported
639 for b, scid, dcid in same:
639 for b, scid, dcid in same:
640 if b in explicit:
640 if b in explicit:
641 explicit.remove(b)
641 explicit.remove(b)
642
642
643 if explicit:
643 if explicit:
644 explicit = sorted(explicit)
644 explicit = sorted(explicit)
645 # we should probably list all of them
645 # we should probably list all of them
646 ui.warn(_('bookmark %s does not exist on the local '
646 ui.warn(_('bookmark %s does not exist on the local '
647 'or remote repository!\n') % explicit[0])
647 'or remote repository!\n') % explicit[0])
648 pushop.bkresult = 2
648 pushop.bkresult = 2
649
649
650 pushop.outbookmarks.sort()
650 pushop.outbookmarks.sort()
651
651
652 def _pushcheckoutgoing(pushop):
652 def _pushcheckoutgoing(pushop):
653 outgoing = pushop.outgoing
653 outgoing = pushop.outgoing
654 unfi = pushop.repo.unfiltered()
654 unfi = pushop.repo.unfiltered()
655 if not outgoing.missing:
655 if not outgoing.missing:
656 # nothing to push
656 # nothing to push
657 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
657 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
658 return False
658 return False
659 # something to push
659 # something to push
660 if not pushop.force:
660 if not pushop.force:
661 # if repo.obsstore == False --> no obsolete
661 # if repo.obsstore == False --> no obsolete
662 # then, save the iteration
662 # then, save the iteration
663 if unfi.obsstore:
663 if unfi.obsstore:
664 # this message are here for 80 char limit reason
664 # this message are here for 80 char limit reason
665 mso = _("push includes obsolete changeset: %s!")
665 mso = _("push includes obsolete changeset: %s!")
666 mspd = _("push includes phase-divergent changeset: %s!")
666 mspd = _("push includes phase-divergent changeset: %s!")
667 mscd = _("push includes content-divergent changeset: %s!")
667 mscd = _("push includes content-divergent changeset: %s!")
668 mst = {"orphan": _("push includes orphan changeset: %s!"),
668 mst = {"orphan": _("push includes orphan changeset: %s!"),
669 "phase-divergent": mspd,
669 "phase-divergent": mspd,
670 "content-divergent": mscd}
670 "content-divergent": mscd}
671 # If we are to push if there is at least one
671 # If we are to push if there is at least one
672 # obsolete or unstable changeset in missing, at
672 # obsolete or unstable changeset in missing, at
673 # least one of the missinghead will be obsolete or
673 # least one of the missinghead will be obsolete or
674 # unstable. So checking heads only is ok
674 # unstable. So checking heads only is ok
675 for node in outgoing.missingheads:
675 for node in outgoing.missingheads:
676 ctx = unfi[node]
676 ctx = unfi[node]
677 if ctx.obsolete():
677 if ctx.obsolete():
678 raise error.Abort(mso % ctx)
678 raise error.Abort(mso % ctx)
679 elif ctx.isunstable():
679 elif ctx.isunstable():
680 # TODO print more than one instability in the abort
680 # TODO print more than one instability in the abort
681 # message
681 # message
682 raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
682 raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
683
683
684 discovery.checkheads(pushop)
684 discovery.checkheads(pushop)
685 return True
685 return True
686
686
687 # List of names of steps to perform for an outgoing bundle2, order matters.
687 # List of names of steps to perform for an outgoing bundle2, order matters.
688 b2partsgenorder = []
688 b2partsgenorder = []
689
689
690 # Mapping between step name and function
690 # Mapping between step name and function
691 #
691 #
692 # This exists to help extensions wrap steps if necessary
692 # This exists to help extensions wrap steps if necessary
693 b2partsgenmapping = {}
693 b2partsgenmapping = {}
694
694
695 def b2partsgenerator(stepname, idx=None):
695 def b2partsgenerator(stepname, idx=None):
696 """decorator for function generating bundle2 part
696 """decorator for function generating bundle2 part
697
697
698 The function is added to the step -> function mapping and appended to the
698 The function is added to the step -> function mapping and appended to the
699 list of steps. Beware that decorated functions will be added in order
699 list of steps. Beware that decorated functions will be added in order
700 (this may matter).
700 (this may matter).
701
701
702 You can only use this decorator for new steps, if you want to wrap a step
702 You can only use this decorator for new steps, if you want to wrap a step
703 from an extension, attack the b2partsgenmapping dictionary directly."""
703 from an extension, attack the b2partsgenmapping dictionary directly."""
704 def dec(func):
704 def dec(func):
705 assert stepname not in b2partsgenmapping
705 assert stepname not in b2partsgenmapping
706 b2partsgenmapping[stepname] = func
706 b2partsgenmapping[stepname] = func
707 if idx is None:
707 if idx is None:
708 b2partsgenorder.append(stepname)
708 b2partsgenorder.append(stepname)
709 else:
709 else:
710 b2partsgenorder.insert(idx, stepname)
710 b2partsgenorder.insert(idx, stepname)
711 return func
711 return func
712 return dec
712 return dec
713
713
714 def _pushb2ctxcheckheads(pushop, bundler):
714 def _pushb2ctxcheckheads(pushop, bundler):
715 """Generate race condition checking parts
715 """Generate race condition checking parts
716
716
717 Exists as an independent function to aid extensions
717 Exists as an independent function to aid extensions
718 """
718 """
719 # * 'force' do not check for push race,
719 # * 'force' do not check for push race,
720 # * if we don't push anything, there are nothing to check.
720 # * if we don't push anything, there are nothing to check.
721 if not pushop.force and pushop.outgoing.missingheads:
721 if not pushop.force and pushop.outgoing.missingheads:
722 allowunrelated = 'related' in bundler.capabilities.get('checkheads', ())
722 allowunrelated = 'related' in bundler.capabilities.get('checkheads', ())
723 emptyremote = pushop.pushbranchmap is None
723 emptyremote = pushop.pushbranchmap is None
724 if not allowunrelated or emptyremote:
724 if not allowunrelated or emptyremote:
725 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
725 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
726 else:
726 else:
727 affected = set()
727 affected = set()
728 for branch, heads in pushop.pushbranchmap.iteritems():
728 for branch, heads in pushop.pushbranchmap.iteritems():
729 remoteheads, newheads, unsyncedheads, discardedheads = heads
729 remoteheads, newheads, unsyncedheads, discardedheads = heads
730 if remoteheads is not None:
730 if remoteheads is not None:
731 remote = set(remoteheads)
731 remote = set(remoteheads)
732 affected |= set(discardedheads) & remote
732 affected |= set(discardedheads) & remote
733 affected |= remote - set(newheads)
733 affected |= remote - set(newheads)
734 if affected:
734 if affected:
735 data = iter(sorted(affected))
735 data = iter(sorted(affected))
736 bundler.newpart('check:updated-heads', data=data)
736 bundler.newpart('check:updated-heads', data=data)
737
737
738 def _pushing(pushop):
738 def _pushing(pushop):
739 """return True if we are pushing anything"""
739 """return True if we are pushing anything"""
740 return bool(pushop.outgoing.missing
740 return bool(pushop.outgoing.missing
741 or pushop.outdatedphases
741 or pushop.outdatedphases
742 or pushop.outobsmarkers
742 or pushop.outobsmarkers
743 or pushop.outbookmarks)
743 or pushop.outbookmarks)
744
744
745 @b2partsgenerator('check-phases')
745 @b2partsgenerator('check-phases')
746 def _pushb2checkphases(pushop, bundler):
746 def _pushb2checkphases(pushop, bundler):
747 """insert phase move checking"""
747 """insert phase move checking"""
748 if not _pushing(pushop) or pushop.force:
748 if not _pushing(pushop) or pushop.force:
749 return
749 return
750 b2caps = bundle2.bundle2caps(pushop.remote)
750 b2caps = bundle2.bundle2caps(pushop.remote)
751 hasphaseheads = 'heads' in b2caps.get('phases', ())
751 hasphaseheads = 'heads' in b2caps.get('phases', ())
752 if pushop.remotephases is not None and hasphaseheads:
752 if pushop.remotephases is not None and hasphaseheads:
753 # check that the remote phase has not changed
753 # check that the remote phase has not changed
754 checks = [[] for p in phases.allphases]
754 checks = [[] for p in phases.allphases]
755 checks[phases.public].extend(pushop.remotephases.publicheads)
755 checks[phases.public].extend(pushop.remotephases.publicheads)
756 checks[phases.draft].extend(pushop.remotephases.draftroots)
756 checks[phases.draft].extend(pushop.remotephases.draftroots)
757 if any(checks):
757 if any(checks):
758 for nodes in checks:
758 for nodes in checks:
759 nodes.sort()
759 nodes.sort()
760 checkdata = phases.binaryencode(checks)
760 checkdata = phases.binaryencode(checks)
761 bundler.newpart('check:phases', data=checkdata)
761 bundler.newpart('check:phases', data=checkdata)
762
762
763 @b2partsgenerator('changeset')
763 @b2partsgenerator('changeset')
764 def _pushb2ctx(pushop, bundler):
764 def _pushb2ctx(pushop, bundler):
765 """handle changegroup push through bundle2
765 """handle changegroup push through bundle2
766
766
767 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
767 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
768 """
768 """
769 if 'changesets' in pushop.stepsdone:
769 if 'changesets' in pushop.stepsdone:
770 return
770 return
771 pushop.stepsdone.add('changesets')
771 pushop.stepsdone.add('changesets')
772 # Send known heads to the server for race detection.
772 # Send known heads to the server for race detection.
773 if not _pushcheckoutgoing(pushop):
773 if not _pushcheckoutgoing(pushop):
774 return
774 return
775 pushop.repo.prepushoutgoinghooks(pushop)
775 pushop.repo.prepushoutgoinghooks(pushop)
776
776
777 _pushb2ctxcheckheads(pushop, bundler)
777 _pushb2ctxcheckheads(pushop, bundler)
778
778
779 b2caps = bundle2.bundle2caps(pushop.remote)
779 b2caps = bundle2.bundle2caps(pushop.remote)
780 version = '01'
780 version = '01'
781 cgversions = b2caps.get('changegroup')
781 cgversions = b2caps.get('changegroup')
782 if cgversions: # 3.1 and 3.2 ship with an empty value
782 if cgversions: # 3.1 and 3.2 ship with an empty value
783 cgversions = [v for v in cgversions
783 cgversions = [v for v in cgversions
784 if v in changegroup.supportedoutgoingversions(
784 if v in changegroup.supportedoutgoingversions(
785 pushop.repo)]
785 pushop.repo)]
786 if not cgversions:
786 if not cgversions:
787 raise ValueError(_('no common changegroup version'))
787 raise ValueError(_('no common changegroup version'))
788 version = max(cgversions)
788 version = max(cgversions)
789 cgstream = changegroup.makestream(pushop.repo, pushop.outgoing, version,
789 cgstream = changegroup.makestream(pushop.repo, pushop.outgoing, version,
790 'push')
790 'push')
791 cgpart = bundler.newpart('changegroup', data=cgstream)
791 cgpart = bundler.newpart('changegroup', data=cgstream)
792 if cgversions:
792 if cgversions:
793 cgpart.addparam('version', version)
793 cgpart.addparam('version', version)
794 if 'treemanifest' in pushop.repo.requirements:
794 if 'treemanifest' in pushop.repo.requirements:
795 cgpart.addparam('treemanifest', '1')
795 cgpart.addparam('treemanifest', '1')
796 def handlereply(op):
796 def handlereply(op):
797 """extract addchangegroup returns from server reply"""
797 """extract addchangegroup returns from server reply"""
798 cgreplies = op.records.getreplies(cgpart.id)
798 cgreplies = op.records.getreplies(cgpart.id)
799 assert len(cgreplies['changegroup']) == 1
799 assert len(cgreplies['changegroup']) == 1
800 pushop.cgresult = cgreplies['changegroup'][0]['return']
800 pushop.cgresult = cgreplies['changegroup'][0]['return']
801 return handlereply
801 return handlereply
802
802
803 @b2partsgenerator('phase')
803 @b2partsgenerator('phase')
804 def _pushb2phases(pushop, bundler):
804 def _pushb2phases(pushop, bundler):
805 """handle phase push through bundle2"""
805 """handle phase push through bundle2"""
806 if 'phases' in pushop.stepsdone:
806 if 'phases' in pushop.stepsdone:
807 return
807 return
808 b2caps = bundle2.bundle2caps(pushop.remote)
808 b2caps = bundle2.bundle2caps(pushop.remote)
809 if 'pushkey' in b2caps:
809 ui = pushop.repo.ui
810
811 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
812 haspushkey = 'pushkey' in b2caps
813 hasphaseheads = 'heads' in b2caps.get('phases', ())
814
815 if hasphaseheads and not legacyphase:
816 _pushb2phaseheads(pushop, bundler)
817 elif haspushkey:
810 _pushb2phasespushkey(pushop, bundler)
818 _pushb2phasespushkey(pushop, bundler)
811
819
820 def _pushb2phaseheads(pushop, bundler):
821 """push phase information through a bundle2 - binary part"""
822 pushop.stepsdone.add('phases')
823 if pushop.outdatedphases:
824 updates = [[] for p in phases.allphases]
825 updates[0].extend(h.node() for h in pushop.outdatedphases)
826 phasedata = phases.binaryencode(updates)
827 bundler.newpart('phase-heads', data=phasedata)
828
812 def _pushb2phasespushkey(pushop, bundler):
829 def _pushb2phasespushkey(pushop, bundler):
813 """push phase information through a bundle2 - pushkey part"""
830 """push phase information through a bundle2 - pushkey part"""
814 pushop.stepsdone.add('phases')
831 pushop.stepsdone.add('phases')
815 part2node = []
832 part2node = []
816
833
817 def handlefailure(pushop, exc):
834 def handlefailure(pushop, exc):
818 targetid = int(exc.partid)
835 targetid = int(exc.partid)
819 for partid, node in part2node:
836 for partid, node in part2node:
820 if partid == targetid:
837 if partid == targetid:
821 raise error.Abort(_('updating %s to public failed') % node)
838 raise error.Abort(_('updating %s to public failed') % node)
822
839
823 enc = pushkey.encode
840 enc = pushkey.encode
824 for newremotehead in pushop.outdatedphases:
841 for newremotehead in pushop.outdatedphases:
825 part = bundler.newpart('pushkey')
842 part = bundler.newpart('pushkey')
826 part.addparam('namespace', enc('phases'))
843 part.addparam('namespace', enc('phases'))
827 part.addparam('key', enc(newremotehead.hex()))
844 part.addparam('key', enc(newremotehead.hex()))
828 part.addparam('old', enc('%d' % phases.draft))
845 part.addparam('old', enc('%d' % phases.draft))
829 part.addparam('new', enc('%d' % phases.public))
846 part.addparam('new', enc('%d' % phases.public))
830 part2node.append((part.id, newremotehead))
847 part2node.append((part.id, newremotehead))
831 pushop.pkfailcb[part.id] = handlefailure
848 pushop.pkfailcb[part.id] = handlefailure
832
849
833 def handlereply(op):
850 def handlereply(op):
834 for partid, node in part2node:
851 for partid, node in part2node:
835 partrep = op.records.getreplies(partid)
852 partrep = op.records.getreplies(partid)
836 results = partrep['pushkey']
853 results = partrep['pushkey']
837 assert len(results) <= 1
854 assert len(results) <= 1
838 msg = None
855 msg = None
839 if not results:
856 if not results:
840 msg = _('server ignored update of %s to public!\n') % node
857 msg = _('server ignored update of %s to public!\n') % node
841 elif not int(results[0]['return']):
858 elif not int(results[0]['return']):
842 msg = _('updating %s to public failed!\n') % node
859 msg = _('updating %s to public failed!\n') % node
843 if msg is not None:
860 if msg is not None:
844 pushop.ui.warn(msg)
861 pushop.ui.warn(msg)
845 return handlereply
862 return handlereply
846
863
847 @b2partsgenerator('obsmarkers')
864 @b2partsgenerator('obsmarkers')
848 def _pushb2obsmarkers(pushop, bundler):
865 def _pushb2obsmarkers(pushop, bundler):
849 if 'obsmarkers' in pushop.stepsdone:
866 if 'obsmarkers' in pushop.stepsdone:
850 return
867 return
851 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
868 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
852 if obsolete.commonversion(remoteversions) is None:
869 if obsolete.commonversion(remoteversions) is None:
853 return
870 return
854 pushop.stepsdone.add('obsmarkers')
871 pushop.stepsdone.add('obsmarkers')
855 if pushop.outobsmarkers:
872 if pushop.outobsmarkers:
856 markers = sorted(pushop.outobsmarkers)
873 markers = sorted(pushop.outobsmarkers)
857 bundle2.buildobsmarkerspart(bundler, markers)
874 bundle2.buildobsmarkerspart(bundler, markers)
858
875
859 @b2partsgenerator('bookmarks')
876 @b2partsgenerator('bookmarks')
860 def _pushb2bookmarks(pushop, bundler):
877 def _pushb2bookmarks(pushop, bundler):
861 """handle bookmark push through bundle2"""
878 """handle bookmark push through bundle2"""
862 if 'bookmarks' in pushop.stepsdone:
879 if 'bookmarks' in pushop.stepsdone:
863 return
880 return
864 b2caps = bundle2.bundle2caps(pushop.remote)
881 b2caps = bundle2.bundle2caps(pushop.remote)
865 if 'pushkey' not in b2caps:
882 if 'pushkey' not in b2caps:
866 return
883 return
867 pushop.stepsdone.add('bookmarks')
884 pushop.stepsdone.add('bookmarks')
868 part2book = []
885 part2book = []
869 enc = pushkey.encode
886 enc = pushkey.encode
870
887
871 def handlefailure(pushop, exc):
888 def handlefailure(pushop, exc):
872 targetid = int(exc.partid)
889 targetid = int(exc.partid)
873 for partid, book, action in part2book:
890 for partid, book, action in part2book:
874 if partid == targetid:
891 if partid == targetid:
875 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
892 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
876 # we should not be called for part we did not generated
893 # we should not be called for part we did not generated
877 assert False
894 assert False
878
895
879 for book, old, new in pushop.outbookmarks:
896 for book, old, new in pushop.outbookmarks:
880 part = bundler.newpart('pushkey')
897 part = bundler.newpart('pushkey')
881 part.addparam('namespace', enc('bookmarks'))
898 part.addparam('namespace', enc('bookmarks'))
882 part.addparam('key', enc(book))
899 part.addparam('key', enc(book))
883 part.addparam('old', enc(old))
900 part.addparam('old', enc(old))
884 part.addparam('new', enc(new))
901 part.addparam('new', enc(new))
885 action = 'update'
902 action = 'update'
886 if not old:
903 if not old:
887 action = 'export'
904 action = 'export'
888 elif not new:
905 elif not new:
889 action = 'delete'
906 action = 'delete'
890 part2book.append((part.id, book, action))
907 part2book.append((part.id, book, action))
891 pushop.pkfailcb[part.id] = handlefailure
908 pushop.pkfailcb[part.id] = handlefailure
892
909
893 def handlereply(op):
910 def handlereply(op):
894 ui = pushop.ui
911 ui = pushop.ui
895 for partid, book, action in part2book:
912 for partid, book, action in part2book:
896 partrep = op.records.getreplies(partid)
913 partrep = op.records.getreplies(partid)
897 results = partrep['pushkey']
914 results = partrep['pushkey']
898 assert len(results) <= 1
915 assert len(results) <= 1
899 if not results:
916 if not results:
900 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
917 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
901 else:
918 else:
902 ret = int(results[0]['return'])
919 ret = int(results[0]['return'])
903 if ret:
920 if ret:
904 ui.status(bookmsgmap[action][0] % book)
921 ui.status(bookmsgmap[action][0] % book)
905 else:
922 else:
906 ui.warn(bookmsgmap[action][1] % book)
923 ui.warn(bookmsgmap[action][1] % book)
907 if pushop.bkresult is not None:
924 if pushop.bkresult is not None:
908 pushop.bkresult = 1
925 pushop.bkresult = 1
909 return handlereply
926 return handlereply
910
927
911 @b2partsgenerator('pushvars', idx=0)
928 @b2partsgenerator('pushvars', idx=0)
912 def _getbundlesendvars(pushop, bundler):
929 def _getbundlesendvars(pushop, bundler):
913 '''send shellvars via bundle2'''
930 '''send shellvars via bundle2'''
914 pushvars = pushop.pushvars
931 pushvars = pushop.pushvars
915 if pushvars:
932 if pushvars:
916 shellvars = {}
933 shellvars = {}
917 for raw in pushvars:
934 for raw in pushvars:
918 if '=' not in raw:
935 if '=' not in raw:
919 msg = ("unable to parse variable '%s', should follow "
936 msg = ("unable to parse variable '%s', should follow "
920 "'KEY=VALUE' or 'KEY=' format")
937 "'KEY=VALUE' or 'KEY=' format")
921 raise error.Abort(msg % raw)
938 raise error.Abort(msg % raw)
922 k, v = raw.split('=', 1)
939 k, v = raw.split('=', 1)
923 shellvars[k] = v
940 shellvars[k] = v
924
941
925 part = bundler.newpart('pushvars')
942 part = bundler.newpart('pushvars')
926
943
927 for key, value in shellvars.iteritems():
944 for key, value in shellvars.iteritems():
928 part.addparam(key, value, mandatory=False)
945 part.addparam(key, value, mandatory=False)
929
946
930 def _pushbundle2(pushop):
947 def _pushbundle2(pushop):
931 """push data to the remote using bundle2
948 """push data to the remote using bundle2
932
949
933 The only currently supported type of data is changegroup but this will
950 The only currently supported type of data is changegroup but this will
934 evolve in the future."""
951 evolve in the future."""
935 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
952 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
936 pushback = (pushop.trmanager
953 pushback = (pushop.trmanager
937 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
954 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
938
955
939 # create reply capability
956 # create reply capability
940 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
957 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
941 allowpushback=pushback))
958 allowpushback=pushback))
942 bundler.newpart('replycaps', data=capsblob)
959 bundler.newpart('replycaps', data=capsblob)
943 replyhandlers = []
960 replyhandlers = []
944 for partgenname in b2partsgenorder:
961 for partgenname in b2partsgenorder:
945 partgen = b2partsgenmapping[partgenname]
962 partgen = b2partsgenmapping[partgenname]
946 ret = partgen(pushop, bundler)
963 ret = partgen(pushop, bundler)
947 if callable(ret):
964 if callable(ret):
948 replyhandlers.append(ret)
965 replyhandlers.append(ret)
949 # do not push if nothing to push
966 # do not push if nothing to push
950 if bundler.nbparts <= 1:
967 if bundler.nbparts <= 1:
951 return
968 return
952 stream = util.chunkbuffer(bundler.getchunks())
969 stream = util.chunkbuffer(bundler.getchunks())
953 try:
970 try:
954 try:
971 try:
955 reply = pushop.remote.unbundle(
972 reply = pushop.remote.unbundle(
956 stream, ['force'], pushop.remote.url())
973 stream, ['force'], pushop.remote.url())
957 except error.BundleValueError as exc:
974 except error.BundleValueError as exc:
958 raise error.Abort(_('missing support for %s') % exc)
975 raise error.Abort(_('missing support for %s') % exc)
959 try:
976 try:
960 trgetter = None
977 trgetter = None
961 if pushback:
978 if pushback:
962 trgetter = pushop.trmanager.transaction
979 trgetter = pushop.trmanager.transaction
963 op = bundle2.processbundle(pushop.repo, reply, trgetter)
980 op = bundle2.processbundle(pushop.repo, reply, trgetter)
964 except error.BundleValueError as exc:
981 except error.BundleValueError as exc:
965 raise error.Abort(_('missing support for %s') % exc)
982 raise error.Abort(_('missing support for %s') % exc)
966 except bundle2.AbortFromPart as exc:
983 except bundle2.AbortFromPart as exc:
967 pushop.ui.status(_('remote: %s\n') % exc)
984 pushop.ui.status(_('remote: %s\n') % exc)
968 if exc.hint is not None:
985 if exc.hint is not None:
969 pushop.ui.status(_('remote: %s\n') % ('(%s)' % exc.hint))
986 pushop.ui.status(_('remote: %s\n') % ('(%s)' % exc.hint))
970 raise error.Abort(_('push failed on remote'))
987 raise error.Abort(_('push failed on remote'))
971 except error.PushkeyFailed as exc:
988 except error.PushkeyFailed as exc:
972 partid = int(exc.partid)
989 partid = int(exc.partid)
973 if partid not in pushop.pkfailcb:
990 if partid not in pushop.pkfailcb:
974 raise
991 raise
975 pushop.pkfailcb[partid](pushop, exc)
992 pushop.pkfailcb[partid](pushop, exc)
976 for rephand in replyhandlers:
993 for rephand in replyhandlers:
977 rephand(op)
994 rephand(op)
978
995
979 def _pushchangeset(pushop):
996 def _pushchangeset(pushop):
980 """Make the actual push of changeset bundle to remote repo"""
997 """Make the actual push of changeset bundle to remote repo"""
981 if 'changesets' in pushop.stepsdone:
998 if 'changesets' in pushop.stepsdone:
982 return
999 return
983 pushop.stepsdone.add('changesets')
1000 pushop.stepsdone.add('changesets')
984 if not _pushcheckoutgoing(pushop):
1001 if not _pushcheckoutgoing(pushop):
985 return
1002 return
986
1003
987 # Should have verified this in push().
1004 # Should have verified this in push().
988 assert pushop.remote.capable('unbundle')
1005 assert pushop.remote.capable('unbundle')
989
1006
990 pushop.repo.prepushoutgoinghooks(pushop)
1007 pushop.repo.prepushoutgoinghooks(pushop)
991 outgoing = pushop.outgoing
1008 outgoing = pushop.outgoing
992 # TODO: get bundlecaps from remote
1009 # TODO: get bundlecaps from remote
993 bundlecaps = None
1010 bundlecaps = None
994 # create a changegroup from local
1011 # create a changegroup from local
995 if pushop.revs is None and not (outgoing.excluded
1012 if pushop.revs is None and not (outgoing.excluded
996 or pushop.repo.changelog.filteredrevs):
1013 or pushop.repo.changelog.filteredrevs):
997 # push everything,
1014 # push everything,
998 # use the fast path, no race possible on push
1015 # use the fast path, no race possible on push
999 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01', 'push',
1016 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01', 'push',
1000 fastpath=True, bundlecaps=bundlecaps)
1017 fastpath=True, bundlecaps=bundlecaps)
1001 else:
1018 else:
1002 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01',
1019 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01',
1003 'push', bundlecaps=bundlecaps)
1020 'push', bundlecaps=bundlecaps)
1004
1021
1005 # apply changegroup to remote
1022 # apply changegroup to remote
1006 # local repo finds heads on server, finds out what
1023 # local repo finds heads on server, finds out what
1007 # revs it must push. once revs transferred, if server
1024 # revs it must push. once revs transferred, if server
1008 # finds it has different heads (someone else won
1025 # finds it has different heads (someone else won
1009 # commit/push race), server aborts.
1026 # commit/push race), server aborts.
1010 if pushop.force:
1027 if pushop.force:
1011 remoteheads = ['force']
1028 remoteheads = ['force']
1012 else:
1029 else:
1013 remoteheads = pushop.remoteheads
1030 remoteheads = pushop.remoteheads
1014 # ssh: return remote's addchangegroup()
1031 # ssh: return remote's addchangegroup()
1015 # http: return remote's addchangegroup() or 0 for error
1032 # http: return remote's addchangegroup() or 0 for error
1016 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
1033 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
1017 pushop.repo.url())
1034 pushop.repo.url())
1018
1035
1019 def _pushsyncphase(pushop):
1036 def _pushsyncphase(pushop):
1020 """synchronise phase information locally and remotely"""
1037 """synchronise phase information locally and remotely"""
1021 cheads = pushop.commonheads
1038 cheads = pushop.commonheads
1022 # even when we don't push, exchanging phase data is useful
1039 # even when we don't push, exchanging phase data is useful
1023 remotephases = pushop.remote.listkeys('phases')
1040 remotephases = pushop.remote.listkeys('phases')
1024 if (pushop.ui.configbool('ui', '_usedassubrepo')
1041 if (pushop.ui.configbool('ui', '_usedassubrepo')
1025 and remotephases # server supports phases
1042 and remotephases # server supports phases
1026 and pushop.cgresult is None # nothing was pushed
1043 and pushop.cgresult is None # nothing was pushed
1027 and remotephases.get('publishing', False)):
1044 and remotephases.get('publishing', False)):
1028 # When:
1045 # When:
1029 # - this is a subrepo push
1046 # - this is a subrepo push
1030 # - and remote support phase
1047 # - and remote support phase
1031 # - and no changeset was pushed
1048 # - and no changeset was pushed
1032 # - and remote is publishing
1049 # - and remote is publishing
1033 # We may be in issue 3871 case!
1050 # We may be in issue 3871 case!
1034 # We drop the possible phase synchronisation done by
1051 # We drop the possible phase synchronisation done by
1035 # courtesy to publish changesets possibly locally draft
1052 # courtesy to publish changesets possibly locally draft
1036 # on the remote.
1053 # on the remote.
1037 remotephases = {'publishing': 'True'}
1054 remotephases = {'publishing': 'True'}
1038 if not remotephases: # old server or public only reply from non-publishing
1055 if not remotephases: # old server or public only reply from non-publishing
1039 _localphasemove(pushop, cheads)
1056 _localphasemove(pushop, cheads)
1040 # don't push any phase data as there is nothing to push
1057 # don't push any phase data as there is nothing to push
1041 else:
1058 else:
1042 ana = phases.analyzeremotephases(pushop.repo, cheads,
1059 ana = phases.analyzeremotephases(pushop.repo, cheads,
1043 remotephases)
1060 remotephases)
1044 pheads, droots = ana
1061 pheads, droots = ana
1045 ### Apply remote phase on local
1062 ### Apply remote phase on local
1046 if remotephases.get('publishing', False):
1063 if remotephases.get('publishing', False):
1047 _localphasemove(pushop, cheads)
1064 _localphasemove(pushop, cheads)
1048 else: # publish = False
1065 else: # publish = False
1049 _localphasemove(pushop, pheads)
1066 _localphasemove(pushop, pheads)
1050 _localphasemove(pushop, cheads, phases.draft)
1067 _localphasemove(pushop, cheads, phases.draft)
1051 ### Apply local phase on remote
1068 ### Apply local phase on remote
1052
1069
1053 if pushop.cgresult:
1070 if pushop.cgresult:
1054 if 'phases' in pushop.stepsdone:
1071 if 'phases' in pushop.stepsdone:
1055 # phases already pushed though bundle2
1072 # phases already pushed though bundle2
1056 return
1073 return
1057 outdated = pushop.outdatedphases
1074 outdated = pushop.outdatedphases
1058 else:
1075 else:
1059 outdated = pushop.fallbackoutdatedphases
1076 outdated = pushop.fallbackoutdatedphases
1060
1077
1061 pushop.stepsdone.add('phases')
1078 pushop.stepsdone.add('phases')
1062
1079
1063 # filter heads already turned public by the push
1080 # filter heads already turned public by the push
1064 outdated = [c for c in outdated if c.node() not in pheads]
1081 outdated = [c for c in outdated if c.node() not in pheads]
1065 # fallback to independent pushkey command
1082 # fallback to independent pushkey command
1066 for newremotehead in outdated:
1083 for newremotehead in outdated:
1067 r = pushop.remote.pushkey('phases',
1084 r = pushop.remote.pushkey('phases',
1068 newremotehead.hex(),
1085 newremotehead.hex(),
1069 str(phases.draft),
1086 str(phases.draft),
1070 str(phases.public))
1087 str(phases.public))
1071 if not r:
1088 if not r:
1072 pushop.ui.warn(_('updating %s to public failed!\n')
1089 pushop.ui.warn(_('updating %s to public failed!\n')
1073 % newremotehead)
1090 % newremotehead)
1074
1091
1075 def _localphasemove(pushop, nodes, phase=phases.public):
1092 def _localphasemove(pushop, nodes, phase=phases.public):
1076 """move <nodes> to <phase> in the local source repo"""
1093 """move <nodes> to <phase> in the local source repo"""
1077 if pushop.trmanager:
1094 if pushop.trmanager:
1078 phases.advanceboundary(pushop.repo,
1095 phases.advanceboundary(pushop.repo,
1079 pushop.trmanager.transaction(),
1096 pushop.trmanager.transaction(),
1080 phase,
1097 phase,
1081 nodes)
1098 nodes)
1082 else:
1099 else:
1083 # repo is not locked, do not change any phases!
1100 # repo is not locked, do not change any phases!
1084 # Informs the user that phases should have been moved when
1101 # Informs the user that phases should have been moved when
1085 # applicable.
1102 # applicable.
1086 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
1103 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
1087 phasestr = phases.phasenames[phase]
1104 phasestr = phases.phasenames[phase]
1088 if actualmoves:
1105 if actualmoves:
1089 pushop.ui.status(_('cannot lock source repo, skipping '
1106 pushop.ui.status(_('cannot lock source repo, skipping '
1090 'local %s phase update\n') % phasestr)
1107 'local %s phase update\n') % phasestr)
1091
1108
1092 def _pushobsolete(pushop):
1109 def _pushobsolete(pushop):
1093 """utility function to push obsolete markers to a remote"""
1110 """utility function to push obsolete markers to a remote"""
1094 if 'obsmarkers' in pushop.stepsdone:
1111 if 'obsmarkers' in pushop.stepsdone:
1095 return
1112 return
1096 repo = pushop.repo
1113 repo = pushop.repo
1097 remote = pushop.remote
1114 remote = pushop.remote
1098 pushop.stepsdone.add('obsmarkers')
1115 pushop.stepsdone.add('obsmarkers')
1099 if pushop.outobsmarkers:
1116 if pushop.outobsmarkers:
1100 pushop.ui.debug('try to push obsolete markers to remote\n')
1117 pushop.ui.debug('try to push obsolete markers to remote\n')
1101 rslts = []
1118 rslts = []
1102 remotedata = obsolete._pushkeyescape(sorted(pushop.outobsmarkers))
1119 remotedata = obsolete._pushkeyescape(sorted(pushop.outobsmarkers))
1103 for key in sorted(remotedata, reverse=True):
1120 for key in sorted(remotedata, reverse=True):
1104 # reverse sort to ensure we end with dump0
1121 # reverse sort to ensure we end with dump0
1105 data = remotedata[key]
1122 data = remotedata[key]
1106 rslts.append(remote.pushkey('obsolete', key, '', data))
1123 rslts.append(remote.pushkey('obsolete', key, '', data))
1107 if [r for r in rslts if not r]:
1124 if [r for r in rslts if not r]:
1108 msg = _('failed to push some obsolete markers!\n')
1125 msg = _('failed to push some obsolete markers!\n')
1109 repo.ui.warn(msg)
1126 repo.ui.warn(msg)
1110
1127
1111 def _pushbookmark(pushop):
1128 def _pushbookmark(pushop):
1112 """Update bookmark position on remote"""
1129 """Update bookmark position on remote"""
1113 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
1130 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
1114 return
1131 return
1115 pushop.stepsdone.add('bookmarks')
1132 pushop.stepsdone.add('bookmarks')
1116 ui = pushop.ui
1133 ui = pushop.ui
1117 remote = pushop.remote
1134 remote = pushop.remote
1118
1135
1119 for b, old, new in pushop.outbookmarks:
1136 for b, old, new in pushop.outbookmarks:
1120 action = 'update'
1137 action = 'update'
1121 if not old:
1138 if not old:
1122 action = 'export'
1139 action = 'export'
1123 elif not new:
1140 elif not new:
1124 action = 'delete'
1141 action = 'delete'
1125 if remote.pushkey('bookmarks', b, old, new):
1142 if remote.pushkey('bookmarks', b, old, new):
1126 ui.status(bookmsgmap[action][0] % b)
1143 ui.status(bookmsgmap[action][0] % b)
1127 else:
1144 else:
1128 ui.warn(bookmsgmap[action][1] % b)
1145 ui.warn(bookmsgmap[action][1] % b)
1129 # discovery can have set the value form invalid entry
1146 # discovery can have set the value form invalid entry
1130 if pushop.bkresult is not None:
1147 if pushop.bkresult is not None:
1131 pushop.bkresult = 1
1148 pushop.bkresult = 1
1132
1149
1133 class pulloperation(object):
1150 class pulloperation(object):
1134 """A object that represent a single pull operation
1151 """A object that represent a single pull operation
1135
1152
1136 It purpose is to carry pull related state and very common operation.
1153 It purpose is to carry pull related state and very common operation.
1137
1154
1138 A new should be created at the beginning of each pull and discarded
1155 A new should be created at the beginning of each pull and discarded
1139 afterward.
1156 afterward.
1140 """
1157 """
1141
1158
1142 def __init__(self, repo, remote, heads=None, force=False, bookmarks=(),
1159 def __init__(self, repo, remote, heads=None, force=False, bookmarks=(),
1143 remotebookmarks=None, streamclonerequested=None):
1160 remotebookmarks=None, streamclonerequested=None):
1144 # repo we pull into
1161 # repo we pull into
1145 self.repo = repo
1162 self.repo = repo
1146 # repo we pull from
1163 # repo we pull from
1147 self.remote = remote
1164 self.remote = remote
1148 # revision we try to pull (None is "all")
1165 # revision we try to pull (None is "all")
1149 self.heads = heads
1166 self.heads = heads
1150 # bookmark pulled explicitly
1167 # bookmark pulled explicitly
1151 self.explicitbookmarks = [repo._bookmarks.expandname(bookmark)
1168 self.explicitbookmarks = [repo._bookmarks.expandname(bookmark)
1152 for bookmark in bookmarks]
1169 for bookmark in bookmarks]
1153 # do we force pull?
1170 # do we force pull?
1154 self.force = force
1171 self.force = force
1155 # whether a streaming clone was requested
1172 # whether a streaming clone was requested
1156 self.streamclonerequested = streamclonerequested
1173 self.streamclonerequested = streamclonerequested
1157 # transaction manager
1174 # transaction manager
1158 self.trmanager = None
1175 self.trmanager = None
1159 # set of common changeset between local and remote before pull
1176 # set of common changeset between local and remote before pull
1160 self.common = None
1177 self.common = None
1161 # set of pulled head
1178 # set of pulled head
1162 self.rheads = None
1179 self.rheads = None
1163 # list of missing changeset to fetch remotely
1180 # list of missing changeset to fetch remotely
1164 self.fetch = None
1181 self.fetch = None
1165 # remote bookmarks data
1182 # remote bookmarks data
1166 self.remotebookmarks = remotebookmarks
1183 self.remotebookmarks = remotebookmarks
1167 # result of changegroup pulling (used as return code by pull)
1184 # result of changegroup pulling (used as return code by pull)
1168 self.cgresult = None
1185 self.cgresult = None
1169 # list of step already done
1186 # list of step already done
1170 self.stepsdone = set()
1187 self.stepsdone = set()
1171 # Whether we attempted a clone from pre-generated bundles.
1188 # Whether we attempted a clone from pre-generated bundles.
1172 self.clonebundleattempted = False
1189 self.clonebundleattempted = False
1173
1190
1174 @util.propertycache
1191 @util.propertycache
1175 def pulledsubset(self):
1192 def pulledsubset(self):
1176 """heads of the set of changeset target by the pull"""
1193 """heads of the set of changeset target by the pull"""
1177 # compute target subset
1194 # compute target subset
1178 if self.heads is None:
1195 if self.heads is None:
1179 # We pulled every thing possible
1196 # We pulled every thing possible
1180 # sync on everything common
1197 # sync on everything common
1181 c = set(self.common)
1198 c = set(self.common)
1182 ret = list(self.common)
1199 ret = list(self.common)
1183 for n in self.rheads:
1200 for n in self.rheads:
1184 if n not in c:
1201 if n not in c:
1185 ret.append(n)
1202 ret.append(n)
1186 return ret
1203 return ret
1187 else:
1204 else:
1188 # We pulled a specific subset
1205 # We pulled a specific subset
1189 # sync on this subset
1206 # sync on this subset
1190 return self.heads
1207 return self.heads
1191
1208
1192 @util.propertycache
1209 @util.propertycache
1193 def canusebundle2(self):
1210 def canusebundle2(self):
1194 return not _forcebundle1(self)
1211 return not _forcebundle1(self)
1195
1212
1196 @util.propertycache
1213 @util.propertycache
1197 def remotebundle2caps(self):
1214 def remotebundle2caps(self):
1198 return bundle2.bundle2caps(self.remote)
1215 return bundle2.bundle2caps(self.remote)
1199
1216
1200 def gettransaction(self):
1217 def gettransaction(self):
1201 # deprecated; talk to trmanager directly
1218 # deprecated; talk to trmanager directly
1202 return self.trmanager.transaction()
1219 return self.trmanager.transaction()
1203
1220
1204 class transactionmanager(util.transactional):
1221 class transactionmanager(util.transactional):
1205 """An object to manage the life cycle of a transaction
1222 """An object to manage the life cycle of a transaction
1206
1223
1207 It creates the transaction on demand and calls the appropriate hooks when
1224 It creates the transaction on demand and calls the appropriate hooks when
1208 closing the transaction."""
1225 closing the transaction."""
1209 def __init__(self, repo, source, url):
1226 def __init__(self, repo, source, url):
1210 self.repo = repo
1227 self.repo = repo
1211 self.source = source
1228 self.source = source
1212 self.url = url
1229 self.url = url
1213 self._tr = None
1230 self._tr = None
1214
1231
1215 def transaction(self):
1232 def transaction(self):
1216 """Return an open transaction object, constructing if necessary"""
1233 """Return an open transaction object, constructing if necessary"""
1217 if not self._tr:
1234 if not self._tr:
1218 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
1235 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
1219 self._tr = self.repo.transaction(trname)
1236 self._tr = self.repo.transaction(trname)
1220 self._tr.hookargs['source'] = self.source
1237 self._tr.hookargs['source'] = self.source
1221 self._tr.hookargs['url'] = self.url
1238 self._tr.hookargs['url'] = self.url
1222 return self._tr
1239 return self._tr
1223
1240
1224 def close(self):
1241 def close(self):
1225 """close transaction if created"""
1242 """close transaction if created"""
1226 if self._tr is not None:
1243 if self._tr is not None:
1227 self._tr.close()
1244 self._tr.close()
1228
1245
1229 def release(self):
1246 def release(self):
1230 """release transaction if created"""
1247 """release transaction if created"""
1231 if self._tr is not None:
1248 if self._tr is not None:
1232 self._tr.release()
1249 self._tr.release()
1233
1250
1234 def pull(repo, remote, heads=None, force=False, bookmarks=(), opargs=None,
1251 def pull(repo, remote, heads=None, force=False, bookmarks=(), opargs=None,
1235 streamclonerequested=None):
1252 streamclonerequested=None):
1236 """Fetch repository data from a remote.
1253 """Fetch repository data from a remote.
1237
1254
1238 This is the main function used to retrieve data from a remote repository.
1255 This is the main function used to retrieve data from a remote repository.
1239
1256
1240 ``repo`` is the local repository to clone into.
1257 ``repo`` is the local repository to clone into.
1241 ``remote`` is a peer instance.
1258 ``remote`` is a peer instance.
1242 ``heads`` is an iterable of revisions we want to pull. ``None`` (the
1259 ``heads`` is an iterable of revisions we want to pull. ``None`` (the
1243 default) means to pull everything from the remote.
1260 default) means to pull everything from the remote.
1244 ``bookmarks`` is an iterable of bookmarks requesting to be pulled. By
1261 ``bookmarks`` is an iterable of bookmarks requesting to be pulled. By
1245 default, all remote bookmarks are pulled.
1262 default, all remote bookmarks are pulled.
1246 ``opargs`` are additional keyword arguments to pass to ``pulloperation``
1263 ``opargs`` are additional keyword arguments to pass to ``pulloperation``
1247 initialization.
1264 initialization.
1248 ``streamclonerequested`` is a boolean indicating whether a "streaming
1265 ``streamclonerequested`` is a boolean indicating whether a "streaming
1249 clone" is requested. A "streaming clone" is essentially a raw file copy
1266 clone" is requested. A "streaming clone" is essentially a raw file copy
1250 of revlogs from the server. This only works when the local repository is
1267 of revlogs from the server. This only works when the local repository is
1251 empty. The default value of ``None`` means to respect the server
1268 empty. The default value of ``None`` means to respect the server
1252 configuration for preferring stream clones.
1269 configuration for preferring stream clones.
1253
1270
1254 Returns the ``pulloperation`` created for this pull.
1271 Returns the ``pulloperation`` created for this pull.
1255 """
1272 """
1256 if opargs is None:
1273 if opargs is None:
1257 opargs = {}
1274 opargs = {}
1258 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks,
1275 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks,
1259 streamclonerequested=streamclonerequested, **opargs)
1276 streamclonerequested=streamclonerequested, **opargs)
1260
1277
1261 peerlocal = pullop.remote.local()
1278 peerlocal = pullop.remote.local()
1262 if peerlocal:
1279 if peerlocal:
1263 missing = set(peerlocal.requirements) - pullop.repo.supported
1280 missing = set(peerlocal.requirements) - pullop.repo.supported
1264 if missing:
1281 if missing:
1265 msg = _("required features are not"
1282 msg = _("required features are not"
1266 " supported in the destination:"
1283 " supported in the destination:"
1267 " %s") % (', '.join(sorted(missing)))
1284 " %s") % (', '.join(sorted(missing)))
1268 raise error.Abort(msg)
1285 raise error.Abort(msg)
1269
1286
1270 wlock = lock = None
1287 wlock = lock = None
1271 try:
1288 try:
1272 wlock = pullop.repo.wlock()
1289 wlock = pullop.repo.wlock()
1273 lock = pullop.repo.lock()
1290 lock = pullop.repo.lock()
1274 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
1291 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
1275 # This should ideally be in _pullbundle2(). However, it needs to run
1292 # This should ideally be in _pullbundle2(). However, it needs to run
1276 # before discovery to avoid extra work.
1293 # before discovery to avoid extra work.
1277 _maybeapplyclonebundle(pullop)
1294 _maybeapplyclonebundle(pullop)
1278 streamclone.maybeperformlegacystreamclone(pullop)
1295 streamclone.maybeperformlegacystreamclone(pullop)
1279 _pulldiscovery(pullop)
1296 _pulldiscovery(pullop)
1280 if pullop.canusebundle2:
1297 if pullop.canusebundle2:
1281 _pullbundle2(pullop)
1298 _pullbundle2(pullop)
1282 _pullchangeset(pullop)
1299 _pullchangeset(pullop)
1283 _pullphase(pullop)
1300 _pullphase(pullop)
1284 _pullbookmarks(pullop)
1301 _pullbookmarks(pullop)
1285 _pullobsolete(pullop)
1302 _pullobsolete(pullop)
1286 pullop.trmanager.close()
1303 pullop.trmanager.close()
1287 finally:
1304 finally:
1288 lockmod.release(pullop.trmanager, lock, wlock)
1305 lockmod.release(pullop.trmanager, lock, wlock)
1289
1306
1290 return pullop
1307 return pullop
1291
1308
1292 # list of steps to perform discovery before pull
1309 # list of steps to perform discovery before pull
1293 pulldiscoveryorder = []
1310 pulldiscoveryorder = []
1294
1311
1295 # Mapping between step name and function
1312 # Mapping between step name and function
1296 #
1313 #
1297 # This exists to help extensions wrap steps if necessary
1314 # This exists to help extensions wrap steps if necessary
1298 pulldiscoverymapping = {}
1315 pulldiscoverymapping = {}
1299
1316
1300 def pulldiscovery(stepname):
1317 def pulldiscovery(stepname):
1301 """decorator for function performing discovery before pull
1318 """decorator for function performing discovery before pull
1302
1319
1303 The function is added to the step -> function mapping and appended to the
1320 The function is added to the step -> function mapping and appended to the
1304 list of steps. Beware that decorated function will be added in order (this
1321 list of steps. Beware that decorated function will be added in order (this
1305 may matter).
1322 may matter).
1306
1323
1307 You can only use this decorator for a new step, if you want to wrap a step
1324 You can only use this decorator for a new step, if you want to wrap a step
1308 from an extension, change the pulldiscovery dictionary directly."""
1325 from an extension, change the pulldiscovery dictionary directly."""
1309 def dec(func):
1326 def dec(func):
1310 assert stepname not in pulldiscoverymapping
1327 assert stepname not in pulldiscoverymapping
1311 pulldiscoverymapping[stepname] = func
1328 pulldiscoverymapping[stepname] = func
1312 pulldiscoveryorder.append(stepname)
1329 pulldiscoveryorder.append(stepname)
1313 return func
1330 return func
1314 return dec
1331 return dec
1315
1332
1316 def _pulldiscovery(pullop):
1333 def _pulldiscovery(pullop):
1317 """Run all discovery steps"""
1334 """Run all discovery steps"""
1318 for stepname in pulldiscoveryorder:
1335 for stepname in pulldiscoveryorder:
1319 step = pulldiscoverymapping[stepname]
1336 step = pulldiscoverymapping[stepname]
1320 step(pullop)
1337 step(pullop)
1321
1338
1322 @pulldiscovery('b1:bookmarks')
1339 @pulldiscovery('b1:bookmarks')
1323 def _pullbookmarkbundle1(pullop):
1340 def _pullbookmarkbundle1(pullop):
1324 """fetch bookmark data in bundle1 case
1341 """fetch bookmark data in bundle1 case
1325
1342
1326 If not using bundle2, we have to fetch bookmarks before changeset
1343 If not using bundle2, we have to fetch bookmarks before changeset
1327 discovery to reduce the chance and impact of race conditions."""
1344 discovery to reduce the chance and impact of race conditions."""
1328 if pullop.remotebookmarks is not None:
1345 if pullop.remotebookmarks is not None:
1329 return
1346 return
1330 if pullop.canusebundle2 and 'listkeys' in pullop.remotebundle2caps:
1347 if pullop.canusebundle2 and 'listkeys' in pullop.remotebundle2caps:
1331 # all known bundle2 servers now support listkeys, but lets be nice with
1348 # all known bundle2 servers now support listkeys, but lets be nice with
1332 # new implementation.
1349 # new implementation.
1333 return
1350 return
1334 pullop.remotebookmarks = pullop.remote.listkeys('bookmarks')
1351 pullop.remotebookmarks = pullop.remote.listkeys('bookmarks')
1335
1352
1336
1353
1337 @pulldiscovery('changegroup')
1354 @pulldiscovery('changegroup')
1338 def _pulldiscoverychangegroup(pullop):
1355 def _pulldiscoverychangegroup(pullop):
1339 """discovery phase for the pull
1356 """discovery phase for the pull
1340
1357
1341 Current handle changeset discovery only, will change handle all discovery
1358 Current handle changeset discovery only, will change handle all discovery
1342 at some point."""
1359 at some point."""
1343 tmp = discovery.findcommonincoming(pullop.repo,
1360 tmp = discovery.findcommonincoming(pullop.repo,
1344 pullop.remote,
1361 pullop.remote,
1345 heads=pullop.heads,
1362 heads=pullop.heads,
1346 force=pullop.force)
1363 force=pullop.force)
1347 common, fetch, rheads = tmp
1364 common, fetch, rheads = tmp
1348 nm = pullop.repo.unfiltered().changelog.nodemap
1365 nm = pullop.repo.unfiltered().changelog.nodemap
1349 if fetch and rheads:
1366 if fetch and rheads:
1350 # If a remote heads is filtered locally, put in back in common.
1367 # If a remote heads is filtered locally, put in back in common.
1351 #
1368 #
1352 # This is a hackish solution to catch most of "common but locally
1369 # This is a hackish solution to catch most of "common but locally
1353 # hidden situation". We do not performs discovery on unfiltered
1370 # hidden situation". We do not performs discovery on unfiltered
1354 # repository because it end up doing a pathological amount of round
1371 # repository because it end up doing a pathological amount of round
1355 # trip for w huge amount of changeset we do not care about.
1372 # trip for w huge amount of changeset we do not care about.
1356 #
1373 #
1357 # If a set of such "common but filtered" changeset exist on the server
1374 # If a set of such "common but filtered" changeset exist on the server
1358 # but are not including a remote heads, we'll not be able to detect it,
1375 # but are not including a remote heads, we'll not be able to detect it,
1359 scommon = set(common)
1376 scommon = set(common)
1360 for n in rheads:
1377 for n in rheads:
1361 if n in nm:
1378 if n in nm:
1362 if n not in scommon:
1379 if n not in scommon:
1363 common.append(n)
1380 common.append(n)
1364 if set(rheads).issubset(set(common)):
1381 if set(rheads).issubset(set(common)):
1365 fetch = []
1382 fetch = []
1366 pullop.common = common
1383 pullop.common = common
1367 pullop.fetch = fetch
1384 pullop.fetch = fetch
1368 pullop.rheads = rheads
1385 pullop.rheads = rheads
1369
1386
1370 def _pullbundle2(pullop):
1387 def _pullbundle2(pullop):
1371 """pull data using bundle2
1388 """pull data using bundle2
1372
1389
1373 For now, the only supported data are changegroup."""
1390 For now, the only supported data are changegroup."""
1374 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
1391 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
1375
1392
1376 # At the moment we don't do stream clones over bundle2. If that is
1393 # At the moment we don't do stream clones over bundle2. If that is
1377 # implemented then here's where the check for that will go.
1394 # implemented then here's where the check for that will go.
1378 streaming = False
1395 streaming = False
1379
1396
1380 # pulling changegroup
1397 # pulling changegroup
1381 pullop.stepsdone.add('changegroup')
1398 pullop.stepsdone.add('changegroup')
1382
1399
1383 kwargs['common'] = pullop.common
1400 kwargs['common'] = pullop.common
1384 kwargs['heads'] = pullop.heads or pullop.rheads
1401 kwargs['heads'] = pullop.heads or pullop.rheads
1385 kwargs['cg'] = pullop.fetch
1402 kwargs['cg'] = pullop.fetch
1386
1403
1387 ui = pullop.repo.ui
1404 ui = pullop.repo.ui
1388 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
1405 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
1389 hasbinaryphase = 'heads' in pullop.remotebundle2caps.get('phases', ())
1406 hasbinaryphase = 'heads' in pullop.remotebundle2caps.get('phases', ())
1390 if (not legacyphase and hasbinaryphase):
1407 if (not legacyphase and hasbinaryphase):
1391 kwargs['phases'] = True
1408 kwargs['phases'] = True
1392 pullop.stepsdone.add('phases')
1409 pullop.stepsdone.add('phases')
1393
1410
1394 if 'listkeys' in pullop.remotebundle2caps:
1411 if 'listkeys' in pullop.remotebundle2caps:
1395 if 'phases' not in pullop.stepsdone:
1412 if 'phases' not in pullop.stepsdone:
1396 kwargs['listkeys'] = ['phases']
1413 kwargs['listkeys'] = ['phases']
1397 if pullop.remotebookmarks is None:
1414 if pullop.remotebookmarks is None:
1398 # make sure to always includes bookmark data when migrating
1415 # make sure to always includes bookmark data when migrating
1399 # `hg incoming --bundle` to using this function.
1416 # `hg incoming --bundle` to using this function.
1400 kwargs.setdefault('listkeys', []).append('bookmarks')
1417 kwargs.setdefault('listkeys', []).append('bookmarks')
1401
1418
1402 # If this is a full pull / clone and the server supports the clone bundles
1419 # If this is a full pull / clone and the server supports the clone bundles
1403 # feature, tell the server whether we attempted a clone bundle. The
1420 # feature, tell the server whether we attempted a clone bundle. The
1404 # presence of this flag indicates the client supports clone bundles. This
1421 # presence of this flag indicates the client supports clone bundles. This
1405 # will enable the server to treat clients that support clone bundles
1422 # will enable the server to treat clients that support clone bundles
1406 # differently from those that don't.
1423 # differently from those that don't.
1407 if (pullop.remote.capable('clonebundles')
1424 if (pullop.remote.capable('clonebundles')
1408 and pullop.heads is None and list(pullop.common) == [nullid]):
1425 and pullop.heads is None and list(pullop.common) == [nullid]):
1409 kwargs['cbattempted'] = pullop.clonebundleattempted
1426 kwargs['cbattempted'] = pullop.clonebundleattempted
1410
1427
1411 if streaming:
1428 if streaming:
1412 pullop.repo.ui.status(_('streaming all changes\n'))
1429 pullop.repo.ui.status(_('streaming all changes\n'))
1413 elif not pullop.fetch:
1430 elif not pullop.fetch:
1414 pullop.repo.ui.status(_("no changes found\n"))
1431 pullop.repo.ui.status(_("no changes found\n"))
1415 pullop.cgresult = 0
1432 pullop.cgresult = 0
1416 else:
1433 else:
1417 if pullop.heads is None and list(pullop.common) == [nullid]:
1434 if pullop.heads is None and list(pullop.common) == [nullid]:
1418 pullop.repo.ui.status(_("requesting all changes\n"))
1435 pullop.repo.ui.status(_("requesting all changes\n"))
1419 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1436 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1420 remoteversions = bundle2.obsmarkersversion(pullop.remotebundle2caps)
1437 remoteversions = bundle2.obsmarkersversion(pullop.remotebundle2caps)
1421 if obsolete.commonversion(remoteversions) is not None:
1438 if obsolete.commonversion(remoteversions) is not None:
1422 kwargs['obsmarkers'] = True
1439 kwargs['obsmarkers'] = True
1423 pullop.stepsdone.add('obsmarkers')
1440 pullop.stepsdone.add('obsmarkers')
1424 _pullbundle2extraprepare(pullop, kwargs)
1441 _pullbundle2extraprepare(pullop, kwargs)
1425 bundle = pullop.remote.getbundle('pull', **pycompat.strkwargs(kwargs))
1442 bundle = pullop.remote.getbundle('pull', **pycompat.strkwargs(kwargs))
1426 try:
1443 try:
1427 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
1444 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
1428 except bundle2.AbortFromPart as exc:
1445 except bundle2.AbortFromPart as exc:
1429 pullop.repo.ui.status(_('remote: abort: %s\n') % exc)
1446 pullop.repo.ui.status(_('remote: abort: %s\n') % exc)
1430 raise error.Abort(_('pull failed on remote'), hint=exc.hint)
1447 raise error.Abort(_('pull failed on remote'), hint=exc.hint)
1431 except error.BundleValueError as exc:
1448 except error.BundleValueError as exc:
1432 raise error.Abort(_('missing support for %s') % exc)
1449 raise error.Abort(_('missing support for %s') % exc)
1433
1450
1434 if pullop.fetch:
1451 if pullop.fetch:
1435 pullop.cgresult = bundle2.combinechangegroupresults(op)
1452 pullop.cgresult = bundle2.combinechangegroupresults(op)
1436
1453
1437 # processing phases change
1454 # processing phases change
1438 for namespace, value in op.records['listkeys']:
1455 for namespace, value in op.records['listkeys']:
1439 if namespace == 'phases':
1456 if namespace == 'phases':
1440 _pullapplyphases(pullop, value)
1457 _pullapplyphases(pullop, value)
1441
1458
1442 # processing bookmark update
1459 # processing bookmark update
1443 for namespace, value in op.records['listkeys']:
1460 for namespace, value in op.records['listkeys']:
1444 if namespace == 'bookmarks':
1461 if namespace == 'bookmarks':
1445 pullop.remotebookmarks = value
1462 pullop.remotebookmarks = value
1446
1463
1447 # bookmark data were either already there or pulled in the bundle
1464 # bookmark data were either already there or pulled in the bundle
1448 if pullop.remotebookmarks is not None:
1465 if pullop.remotebookmarks is not None:
1449 _pullbookmarks(pullop)
1466 _pullbookmarks(pullop)
1450
1467
1451 def _pullbundle2extraprepare(pullop, kwargs):
1468 def _pullbundle2extraprepare(pullop, kwargs):
1452 """hook function so that extensions can extend the getbundle call"""
1469 """hook function so that extensions can extend the getbundle call"""
1453
1470
1454 def _pullchangeset(pullop):
1471 def _pullchangeset(pullop):
1455 """pull changeset from unbundle into the local repo"""
1472 """pull changeset from unbundle into the local repo"""
1456 # We delay the open of the transaction as late as possible so we
1473 # We delay the open of the transaction as late as possible so we
1457 # don't open transaction for nothing or you break future useful
1474 # don't open transaction for nothing or you break future useful
1458 # rollback call
1475 # rollback call
1459 if 'changegroup' in pullop.stepsdone:
1476 if 'changegroup' in pullop.stepsdone:
1460 return
1477 return
1461 pullop.stepsdone.add('changegroup')
1478 pullop.stepsdone.add('changegroup')
1462 if not pullop.fetch:
1479 if not pullop.fetch:
1463 pullop.repo.ui.status(_("no changes found\n"))
1480 pullop.repo.ui.status(_("no changes found\n"))
1464 pullop.cgresult = 0
1481 pullop.cgresult = 0
1465 return
1482 return
1466 tr = pullop.gettransaction()
1483 tr = pullop.gettransaction()
1467 if pullop.heads is None and list(pullop.common) == [nullid]:
1484 if pullop.heads is None and list(pullop.common) == [nullid]:
1468 pullop.repo.ui.status(_("requesting all changes\n"))
1485 pullop.repo.ui.status(_("requesting all changes\n"))
1469 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1486 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1470 # issue1320, avoid a race if remote changed after discovery
1487 # issue1320, avoid a race if remote changed after discovery
1471 pullop.heads = pullop.rheads
1488 pullop.heads = pullop.rheads
1472
1489
1473 if pullop.remote.capable('getbundle'):
1490 if pullop.remote.capable('getbundle'):
1474 # TODO: get bundlecaps from remote
1491 # TODO: get bundlecaps from remote
1475 cg = pullop.remote.getbundle('pull', common=pullop.common,
1492 cg = pullop.remote.getbundle('pull', common=pullop.common,
1476 heads=pullop.heads or pullop.rheads)
1493 heads=pullop.heads or pullop.rheads)
1477 elif pullop.heads is None:
1494 elif pullop.heads is None:
1478 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
1495 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
1479 elif not pullop.remote.capable('changegroupsubset'):
1496 elif not pullop.remote.capable('changegroupsubset'):
1480 raise error.Abort(_("partial pull cannot be done because "
1497 raise error.Abort(_("partial pull cannot be done because "
1481 "other repository doesn't support "
1498 "other repository doesn't support "
1482 "changegroupsubset."))
1499 "changegroupsubset."))
1483 else:
1500 else:
1484 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
1501 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
1485 bundleop = bundle2.applybundle(pullop.repo, cg, tr, 'pull',
1502 bundleop = bundle2.applybundle(pullop.repo, cg, tr, 'pull',
1486 pullop.remote.url())
1503 pullop.remote.url())
1487 pullop.cgresult = bundle2.combinechangegroupresults(bundleop)
1504 pullop.cgresult = bundle2.combinechangegroupresults(bundleop)
1488
1505
1489 def _pullphase(pullop):
1506 def _pullphase(pullop):
1490 # Get remote phases data from remote
1507 # Get remote phases data from remote
1491 if 'phases' in pullop.stepsdone:
1508 if 'phases' in pullop.stepsdone:
1492 return
1509 return
1493 remotephases = pullop.remote.listkeys('phases')
1510 remotephases = pullop.remote.listkeys('phases')
1494 _pullapplyphases(pullop, remotephases)
1511 _pullapplyphases(pullop, remotephases)
1495
1512
1496 def _pullapplyphases(pullop, remotephases):
1513 def _pullapplyphases(pullop, remotephases):
1497 """apply phase movement from observed remote state"""
1514 """apply phase movement from observed remote state"""
1498 if 'phases' in pullop.stepsdone:
1515 if 'phases' in pullop.stepsdone:
1499 return
1516 return
1500 pullop.stepsdone.add('phases')
1517 pullop.stepsdone.add('phases')
1501 publishing = bool(remotephases.get('publishing', False))
1518 publishing = bool(remotephases.get('publishing', False))
1502 if remotephases and not publishing:
1519 if remotephases and not publishing:
1503 # remote is new and non-publishing
1520 # remote is new and non-publishing
1504 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1521 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1505 pullop.pulledsubset,
1522 pullop.pulledsubset,
1506 remotephases)
1523 remotephases)
1507 dheads = pullop.pulledsubset
1524 dheads = pullop.pulledsubset
1508 else:
1525 else:
1509 # Remote is old or publishing all common changesets
1526 # Remote is old or publishing all common changesets
1510 # should be seen as public
1527 # should be seen as public
1511 pheads = pullop.pulledsubset
1528 pheads = pullop.pulledsubset
1512 dheads = []
1529 dheads = []
1513 unfi = pullop.repo.unfiltered()
1530 unfi = pullop.repo.unfiltered()
1514 phase = unfi._phasecache.phase
1531 phase = unfi._phasecache.phase
1515 rev = unfi.changelog.nodemap.get
1532 rev = unfi.changelog.nodemap.get
1516 public = phases.public
1533 public = phases.public
1517 draft = phases.draft
1534 draft = phases.draft
1518
1535
1519 # exclude changesets already public locally and update the others
1536 # exclude changesets already public locally and update the others
1520 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1537 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1521 if pheads:
1538 if pheads:
1522 tr = pullop.gettransaction()
1539 tr = pullop.gettransaction()
1523 phases.advanceboundary(pullop.repo, tr, public, pheads)
1540 phases.advanceboundary(pullop.repo, tr, public, pheads)
1524
1541
1525 # exclude changesets already draft locally and update the others
1542 # exclude changesets already draft locally and update the others
1526 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1543 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1527 if dheads:
1544 if dheads:
1528 tr = pullop.gettransaction()
1545 tr = pullop.gettransaction()
1529 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1546 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1530
1547
1531 def _pullbookmarks(pullop):
1548 def _pullbookmarks(pullop):
1532 """process the remote bookmark information to update the local one"""
1549 """process the remote bookmark information to update the local one"""
1533 if 'bookmarks' in pullop.stepsdone:
1550 if 'bookmarks' in pullop.stepsdone:
1534 return
1551 return
1535 pullop.stepsdone.add('bookmarks')
1552 pullop.stepsdone.add('bookmarks')
1536 repo = pullop.repo
1553 repo = pullop.repo
1537 remotebookmarks = pullop.remotebookmarks
1554 remotebookmarks = pullop.remotebookmarks
1538 remotebookmarks = bookmod.unhexlifybookmarks(remotebookmarks)
1555 remotebookmarks = bookmod.unhexlifybookmarks(remotebookmarks)
1539 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1556 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1540 pullop.remote.url(),
1557 pullop.remote.url(),
1541 pullop.gettransaction,
1558 pullop.gettransaction,
1542 explicit=pullop.explicitbookmarks)
1559 explicit=pullop.explicitbookmarks)
1543
1560
1544 def _pullobsolete(pullop):
1561 def _pullobsolete(pullop):
1545 """utility function to pull obsolete markers from a remote
1562 """utility function to pull obsolete markers from a remote
1546
1563
1547 The `gettransaction` is function that return the pull transaction, creating
1564 The `gettransaction` is function that return the pull transaction, creating
1548 one if necessary. We return the transaction to inform the calling code that
1565 one if necessary. We return the transaction to inform the calling code that
1549 a new transaction have been created (when applicable).
1566 a new transaction have been created (when applicable).
1550
1567
1551 Exists mostly to allow overriding for experimentation purpose"""
1568 Exists mostly to allow overriding for experimentation purpose"""
1552 if 'obsmarkers' in pullop.stepsdone:
1569 if 'obsmarkers' in pullop.stepsdone:
1553 return
1570 return
1554 pullop.stepsdone.add('obsmarkers')
1571 pullop.stepsdone.add('obsmarkers')
1555 tr = None
1572 tr = None
1556 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1573 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1557 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1574 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1558 remoteobs = pullop.remote.listkeys('obsolete')
1575 remoteobs = pullop.remote.listkeys('obsolete')
1559 if 'dump0' in remoteobs:
1576 if 'dump0' in remoteobs:
1560 tr = pullop.gettransaction()
1577 tr = pullop.gettransaction()
1561 markers = []
1578 markers = []
1562 for key in sorted(remoteobs, reverse=True):
1579 for key in sorted(remoteobs, reverse=True):
1563 if key.startswith('dump'):
1580 if key.startswith('dump'):
1564 data = util.b85decode(remoteobs[key])
1581 data = util.b85decode(remoteobs[key])
1565 version, newmarks = obsolete._readmarkers(data)
1582 version, newmarks = obsolete._readmarkers(data)
1566 markers += newmarks
1583 markers += newmarks
1567 if markers:
1584 if markers:
1568 pullop.repo.obsstore.add(tr, markers)
1585 pullop.repo.obsstore.add(tr, markers)
1569 pullop.repo.invalidatevolatilesets()
1586 pullop.repo.invalidatevolatilesets()
1570 return tr
1587 return tr
1571
1588
1572 def caps20to10(repo):
1589 def caps20to10(repo):
1573 """return a set with appropriate options to use bundle20 during getbundle"""
1590 """return a set with appropriate options to use bundle20 during getbundle"""
1574 caps = {'HG20'}
1591 caps = {'HG20'}
1575 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1592 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1576 caps.add('bundle2=' + urlreq.quote(capsblob))
1593 caps.add('bundle2=' + urlreq.quote(capsblob))
1577 return caps
1594 return caps
1578
1595
1579 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1596 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1580 getbundle2partsorder = []
1597 getbundle2partsorder = []
1581
1598
1582 # Mapping between step name and function
1599 # Mapping between step name and function
1583 #
1600 #
1584 # This exists to help extensions wrap steps if necessary
1601 # This exists to help extensions wrap steps if necessary
1585 getbundle2partsmapping = {}
1602 getbundle2partsmapping = {}
1586
1603
1587 def getbundle2partsgenerator(stepname, idx=None):
1604 def getbundle2partsgenerator(stepname, idx=None):
1588 """decorator for function generating bundle2 part for getbundle
1605 """decorator for function generating bundle2 part for getbundle
1589
1606
1590 The function is added to the step -> function mapping and appended to the
1607 The function is added to the step -> function mapping and appended to the
1591 list of steps. Beware that decorated functions will be added in order
1608 list of steps. Beware that decorated functions will be added in order
1592 (this may matter).
1609 (this may matter).
1593
1610
1594 You can only use this decorator for new steps, if you want to wrap a step
1611 You can only use this decorator for new steps, if you want to wrap a step
1595 from an extension, attack the getbundle2partsmapping dictionary directly."""
1612 from an extension, attack the getbundle2partsmapping dictionary directly."""
1596 def dec(func):
1613 def dec(func):
1597 assert stepname not in getbundle2partsmapping
1614 assert stepname not in getbundle2partsmapping
1598 getbundle2partsmapping[stepname] = func
1615 getbundle2partsmapping[stepname] = func
1599 if idx is None:
1616 if idx is None:
1600 getbundle2partsorder.append(stepname)
1617 getbundle2partsorder.append(stepname)
1601 else:
1618 else:
1602 getbundle2partsorder.insert(idx, stepname)
1619 getbundle2partsorder.insert(idx, stepname)
1603 return func
1620 return func
1604 return dec
1621 return dec
1605
1622
1606 def bundle2requested(bundlecaps):
1623 def bundle2requested(bundlecaps):
1607 if bundlecaps is not None:
1624 if bundlecaps is not None:
1608 return any(cap.startswith('HG2') for cap in bundlecaps)
1625 return any(cap.startswith('HG2') for cap in bundlecaps)
1609 return False
1626 return False
1610
1627
1611 def getbundlechunks(repo, source, heads=None, common=None, bundlecaps=None,
1628 def getbundlechunks(repo, source, heads=None, common=None, bundlecaps=None,
1612 **kwargs):
1629 **kwargs):
1613 """Return chunks constituting a bundle's raw data.
1630 """Return chunks constituting a bundle's raw data.
1614
1631
1615 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
1632 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
1616 passed.
1633 passed.
1617
1634
1618 Returns an iterator over raw chunks (of varying sizes).
1635 Returns an iterator over raw chunks (of varying sizes).
1619 """
1636 """
1620 kwargs = pycompat.byteskwargs(kwargs)
1637 kwargs = pycompat.byteskwargs(kwargs)
1621 usebundle2 = bundle2requested(bundlecaps)
1638 usebundle2 = bundle2requested(bundlecaps)
1622 # bundle10 case
1639 # bundle10 case
1623 if not usebundle2:
1640 if not usebundle2:
1624 if bundlecaps and not kwargs.get('cg', True):
1641 if bundlecaps and not kwargs.get('cg', True):
1625 raise ValueError(_('request for bundle10 must include changegroup'))
1642 raise ValueError(_('request for bundle10 must include changegroup'))
1626
1643
1627 if kwargs:
1644 if kwargs:
1628 raise ValueError(_('unsupported getbundle arguments: %s')
1645 raise ValueError(_('unsupported getbundle arguments: %s')
1629 % ', '.join(sorted(kwargs.keys())))
1646 % ', '.join(sorted(kwargs.keys())))
1630 outgoing = _computeoutgoing(repo, heads, common)
1647 outgoing = _computeoutgoing(repo, heads, common)
1631 return changegroup.makestream(repo, outgoing, '01', source,
1648 return changegroup.makestream(repo, outgoing, '01', source,
1632 bundlecaps=bundlecaps)
1649 bundlecaps=bundlecaps)
1633
1650
1634 # bundle20 case
1651 # bundle20 case
1635 b2caps = {}
1652 b2caps = {}
1636 for bcaps in bundlecaps:
1653 for bcaps in bundlecaps:
1637 if bcaps.startswith('bundle2='):
1654 if bcaps.startswith('bundle2='):
1638 blob = urlreq.unquote(bcaps[len('bundle2='):])
1655 blob = urlreq.unquote(bcaps[len('bundle2='):])
1639 b2caps.update(bundle2.decodecaps(blob))
1656 b2caps.update(bundle2.decodecaps(blob))
1640 bundler = bundle2.bundle20(repo.ui, b2caps)
1657 bundler = bundle2.bundle20(repo.ui, b2caps)
1641
1658
1642 kwargs['heads'] = heads
1659 kwargs['heads'] = heads
1643 kwargs['common'] = common
1660 kwargs['common'] = common
1644
1661
1645 for name in getbundle2partsorder:
1662 for name in getbundle2partsorder:
1646 func = getbundle2partsmapping[name]
1663 func = getbundle2partsmapping[name]
1647 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1664 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1648 **pycompat.strkwargs(kwargs))
1665 **pycompat.strkwargs(kwargs))
1649
1666
1650 return bundler.getchunks()
1667 return bundler.getchunks()
1651
1668
1652 @getbundle2partsgenerator('changegroup')
1669 @getbundle2partsgenerator('changegroup')
1653 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1670 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1654 b2caps=None, heads=None, common=None, **kwargs):
1671 b2caps=None, heads=None, common=None, **kwargs):
1655 """add a changegroup part to the requested bundle"""
1672 """add a changegroup part to the requested bundle"""
1656 cgstream = None
1673 cgstream = None
1657 if kwargs.get('cg', True):
1674 if kwargs.get('cg', True):
1658 # build changegroup bundle here.
1675 # build changegroup bundle here.
1659 version = '01'
1676 version = '01'
1660 cgversions = b2caps.get('changegroup')
1677 cgversions = b2caps.get('changegroup')
1661 if cgversions: # 3.1 and 3.2 ship with an empty value
1678 if cgversions: # 3.1 and 3.2 ship with an empty value
1662 cgversions = [v for v in cgversions
1679 cgversions = [v for v in cgversions
1663 if v in changegroup.supportedoutgoingversions(repo)]
1680 if v in changegroup.supportedoutgoingversions(repo)]
1664 if not cgversions:
1681 if not cgversions:
1665 raise ValueError(_('no common changegroup version'))
1682 raise ValueError(_('no common changegroup version'))
1666 version = max(cgversions)
1683 version = max(cgversions)
1667 outgoing = _computeoutgoing(repo, heads, common)
1684 outgoing = _computeoutgoing(repo, heads, common)
1668 if outgoing.missing:
1685 if outgoing.missing:
1669 cgstream = changegroup.makestream(repo, outgoing, version, source,
1686 cgstream = changegroup.makestream(repo, outgoing, version, source,
1670 bundlecaps=bundlecaps)
1687 bundlecaps=bundlecaps)
1671
1688
1672 if cgstream:
1689 if cgstream:
1673 part = bundler.newpart('changegroup', data=cgstream)
1690 part = bundler.newpart('changegroup', data=cgstream)
1674 if cgversions:
1691 if cgversions:
1675 part.addparam('version', version)
1692 part.addparam('version', version)
1676 part.addparam('nbchanges', '%d' % len(outgoing.missing),
1693 part.addparam('nbchanges', '%d' % len(outgoing.missing),
1677 mandatory=False)
1694 mandatory=False)
1678 if 'treemanifest' in repo.requirements:
1695 if 'treemanifest' in repo.requirements:
1679 part.addparam('treemanifest', '1')
1696 part.addparam('treemanifest', '1')
1680
1697
1681 @getbundle2partsgenerator('listkeys')
1698 @getbundle2partsgenerator('listkeys')
1682 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1699 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1683 b2caps=None, **kwargs):
1700 b2caps=None, **kwargs):
1684 """add parts containing listkeys namespaces to the requested bundle"""
1701 """add parts containing listkeys namespaces to the requested bundle"""
1685 listkeys = kwargs.get('listkeys', ())
1702 listkeys = kwargs.get('listkeys', ())
1686 for namespace in listkeys:
1703 for namespace in listkeys:
1687 part = bundler.newpart('listkeys')
1704 part = bundler.newpart('listkeys')
1688 part.addparam('namespace', namespace)
1705 part.addparam('namespace', namespace)
1689 keys = repo.listkeys(namespace).items()
1706 keys = repo.listkeys(namespace).items()
1690 part.data = pushkey.encodekeys(keys)
1707 part.data = pushkey.encodekeys(keys)
1691
1708
1692 @getbundle2partsgenerator('obsmarkers')
1709 @getbundle2partsgenerator('obsmarkers')
1693 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1710 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1694 b2caps=None, heads=None, **kwargs):
1711 b2caps=None, heads=None, **kwargs):
1695 """add an obsolescence markers part to the requested bundle"""
1712 """add an obsolescence markers part to the requested bundle"""
1696 if kwargs.get('obsmarkers', False):
1713 if kwargs.get('obsmarkers', False):
1697 if heads is None:
1714 if heads is None:
1698 heads = repo.heads()
1715 heads = repo.heads()
1699 subset = [c.node() for c in repo.set('::%ln', heads)]
1716 subset = [c.node() for c in repo.set('::%ln', heads)]
1700 markers = repo.obsstore.relevantmarkers(subset)
1717 markers = repo.obsstore.relevantmarkers(subset)
1701 markers = sorted(markers)
1718 markers = sorted(markers)
1702 bundle2.buildobsmarkerspart(bundler, markers)
1719 bundle2.buildobsmarkerspart(bundler, markers)
1703
1720
1704 @getbundle2partsgenerator('phases')
1721 @getbundle2partsgenerator('phases')
1705 def _getbundlephasespart(bundler, repo, source, bundlecaps=None,
1722 def _getbundlephasespart(bundler, repo, source, bundlecaps=None,
1706 b2caps=None, heads=None, **kwargs):
1723 b2caps=None, heads=None, **kwargs):
1707 """add phase heads part to the requested bundle"""
1724 """add phase heads part to the requested bundle"""
1708 if kwargs.get('phases', False):
1725 if kwargs.get('phases', False):
1709 if not 'heads' in b2caps.get('phases'):
1726 if not 'heads' in b2caps.get('phases'):
1710 raise ValueError(_('no common phases exchange method'))
1727 raise ValueError(_('no common phases exchange method'))
1711 if heads is None:
1728 if heads is None:
1712 heads = repo.heads()
1729 heads = repo.heads()
1713
1730
1714 headsbyphase = collections.defaultdict(set)
1731 headsbyphase = collections.defaultdict(set)
1715 if repo.publishing():
1732 if repo.publishing():
1716 headsbyphase[phases.public] = heads
1733 headsbyphase[phases.public] = heads
1717 else:
1734 else:
1718 # find the appropriate heads to move
1735 # find the appropriate heads to move
1719
1736
1720 phase = repo._phasecache.phase
1737 phase = repo._phasecache.phase
1721 node = repo.changelog.node
1738 node = repo.changelog.node
1722 rev = repo.changelog.rev
1739 rev = repo.changelog.rev
1723 for h in heads:
1740 for h in heads:
1724 headsbyphase[phase(repo, rev(h))].add(h)
1741 headsbyphase[phase(repo, rev(h))].add(h)
1725 seenphases = list(headsbyphase.keys())
1742 seenphases = list(headsbyphase.keys())
1726
1743
1727 # We do not handle anything but public and draft phase for now)
1744 # We do not handle anything but public and draft phase for now)
1728 if seenphases:
1745 if seenphases:
1729 assert max(seenphases) <= phases.draft
1746 assert max(seenphases) <= phases.draft
1730
1747
1731 # if client is pulling non-public changesets, we need to find
1748 # if client is pulling non-public changesets, we need to find
1732 # intermediate public heads.
1749 # intermediate public heads.
1733 draftheads = headsbyphase.get(phases.draft, set())
1750 draftheads = headsbyphase.get(phases.draft, set())
1734 if draftheads:
1751 if draftheads:
1735 publicheads = headsbyphase.get(phases.public, set())
1752 publicheads = headsbyphase.get(phases.public, set())
1736
1753
1737 revset = 'heads(only(%ln, %ln) and public())'
1754 revset = 'heads(only(%ln, %ln) and public())'
1738 extraheads = repo.revs(revset, draftheads, publicheads)
1755 extraheads = repo.revs(revset, draftheads, publicheads)
1739 for r in extraheads:
1756 for r in extraheads:
1740 headsbyphase[phases.public].add(node(r))
1757 headsbyphase[phases.public].add(node(r))
1741
1758
1742 # transform data in a format used by the encoding function
1759 # transform data in a format used by the encoding function
1743 phasemapping = []
1760 phasemapping = []
1744 for phase in phases.allphases:
1761 for phase in phases.allphases:
1745 phasemapping.append(sorted(headsbyphase[phase]))
1762 phasemapping.append(sorted(headsbyphase[phase]))
1746
1763
1747 # generate the actual part
1764 # generate the actual part
1748 phasedata = phases.binaryencode(phasemapping)
1765 phasedata = phases.binaryencode(phasemapping)
1749 bundler.newpart('phase-heads', data=phasedata)
1766 bundler.newpart('phase-heads', data=phasedata)
1750
1767
1751 @getbundle2partsgenerator('hgtagsfnodes')
1768 @getbundle2partsgenerator('hgtagsfnodes')
1752 def _getbundletagsfnodes(bundler, repo, source, bundlecaps=None,
1769 def _getbundletagsfnodes(bundler, repo, source, bundlecaps=None,
1753 b2caps=None, heads=None, common=None,
1770 b2caps=None, heads=None, common=None,
1754 **kwargs):
1771 **kwargs):
1755 """Transfer the .hgtags filenodes mapping.
1772 """Transfer the .hgtags filenodes mapping.
1756
1773
1757 Only values for heads in this bundle will be transferred.
1774 Only values for heads in this bundle will be transferred.
1758
1775
1759 The part data consists of pairs of 20 byte changeset node and .hgtags
1776 The part data consists of pairs of 20 byte changeset node and .hgtags
1760 filenodes raw values.
1777 filenodes raw values.
1761 """
1778 """
1762 # Don't send unless:
1779 # Don't send unless:
1763 # - changeset are being exchanged,
1780 # - changeset are being exchanged,
1764 # - the client supports it.
1781 # - the client supports it.
1765 if not (kwargs.get('cg', True) and 'hgtagsfnodes' in b2caps):
1782 if not (kwargs.get('cg', True) and 'hgtagsfnodes' in b2caps):
1766 return
1783 return
1767
1784
1768 outgoing = _computeoutgoing(repo, heads, common)
1785 outgoing = _computeoutgoing(repo, heads, common)
1769 bundle2.addparttagsfnodescache(repo, bundler, outgoing)
1786 bundle2.addparttagsfnodescache(repo, bundler, outgoing)
1770
1787
1771 def _getbookmarks(repo, **kwargs):
1788 def _getbookmarks(repo, **kwargs):
1772 """Returns bookmark to node mapping.
1789 """Returns bookmark to node mapping.
1773
1790
1774 This function is primarily used to generate `bookmarks` bundle2 part.
1791 This function is primarily used to generate `bookmarks` bundle2 part.
1775 It is a separate function in order to make it easy to wrap it
1792 It is a separate function in order to make it easy to wrap it
1776 in extensions. Passing `kwargs` to the function makes it easy to
1793 in extensions. Passing `kwargs` to the function makes it easy to
1777 add new parameters in extensions.
1794 add new parameters in extensions.
1778 """
1795 """
1779
1796
1780 return dict(bookmod.listbinbookmarks(repo))
1797 return dict(bookmod.listbinbookmarks(repo))
1781
1798
1782 def check_heads(repo, their_heads, context):
1799 def check_heads(repo, their_heads, context):
1783 """check if the heads of a repo have been modified
1800 """check if the heads of a repo have been modified
1784
1801
1785 Used by peer for unbundling.
1802 Used by peer for unbundling.
1786 """
1803 """
1787 heads = repo.heads()
1804 heads = repo.heads()
1788 heads_hash = hashlib.sha1(''.join(sorted(heads))).digest()
1805 heads_hash = hashlib.sha1(''.join(sorted(heads))).digest()
1789 if not (their_heads == ['force'] or their_heads == heads or
1806 if not (their_heads == ['force'] or their_heads == heads or
1790 their_heads == ['hashed', heads_hash]):
1807 their_heads == ['hashed', heads_hash]):
1791 # someone else committed/pushed/unbundled while we
1808 # someone else committed/pushed/unbundled while we
1792 # were transferring data
1809 # were transferring data
1793 raise error.PushRaced('repository changed while %s - '
1810 raise error.PushRaced('repository changed while %s - '
1794 'please try again' % context)
1811 'please try again' % context)
1795
1812
1796 def unbundle(repo, cg, heads, source, url):
1813 def unbundle(repo, cg, heads, source, url):
1797 """Apply a bundle to a repo.
1814 """Apply a bundle to a repo.
1798
1815
1799 this function makes sure the repo is locked during the application and have
1816 this function makes sure the repo is locked during the application and have
1800 mechanism to check that no push race occurred between the creation of the
1817 mechanism to check that no push race occurred between the creation of the
1801 bundle and its application.
1818 bundle and its application.
1802
1819
1803 If the push was raced as PushRaced exception is raised."""
1820 If the push was raced as PushRaced exception is raised."""
1804 r = 0
1821 r = 0
1805 # need a transaction when processing a bundle2 stream
1822 # need a transaction when processing a bundle2 stream
1806 # [wlock, lock, tr] - needs to be an array so nested functions can modify it
1823 # [wlock, lock, tr] - needs to be an array so nested functions can modify it
1807 lockandtr = [None, None, None]
1824 lockandtr = [None, None, None]
1808 recordout = None
1825 recordout = None
1809 # quick fix for output mismatch with bundle2 in 3.4
1826 # quick fix for output mismatch with bundle2 in 3.4
1810 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture')
1827 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture')
1811 if url.startswith('remote:http:') or url.startswith('remote:https:'):
1828 if url.startswith('remote:http:') or url.startswith('remote:https:'):
1812 captureoutput = True
1829 captureoutput = True
1813 try:
1830 try:
1814 # note: outside bundle1, 'heads' is expected to be empty and this
1831 # note: outside bundle1, 'heads' is expected to be empty and this
1815 # 'check_heads' call wil be a no-op
1832 # 'check_heads' call wil be a no-op
1816 check_heads(repo, heads, 'uploading changes')
1833 check_heads(repo, heads, 'uploading changes')
1817 # push can proceed
1834 # push can proceed
1818 if not isinstance(cg, bundle2.unbundle20):
1835 if not isinstance(cg, bundle2.unbundle20):
1819 # legacy case: bundle1 (changegroup 01)
1836 # legacy case: bundle1 (changegroup 01)
1820 txnname = "\n".join([source, util.hidepassword(url)])
1837 txnname = "\n".join([source, util.hidepassword(url)])
1821 with repo.lock(), repo.transaction(txnname) as tr:
1838 with repo.lock(), repo.transaction(txnname) as tr:
1822 op = bundle2.applybundle(repo, cg, tr, source, url)
1839 op = bundle2.applybundle(repo, cg, tr, source, url)
1823 r = bundle2.combinechangegroupresults(op)
1840 r = bundle2.combinechangegroupresults(op)
1824 else:
1841 else:
1825 r = None
1842 r = None
1826 try:
1843 try:
1827 def gettransaction():
1844 def gettransaction():
1828 if not lockandtr[2]:
1845 if not lockandtr[2]:
1829 lockandtr[0] = repo.wlock()
1846 lockandtr[0] = repo.wlock()
1830 lockandtr[1] = repo.lock()
1847 lockandtr[1] = repo.lock()
1831 lockandtr[2] = repo.transaction(source)
1848 lockandtr[2] = repo.transaction(source)
1832 lockandtr[2].hookargs['source'] = source
1849 lockandtr[2].hookargs['source'] = source
1833 lockandtr[2].hookargs['url'] = url
1850 lockandtr[2].hookargs['url'] = url
1834 lockandtr[2].hookargs['bundle2'] = '1'
1851 lockandtr[2].hookargs['bundle2'] = '1'
1835 return lockandtr[2]
1852 return lockandtr[2]
1836
1853
1837 # Do greedy locking by default until we're satisfied with lazy
1854 # Do greedy locking by default until we're satisfied with lazy
1838 # locking.
1855 # locking.
1839 if not repo.ui.configbool('experimental', 'bundle2lazylocking'):
1856 if not repo.ui.configbool('experimental', 'bundle2lazylocking'):
1840 gettransaction()
1857 gettransaction()
1841
1858
1842 op = bundle2.bundleoperation(repo, gettransaction,
1859 op = bundle2.bundleoperation(repo, gettransaction,
1843 captureoutput=captureoutput)
1860 captureoutput=captureoutput)
1844 try:
1861 try:
1845 op = bundle2.processbundle(repo, cg, op=op)
1862 op = bundle2.processbundle(repo, cg, op=op)
1846 finally:
1863 finally:
1847 r = op.reply
1864 r = op.reply
1848 if captureoutput and r is not None:
1865 if captureoutput and r is not None:
1849 repo.ui.pushbuffer(error=True, subproc=True)
1866 repo.ui.pushbuffer(error=True, subproc=True)
1850 def recordout(output):
1867 def recordout(output):
1851 r.newpart('output', data=output, mandatory=False)
1868 r.newpart('output', data=output, mandatory=False)
1852 if lockandtr[2] is not None:
1869 if lockandtr[2] is not None:
1853 lockandtr[2].close()
1870 lockandtr[2].close()
1854 except BaseException as exc:
1871 except BaseException as exc:
1855 exc.duringunbundle2 = True
1872 exc.duringunbundle2 = True
1856 if captureoutput and r is not None:
1873 if captureoutput and r is not None:
1857 parts = exc._bundle2salvagedoutput = r.salvageoutput()
1874 parts = exc._bundle2salvagedoutput = r.salvageoutput()
1858 def recordout(output):
1875 def recordout(output):
1859 part = bundle2.bundlepart('output', data=output,
1876 part = bundle2.bundlepart('output', data=output,
1860 mandatory=False)
1877 mandatory=False)
1861 parts.append(part)
1878 parts.append(part)
1862 raise
1879 raise
1863 finally:
1880 finally:
1864 lockmod.release(lockandtr[2], lockandtr[1], lockandtr[0])
1881 lockmod.release(lockandtr[2], lockandtr[1], lockandtr[0])
1865 if recordout is not None:
1882 if recordout is not None:
1866 recordout(repo.ui.popbuffer())
1883 recordout(repo.ui.popbuffer())
1867 return r
1884 return r
1868
1885
1869 def _maybeapplyclonebundle(pullop):
1886 def _maybeapplyclonebundle(pullop):
1870 """Apply a clone bundle from a remote, if possible."""
1887 """Apply a clone bundle from a remote, if possible."""
1871
1888
1872 repo = pullop.repo
1889 repo = pullop.repo
1873 remote = pullop.remote
1890 remote = pullop.remote
1874
1891
1875 if not repo.ui.configbool('ui', 'clonebundles'):
1892 if not repo.ui.configbool('ui', 'clonebundles'):
1876 return
1893 return
1877
1894
1878 # Only run if local repo is empty.
1895 # Only run if local repo is empty.
1879 if len(repo):
1896 if len(repo):
1880 return
1897 return
1881
1898
1882 if pullop.heads:
1899 if pullop.heads:
1883 return
1900 return
1884
1901
1885 if not remote.capable('clonebundles'):
1902 if not remote.capable('clonebundles'):
1886 return
1903 return
1887
1904
1888 res = remote._call('clonebundles')
1905 res = remote._call('clonebundles')
1889
1906
1890 # If we call the wire protocol command, that's good enough to record the
1907 # If we call the wire protocol command, that's good enough to record the
1891 # attempt.
1908 # attempt.
1892 pullop.clonebundleattempted = True
1909 pullop.clonebundleattempted = True
1893
1910
1894 entries = parseclonebundlesmanifest(repo, res)
1911 entries = parseclonebundlesmanifest(repo, res)
1895 if not entries:
1912 if not entries:
1896 repo.ui.note(_('no clone bundles available on remote; '
1913 repo.ui.note(_('no clone bundles available on remote; '
1897 'falling back to regular clone\n'))
1914 'falling back to regular clone\n'))
1898 return
1915 return
1899
1916
1900 entries = filterclonebundleentries(
1917 entries = filterclonebundleentries(
1901 repo, entries, streamclonerequested=pullop.streamclonerequested)
1918 repo, entries, streamclonerequested=pullop.streamclonerequested)
1902
1919
1903 if not entries:
1920 if not entries:
1904 # There is a thundering herd concern here. However, if a server
1921 # There is a thundering herd concern here. However, if a server
1905 # operator doesn't advertise bundles appropriate for its clients,
1922 # operator doesn't advertise bundles appropriate for its clients,
1906 # they deserve what's coming. Furthermore, from a client's
1923 # they deserve what's coming. Furthermore, from a client's
1907 # perspective, no automatic fallback would mean not being able to
1924 # perspective, no automatic fallback would mean not being able to
1908 # clone!
1925 # clone!
1909 repo.ui.warn(_('no compatible clone bundles available on server; '
1926 repo.ui.warn(_('no compatible clone bundles available on server; '
1910 'falling back to regular clone\n'))
1927 'falling back to regular clone\n'))
1911 repo.ui.warn(_('(you may want to report this to the server '
1928 repo.ui.warn(_('(you may want to report this to the server '
1912 'operator)\n'))
1929 'operator)\n'))
1913 return
1930 return
1914
1931
1915 entries = sortclonebundleentries(repo.ui, entries)
1932 entries = sortclonebundleentries(repo.ui, entries)
1916
1933
1917 url = entries[0]['URL']
1934 url = entries[0]['URL']
1918 repo.ui.status(_('applying clone bundle from %s\n') % url)
1935 repo.ui.status(_('applying clone bundle from %s\n') % url)
1919 if trypullbundlefromurl(repo.ui, repo, url):
1936 if trypullbundlefromurl(repo.ui, repo, url):
1920 repo.ui.status(_('finished applying clone bundle\n'))
1937 repo.ui.status(_('finished applying clone bundle\n'))
1921 # Bundle failed.
1938 # Bundle failed.
1922 #
1939 #
1923 # We abort by default to avoid the thundering herd of
1940 # We abort by default to avoid the thundering herd of
1924 # clients flooding a server that was expecting expensive
1941 # clients flooding a server that was expecting expensive
1925 # clone load to be offloaded.
1942 # clone load to be offloaded.
1926 elif repo.ui.configbool('ui', 'clonebundlefallback'):
1943 elif repo.ui.configbool('ui', 'clonebundlefallback'):
1927 repo.ui.warn(_('falling back to normal clone\n'))
1944 repo.ui.warn(_('falling back to normal clone\n'))
1928 else:
1945 else:
1929 raise error.Abort(_('error applying bundle'),
1946 raise error.Abort(_('error applying bundle'),
1930 hint=_('if this error persists, consider contacting '
1947 hint=_('if this error persists, consider contacting '
1931 'the server operator or disable clone '
1948 'the server operator or disable clone '
1932 'bundles via '
1949 'bundles via '
1933 '"--config ui.clonebundles=false"'))
1950 '"--config ui.clonebundles=false"'))
1934
1951
1935 def parseclonebundlesmanifest(repo, s):
1952 def parseclonebundlesmanifest(repo, s):
1936 """Parses the raw text of a clone bundles manifest.
1953 """Parses the raw text of a clone bundles manifest.
1937
1954
1938 Returns a list of dicts. The dicts have a ``URL`` key corresponding
1955 Returns a list of dicts. The dicts have a ``URL`` key corresponding
1939 to the URL and other keys are the attributes for the entry.
1956 to the URL and other keys are the attributes for the entry.
1940 """
1957 """
1941 m = []
1958 m = []
1942 for line in s.splitlines():
1959 for line in s.splitlines():
1943 fields = line.split()
1960 fields = line.split()
1944 if not fields:
1961 if not fields:
1945 continue
1962 continue
1946 attrs = {'URL': fields[0]}
1963 attrs = {'URL': fields[0]}
1947 for rawattr in fields[1:]:
1964 for rawattr in fields[1:]:
1948 key, value = rawattr.split('=', 1)
1965 key, value = rawattr.split('=', 1)
1949 key = urlreq.unquote(key)
1966 key = urlreq.unquote(key)
1950 value = urlreq.unquote(value)
1967 value = urlreq.unquote(value)
1951 attrs[key] = value
1968 attrs[key] = value
1952
1969
1953 # Parse BUNDLESPEC into components. This makes client-side
1970 # Parse BUNDLESPEC into components. This makes client-side
1954 # preferences easier to specify since you can prefer a single
1971 # preferences easier to specify since you can prefer a single
1955 # component of the BUNDLESPEC.
1972 # component of the BUNDLESPEC.
1956 if key == 'BUNDLESPEC':
1973 if key == 'BUNDLESPEC':
1957 try:
1974 try:
1958 comp, version, params = parsebundlespec(repo, value,
1975 comp, version, params = parsebundlespec(repo, value,
1959 externalnames=True)
1976 externalnames=True)
1960 attrs['COMPRESSION'] = comp
1977 attrs['COMPRESSION'] = comp
1961 attrs['VERSION'] = version
1978 attrs['VERSION'] = version
1962 except error.InvalidBundleSpecification:
1979 except error.InvalidBundleSpecification:
1963 pass
1980 pass
1964 except error.UnsupportedBundleSpecification:
1981 except error.UnsupportedBundleSpecification:
1965 pass
1982 pass
1966
1983
1967 m.append(attrs)
1984 m.append(attrs)
1968
1985
1969 return m
1986 return m
1970
1987
1971 def filterclonebundleentries(repo, entries, streamclonerequested=False):
1988 def filterclonebundleentries(repo, entries, streamclonerequested=False):
1972 """Remove incompatible clone bundle manifest entries.
1989 """Remove incompatible clone bundle manifest entries.
1973
1990
1974 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
1991 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
1975 and returns a new list consisting of only the entries that this client
1992 and returns a new list consisting of only the entries that this client
1976 should be able to apply.
1993 should be able to apply.
1977
1994
1978 There is no guarantee we'll be able to apply all returned entries because
1995 There is no guarantee we'll be able to apply all returned entries because
1979 the metadata we use to filter on may be missing or wrong.
1996 the metadata we use to filter on may be missing or wrong.
1980 """
1997 """
1981 newentries = []
1998 newentries = []
1982 for entry in entries:
1999 for entry in entries:
1983 spec = entry.get('BUNDLESPEC')
2000 spec = entry.get('BUNDLESPEC')
1984 if spec:
2001 if spec:
1985 try:
2002 try:
1986 comp, version, params = parsebundlespec(repo, spec, strict=True)
2003 comp, version, params = parsebundlespec(repo, spec, strict=True)
1987
2004
1988 # If a stream clone was requested, filter out non-streamclone
2005 # If a stream clone was requested, filter out non-streamclone
1989 # entries.
2006 # entries.
1990 if streamclonerequested and (comp != 'UN' or version != 's1'):
2007 if streamclonerequested and (comp != 'UN' or version != 's1'):
1991 repo.ui.debug('filtering %s because not a stream clone\n' %
2008 repo.ui.debug('filtering %s because not a stream clone\n' %
1992 entry['URL'])
2009 entry['URL'])
1993 continue
2010 continue
1994
2011
1995 except error.InvalidBundleSpecification as e:
2012 except error.InvalidBundleSpecification as e:
1996 repo.ui.debug(str(e) + '\n')
2013 repo.ui.debug(str(e) + '\n')
1997 continue
2014 continue
1998 except error.UnsupportedBundleSpecification as e:
2015 except error.UnsupportedBundleSpecification as e:
1999 repo.ui.debug('filtering %s because unsupported bundle '
2016 repo.ui.debug('filtering %s because unsupported bundle '
2000 'spec: %s\n' % (entry['URL'], str(e)))
2017 'spec: %s\n' % (entry['URL'], str(e)))
2001 continue
2018 continue
2002 # If we don't have a spec and requested a stream clone, we don't know
2019 # If we don't have a spec and requested a stream clone, we don't know
2003 # what the entry is so don't attempt to apply it.
2020 # what the entry is so don't attempt to apply it.
2004 elif streamclonerequested:
2021 elif streamclonerequested:
2005 repo.ui.debug('filtering %s because cannot determine if a stream '
2022 repo.ui.debug('filtering %s because cannot determine if a stream '
2006 'clone bundle\n' % entry['URL'])
2023 'clone bundle\n' % entry['URL'])
2007 continue
2024 continue
2008
2025
2009 if 'REQUIRESNI' in entry and not sslutil.hassni:
2026 if 'REQUIRESNI' in entry and not sslutil.hassni:
2010 repo.ui.debug('filtering %s because SNI not supported\n' %
2027 repo.ui.debug('filtering %s because SNI not supported\n' %
2011 entry['URL'])
2028 entry['URL'])
2012 continue
2029 continue
2013
2030
2014 newentries.append(entry)
2031 newentries.append(entry)
2015
2032
2016 return newentries
2033 return newentries
2017
2034
2018 class clonebundleentry(object):
2035 class clonebundleentry(object):
2019 """Represents an item in a clone bundles manifest.
2036 """Represents an item in a clone bundles manifest.
2020
2037
2021 This rich class is needed to support sorting since sorted() in Python 3
2038 This rich class is needed to support sorting since sorted() in Python 3
2022 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
2039 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
2023 won't work.
2040 won't work.
2024 """
2041 """
2025
2042
2026 def __init__(self, value, prefers):
2043 def __init__(self, value, prefers):
2027 self.value = value
2044 self.value = value
2028 self.prefers = prefers
2045 self.prefers = prefers
2029
2046
2030 def _cmp(self, other):
2047 def _cmp(self, other):
2031 for prefkey, prefvalue in self.prefers:
2048 for prefkey, prefvalue in self.prefers:
2032 avalue = self.value.get(prefkey)
2049 avalue = self.value.get(prefkey)
2033 bvalue = other.value.get(prefkey)
2050 bvalue = other.value.get(prefkey)
2034
2051
2035 # Special case for b missing attribute and a matches exactly.
2052 # Special case for b missing attribute and a matches exactly.
2036 if avalue is not None and bvalue is None and avalue == prefvalue:
2053 if avalue is not None and bvalue is None and avalue == prefvalue:
2037 return -1
2054 return -1
2038
2055
2039 # Special case for a missing attribute and b matches exactly.
2056 # Special case for a missing attribute and b matches exactly.
2040 if bvalue is not None and avalue is None and bvalue == prefvalue:
2057 if bvalue is not None and avalue is None and bvalue == prefvalue:
2041 return 1
2058 return 1
2042
2059
2043 # We can't compare unless attribute present on both.
2060 # We can't compare unless attribute present on both.
2044 if avalue is None or bvalue is None:
2061 if avalue is None or bvalue is None:
2045 continue
2062 continue
2046
2063
2047 # Same values should fall back to next attribute.
2064 # Same values should fall back to next attribute.
2048 if avalue == bvalue:
2065 if avalue == bvalue:
2049 continue
2066 continue
2050
2067
2051 # Exact matches come first.
2068 # Exact matches come first.
2052 if avalue == prefvalue:
2069 if avalue == prefvalue:
2053 return -1
2070 return -1
2054 if bvalue == prefvalue:
2071 if bvalue == prefvalue:
2055 return 1
2072 return 1
2056
2073
2057 # Fall back to next attribute.
2074 # Fall back to next attribute.
2058 continue
2075 continue
2059
2076
2060 # If we got here we couldn't sort by attributes and prefers. Fall
2077 # If we got here we couldn't sort by attributes and prefers. Fall
2061 # back to index order.
2078 # back to index order.
2062 return 0
2079 return 0
2063
2080
2064 def __lt__(self, other):
2081 def __lt__(self, other):
2065 return self._cmp(other) < 0
2082 return self._cmp(other) < 0
2066
2083
2067 def __gt__(self, other):
2084 def __gt__(self, other):
2068 return self._cmp(other) > 0
2085 return self._cmp(other) > 0
2069
2086
2070 def __eq__(self, other):
2087 def __eq__(self, other):
2071 return self._cmp(other) == 0
2088 return self._cmp(other) == 0
2072
2089
2073 def __le__(self, other):
2090 def __le__(self, other):
2074 return self._cmp(other) <= 0
2091 return self._cmp(other) <= 0
2075
2092
2076 def __ge__(self, other):
2093 def __ge__(self, other):
2077 return self._cmp(other) >= 0
2094 return self._cmp(other) >= 0
2078
2095
2079 def __ne__(self, other):
2096 def __ne__(self, other):
2080 return self._cmp(other) != 0
2097 return self._cmp(other) != 0
2081
2098
2082 def sortclonebundleentries(ui, entries):
2099 def sortclonebundleentries(ui, entries):
2083 prefers = ui.configlist('ui', 'clonebundleprefers')
2100 prefers = ui.configlist('ui', 'clonebundleprefers')
2084 if not prefers:
2101 if not prefers:
2085 return list(entries)
2102 return list(entries)
2086
2103
2087 prefers = [p.split('=', 1) for p in prefers]
2104 prefers = [p.split('=', 1) for p in prefers]
2088
2105
2089 items = sorted(clonebundleentry(v, prefers) for v in entries)
2106 items = sorted(clonebundleentry(v, prefers) for v in entries)
2090 return [i.value for i in items]
2107 return [i.value for i in items]
2091
2108
2092 def trypullbundlefromurl(ui, repo, url):
2109 def trypullbundlefromurl(ui, repo, url):
2093 """Attempt to apply a bundle from a URL."""
2110 """Attempt to apply a bundle from a URL."""
2094 with repo.lock(), repo.transaction('bundleurl') as tr:
2111 with repo.lock(), repo.transaction('bundleurl') as tr:
2095 try:
2112 try:
2096 fh = urlmod.open(ui, url)
2113 fh = urlmod.open(ui, url)
2097 cg = readbundle(ui, fh, 'stream')
2114 cg = readbundle(ui, fh, 'stream')
2098
2115
2099 if isinstance(cg, streamclone.streamcloneapplier):
2116 if isinstance(cg, streamclone.streamcloneapplier):
2100 cg.apply(repo)
2117 cg.apply(repo)
2101 else:
2118 else:
2102 bundle2.applybundle(repo, cg, tr, 'clonebundles', url)
2119 bundle2.applybundle(repo, cg, tr, 'clonebundles', url)
2103 return True
2120 return True
2104 except urlerr.httperror as e:
2121 except urlerr.httperror as e:
2105 ui.warn(_('HTTP error fetching bundle: %s\n') % str(e))
2122 ui.warn(_('HTTP error fetching bundle: %s\n') % str(e))
2106 except urlerr.urlerror as e:
2123 except urlerr.urlerror as e:
2107 ui.warn(_('error fetching bundle: %s\n') % e.reason)
2124 ui.warn(_('error fetching bundle: %s\n') % e.reason)
2108
2125
2109 return False
2126 return False
@@ -1,2214 +1,2183
1 > do_push()
1 > do_push()
2 > {
2 > {
3 > user=$1
3 > user=$1
4 > shift
4 > shift
5 > echo "Pushing as user $user"
5 > echo "Pushing as user $user"
6 > echo 'hgrc = """'
6 > echo 'hgrc = """'
7 > sed -n '/\[[ha]/,$p' b/.hg/hgrc | grep -v fakegroups.py
7 > sed -n '/\[[ha]/,$p' b/.hg/hgrc | grep -v fakegroups.py
8 > echo '"""'
8 > echo '"""'
9 > if test -f acl.config; then
9 > if test -f acl.config; then
10 > echo 'acl.config = """'
10 > echo 'acl.config = """'
11 > cat acl.config
11 > cat acl.config
12 > echo '"""'
12 > echo '"""'
13 > fi
13 > fi
14 > # On AIX /etc/profile sets LOGNAME read-only. So
14 > # On AIX /etc/profile sets LOGNAME read-only. So
15 > # LOGNAME=$user hg --cws a --debug push ../b
15 > # LOGNAME=$user hg --cws a --debug push ../b
16 > # fails with "This variable is read only."
16 > # fails with "This variable is read only."
17 > # Use env to work around this.
17 > # Use env to work around this.
18 > env LOGNAME=$user hg --cwd a --debug push ../b
18 > env LOGNAME=$user hg --cwd a --debug push ../b
19 > hg --cwd b rollback
19 > hg --cwd b rollback
20 > hg --cwd b --quiet tip
20 > hg --cwd b --quiet tip
21 > echo
21 > echo
22 > }
22 > }
23
23
24 > init_config()
24 > init_config()
25 > {
25 > {
26 > cat > fakegroups.py <<EOF
26 > cat > fakegroups.py <<EOF
27 > from hgext import acl
27 > from hgext import acl
28 > def fakegetusers(ui, group):
28 > def fakegetusers(ui, group):
29 > try:
29 > try:
30 > return acl._getusersorig(ui, group)
30 > return acl._getusersorig(ui, group)
31 > except:
31 > except:
32 > return ["fred", "betty"]
32 > return ["fred", "betty"]
33 > acl._getusersorig = acl._getusers
33 > acl._getusersorig = acl._getusers
34 > acl._getusers = fakegetusers
34 > acl._getusers = fakegetusers
35 > EOF
35 > EOF
36 > rm -f acl.config
36 > rm -f acl.config
37 > cat > $config <<EOF
37 > cat > $config <<EOF
38 > [hooks]
38 > [hooks]
39 > pretxnchangegroup.acl = python:hgext.acl.hook
39 > pretxnchangegroup.acl = python:hgext.acl.hook
40 > [acl]
40 > [acl]
41 > sources = push
41 > sources = push
42 > [extensions]
42 > [extensions]
43 > f=`pwd`/fakegroups.py
43 > f=`pwd`/fakegroups.py
44 > EOF
44 > EOF
45 > }
45 > }
46
46
47 $ hg init a
47 $ hg init a
48 $ cd a
48 $ cd a
49 $ mkdir foo foo/Bar quux
49 $ mkdir foo foo/Bar quux
50 $ echo 'in foo' > foo/file.txt
50 $ echo 'in foo' > foo/file.txt
51 $ echo 'in foo/Bar' > foo/Bar/file.txt
51 $ echo 'in foo/Bar' > foo/Bar/file.txt
52 $ echo 'in quux' > quux/file.py
52 $ echo 'in quux' > quux/file.py
53 $ hg add -q
53 $ hg add -q
54 $ hg ci -m 'add files' -d '1000000 0'
54 $ hg ci -m 'add files' -d '1000000 0'
55 $ echo >> foo/file.txt
55 $ echo >> foo/file.txt
56 $ hg ci -m 'change foo/file' -d '1000001 0'
56 $ hg ci -m 'change foo/file' -d '1000001 0'
57 $ echo >> foo/Bar/file.txt
57 $ echo >> foo/Bar/file.txt
58 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
58 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
59 $ echo >> quux/file.py
59 $ echo >> quux/file.py
60 $ hg ci -m 'change quux/file' -d '1000003 0'
60 $ hg ci -m 'change quux/file' -d '1000003 0'
61 $ hg tip --quiet
61 $ hg tip --quiet
62 3:911600dab2ae
62 3:911600dab2ae
63
63
64 $ cd ..
64 $ cd ..
65 $ hg clone -r 0 a b
65 $ hg clone -r 0 a b
66 adding changesets
66 adding changesets
67 adding manifests
67 adding manifests
68 adding file changes
68 adding file changes
69 added 1 changesets with 3 changes to 3 files
69 added 1 changesets with 3 changes to 3 files
70 new changesets 6675d58eff77
70 new changesets 6675d58eff77
71 updating to branch default
71 updating to branch default
72 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
72 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
73
73
74 $ config=b/.hg/hgrc
74 $ config=b/.hg/hgrc
75
75
76 Extension disabled for lack of a hook
76 Extension disabled for lack of a hook
77
77
78 $ do_push fred
78 $ do_push fred
79 Pushing as user fred
79 Pushing as user fred
80 hgrc = """
80 hgrc = """
81 """
81 """
82 pushing to ../b
82 pushing to ../b
83 query 1; heads
83 query 1; heads
84 searching for changes
84 searching for changes
85 all remote heads known locally
85 all remote heads known locally
86 listing keys for "phases"
86 listing keys for "phases"
87 checking for updated bookmarks
87 checking for updated bookmarks
88 listing keys for "bookmarks"
88 listing keys for "bookmarks"
89 listing keys for "bookmarks"
89 listing keys for "bookmarks"
90 3 changesets found
90 3 changesets found
91 list of changesets:
91 list of changesets:
92 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
92 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
93 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
93 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
94 911600dab2ae7a9baff75958b84fe606851ce955
94 911600dab2ae7a9baff75958b84fe606851ce955
95 bundle2-output-bundle: "HG20", 5 parts total
95 bundle2-output-bundle: "HG20", 5 parts total
96 bundle2-output-part: "replycaps" 168 bytes payload
96 bundle2-output-part: "replycaps" 168 bytes payload
97 bundle2-output-part: "check:phases" 24 bytes payload
97 bundle2-output-part: "check:phases" 24 bytes payload
98 bundle2-output-part: "check:heads" streamed payload
98 bundle2-output-part: "check:heads" streamed payload
99 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
99 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
100 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
100 bundle2-output-part: "phase-heads" 24 bytes payload
101 bundle2-input-bundle: with-transaction
101 bundle2-input-bundle: with-transaction
102 bundle2-input-part: "replycaps" supported
102 bundle2-input-part: "replycaps" supported
103 bundle2-input-part: total payload size 168
103 bundle2-input-part: total payload size 168
104 bundle2-input-part: "check:phases" supported
104 bundle2-input-part: "check:phases" supported
105 bundle2-input-part: total payload size 24
105 bundle2-input-part: total payload size 24
106 bundle2-input-part: "check:heads" supported
106 bundle2-input-part: "check:heads" supported
107 bundle2-input-part: total payload size 20
107 bundle2-input-part: total payload size 20
108 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
108 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
109 adding changesets
109 adding changesets
110 add changeset ef1ea85a6374
110 add changeset ef1ea85a6374
111 add changeset f9cafe1212c8
111 add changeset f9cafe1212c8
112 add changeset 911600dab2ae
112 add changeset 911600dab2ae
113 adding manifests
113 adding manifests
114 adding file changes
114 adding file changes
115 adding foo/Bar/file.txt revisions
115 adding foo/Bar/file.txt revisions
116 adding foo/file.txt revisions
116 adding foo/file.txt revisions
117 adding quux/file.py revisions
117 adding quux/file.py revisions
118 added 3 changesets with 3 changes to 3 files
118 added 3 changesets with 3 changes to 3 files
119 bundle2-input-part: total payload size 1553
119 bundle2-input-part: total payload size 1553
120 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
120 bundle2-input-part: "phase-heads" supported
121 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
121 bundle2-input-part: total payload size 24
122 bundle2-input-bundle: 4 parts total
122 bundle2-input-bundle: 4 parts total
123 updating the branch cache
123 updating the branch cache
124 bundle2-output-bundle: "HG20", 2 parts total
124 bundle2-output-bundle: "HG20", 1 parts total
125 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
125 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
126 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
127 bundle2-input-bundle: no-transaction
126 bundle2-input-bundle: no-transaction
128 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
127 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
129 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
128 bundle2-input-bundle: 0 parts total
130 bundle2-input-bundle: 1 parts total
131 listing keys for "phases"
129 listing keys for "phases"
132 repository tip rolled back to revision 0 (undo push)
130 repository tip rolled back to revision 0 (undo push)
133 0:6675d58eff77
131 0:6675d58eff77
134
132
135
133
136 $ echo '[hooks]' >> $config
134 $ echo '[hooks]' >> $config
137 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
135 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
138
136
139 Extension disabled for lack of acl.sources
137 Extension disabled for lack of acl.sources
140
138
141 $ do_push fred
139 $ do_push fred
142 Pushing as user fred
140 Pushing as user fred
143 hgrc = """
141 hgrc = """
144 [hooks]
142 [hooks]
145 pretxnchangegroup.acl = python:hgext.acl.hook
143 pretxnchangegroup.acl = python:hgext.acl.hook
146 """
144 """
147 pushing to ../b
145 pushing to ../b
148 query 1; heads
146 query 1; heads
149 searching for changes
147 searching for changes
150 all remote heads known locally
148 all remote heads known locally
151 listing keys for "phases"
149 listing keys for "phases"
152 checking for updated bookmarks
150 checking for updated bookmarks
153 listing keys for "bookmarks"
151 listing keys for "bookmarks"
154 listing keys for "bookmarks"
152 listing keys for "bookmarks"
155 3 changesets found
153 3 changesets found
156 list of changesets:
154 list of changesets:
157 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
155 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
158 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
156 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
159 911600dab2ae7a9baff75958b84fe606851ce955
157 911600dab2ae7a9baff75958b84fe606851ce955
160 bundle2-output-bundle: "HG20", 5 parts total
158 bundle2-output-bundle: "HG20", 5 parts total
161 bundle2-output-part: "replycaps" 168 bytes payload
159 bundle2-output-part: "replycaps" 168 bytes payload
162 bundle2-output-part: "check:phases" 24 bytes payload
160 bundle2-output-part: "check:phases" 24 bytes payload
163 bundle2-output-part: "check:heads" streamed payload
161 bundle2-output-part: "check:heads" streamed payload
164 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
162 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
165 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
163 bundle2-output-part: "phase-heads" 24 bytes payload
166 bundle2-input-bundle: with-transaction
164 bundle2-input-bundle: with-transaction
167 bundle2-input-part: "replycaps" supported
165 bundle2-input-part: "replycaps" supported
168 bundle2-input-part: total payload size 168
166 bundle2-input-part: total payload size 168
169 bundle2-input-part: "check:phases" supported
167 bundle2-input-part: "check:phases" supported
170 bundle2-input-part: total payload size 24
168 bundle2-input-part: total payload size 24
171 bundle2-input-part: "check:heads" supported
169 bundle2-input-part: "check:heads" supported
172 bundle2-input-part: total payload size 20
170 bundle2-input-part: total payload size 20
173 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
171 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
174 adding changesets
172 adding changesets
175 add changeset ef1ea85a6374
173 add changeset ef1ea85a6374
176 add changeset f9cafe1212c8
174 add changeset f9cafe1212c8
177 add changeset 911600dab2ae
175 add changeset 911600dab2ae
178 adding manifests
176 adding manifests
179 adding file changes
177 adding file changes
180 adding foo/Bar/file.txt revisions
178 adding foo/Bar/file.txt revisions
181 adding foo/file.txt revisions
179 adding foo/file.txt revisions
182 adding quux/file.py revisions
180 adding quux/file.py revisions
183 added 3 changesets with 3 changes to 3 files
181 added 3 changesets with 3 changes to 3 files
184 calling hook pretxnchangegroup.acl: hgext.acl.hook
182 calling hook pretxnchangegroup.acl: hgext.acl.hook
185 acl: changes have source "push" - skipping
183 acl: changes have source "push" - skipping
186 bundle2-input-part: total payload size 1553
184 bundle2-input-part: total payload size 1553
187 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
185 bundle2-input-part: "phase-heads" supported
188 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
186 bundle2-input-part: total payload size 24
189 bundle2-input-bundle: 4 parts total
187 bundle2-input-bundle: 4 parts total
190 updating the branch cache
188 updating the branch cache
191 bundle2-output-bundle: "HG20", 2 parts total
189 bundle2-output-bundle: "HG20", 1 parts total
192 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
190 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
193 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
194 bundle2-input-bundle: no-transaction
191 bundle2-input-bundle: no-transaction
195 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
192 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
196 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
193 bundle2-input-bundle: 0 parts total
197 bundle2-input-bundle: 1 parts total
198 listing keys for "phases"
194 listing keys for "phases"
199 repository tip rolled back to revision 0 (undo push)
195 repository tip rolled back to revision 0 (undo push)
200 0:6675d58eff77
196 0:6675d58eff77
201
197
202
198
203 No [acl.allow]/[acl.deny]
199 No [acl.allow]/[acl.deny]
204
200
205 $ echo '[acl]' >> $config
201 $ echo '[acl]' >> $config
206 $ echo 'sources = push' >> $config
202 $ echo 'sources = push' >> $config
207 $ do_push fred
203 $ do_push fred
208 Pushing as user fred
204 Pushing as user fred
209 hgrc = """
205 hgrc = """
210 [hooks]
206 [hooks]
211 pretxnchangegroup.acl = python:hgext.acl.hook
207 pretxnchangegroup.acl = python:hgext.acl.hook
212 [acl]
208 [acl]
213 sources = push
209 sources = push
214 """
210 """
215 pushing to ../b
211 pushing to ../b
216 query 1; heads
212 query 1; heads
217 searching for changes
213 searching for changes
218 all remote heads known locally
214 all remote heads known locally
219 listing keys for "phases"
215 listing keys for "phases"
220 checking for updated bookmarks
216 checking for updated bookmarks
221 listing keys for "bookmarks"
217 listing keys for "bookmarks"
222 listing keys for "bookmarks"
218 listing keys for "bookmarks"
223 3 changesets found
219 3 changesets found
224 list of changesets:
220 list of changesets:
225 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
221 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
226 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
222 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
227 911600dab2ae7a9baff75958b84fe606851ce955
223 911600dab2ae7a9baff75958b84fe606851ce955
228 bundle2-output-bundle: "HG20", 5 parts total
224 bundle2-output-bundle: "HG20", 5 parts total
229 bundle2-output-part: "replycaps" 168 bytes payload
225 bundle2-output-part: "replycaps" 168 bytes payload
230 bundle2-output-part: "check:phases" 24 bytes payload
226 bundle2-output-part: "check:phases" 24 bytes payload
231 bundle2-output-part: "check:heads" streamed payload
227 bundle2-output-part: "check:heads" streamed payload
232 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
228 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
233 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
229 bundle2-output-part: "phase-heads" 24 bytes payload
234 bundle2-input-bundle: with-transaction
230 bundle2-input-bundle: with-transaction
235 bundle2-input-part: "replycaps" supported
231 bundle2-input-part: "replycaps" supported
236 bundle2-input-part: total payload size 168
232 bundle2-input-part: total payload size 168
237 bundle2-input-part: "check:phases" supported
233 bundle2-input-part: "check:phases" supported
238 bundle2-input-part: total payload size 24
234 bundle2-input-part: total payload size 24
239 bundle2-input-part: "check:heads" supported
235 bundle2-input-part: "check:heads" supported
240 bundle2-input-part: total payload size 20
236 bundle2-input-part: total payload size 20
241 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
237 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
242 adding changesets
238 adding changesets
243 add changeset ef1ea85a6374
239 add changeset ef1ea85a6374
244 add changeset f9cafe1212c8
240 add changeset f9cafe1212c8
245 add changeset 911600dab2ae
241 add changeset 911600dab2ae
246 adding manifests
242 adding manifests
247 adding file changes
243 adding file changes
248 adding foo/Bar/file.txt revisions
244 adding foo/Bar/file.txt revisions
249 adding foo/file.txt revisions
245 adding foo/file.txt revisions
250 adding quux/file.py revisions
246 adding quux/file.py revisions
251 added 3 changesets with 3 changes to 3 files
247 added 3 changesets with 3 changes to 3 files
252 calling hook pretxnchangegroup.acl: hgext.acl.hook
248 calling hook pretxnchangegroup.acl: hgext.acl.hook
253 acl: checking access for user "fred"
249 acl: checking access for user "fred"
254 acl: acl.allow.branches not enabled
250 acl: acl.allow.branches not enabled
255 acl: acl.deny.branches not enabled
251 acl: acl.deny.branches not enabled
256 acl: acl.allow not enabled
252 acl: acl.allow not enabled
257 acl: acl.deny not enabled
253 acl: acl.deny not enabled
258 acl: branch access granted: "ef1ea85a6374" on branch "default"
254 acl: branch access granted: "ef1ea85a6374" on branch "default"
259 acl: path access granted: "ef1ea85a6374"
255 acl: path access granted: "ef1ea85a6374"
260 acl: branch access granted: "f9cafe1212c8" on branch "default"
256 acl: branch access granted: "f9cafe1212c8" on branch "default"
261 acl: path access granted: "f9cafe1212c8"
257 acl: path access granted: "f9cafe1212c8"
262 acl: branch access granted: "911600dab2ae" on branch "default"
258 acl: branch access granted: "911600dab2ae" on branch "default"
263 acl: path access granted: "911600dab2ae"
259 acl: path access granted: "911600dab2ae"
264 bundle2-input-part: total payload size 1553
260 bundle2-input-part: total payload size 1553
265 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
261 bundle2-input-part: "phase-heads" supported
266 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
262 bundle2-input-part: total payload size 24
267 bundle2-input-bundle: 4 parts total
263 bundle2-input-bundle: 4 parts total
268 updating the branch cache
264 updating the branch cache
269 bundle2-output-bundle: "HG20", 2 parts total
265 bundle2-output-bundle: "HG20", 1 parts total
270 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
266 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
271 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
272 bundle2-input-bundle: no-transaction
267 bundle2-input-bundle: no-transaction
273 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
268 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
274 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
269 bundle2-input-bundle: 0 parts total
275 bundle2-input-bundle: 1 parts total
276 listing keys for "phases"
270 listing keys for "phases"
277 repository tip rolled back to revision 0 (undo push)
271 repository tip rolled back to revision 0 (undo push)
278 0:6675d58eff77
272 0:6675d58eff77
279
273
280
274
281 Empty [acl.allow]
275 Empty [acl.allow]
282
276
283 $ echo '[acl.allow]' >> $config
277 $ echo '[acl.allow]' >> $config
284 $ do_push fred
278 $ do_push fred
285 Pushing as user fred
279 Pushing as user fred
286 hgrc = """
280 hgrc = """
287 [hooks]
281 [hooks]
288 pretxnchangegroup.acl = python:hgext.acl.hook
282 pretxnchangegroup.acl = python:hgext.acl.hook
289 [acl]
283 [acl]
290 sources = push
284 sources = push
291 [acl.allow]
285 [acl.allow]
292 """
286 """
293 pushing to ../b
287 pushing to ../b
294 query 1; heads
288 query 1; heads
295 searching for changes
289 searching for changes
296 all remote heads known locally
290 all remote heads known locally
297 listing keys for "phases"
291 listing keys for "phases"
298 checking for updated bookmarks
292 checking for updated bookmarks
299 listing keys for "bookmarks"
293 listing keys for "bookmarks"
300 listing keys for "bookmarks"
294 listing keys for "bookmarks"
301 3 changesets found
295 3 changesets found
302 list of changesets:
296 list of changesets:
303 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
297 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
304 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
298 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
305 911600dab2ae7a9baff75958b84fe606851ce955
299 911600dab2ae7a9baff75958b84fe606851ce955
306 bundle2-output-bundle: "HG20", 5 parts total
300 bundle2-output-bundle: "HG20", 5 parts total
307 bundle2-output-part: "replycaps" 168 bytes payload
301 bundle2-output-part: "replycaps" 168 bytes payload
308 bundle2-output-part: "check:phases" 24 bytes payload
302 bundle2-output-part: "check:phases" 24 bytes payload
309 bundle2-output-part: "check:heads" streamed payload
303 bundle2-output-part: "check:heads" streamed payload
310 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
304 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
311 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
305 bundle2-output-part: "phase-heads" 24 bytes payload
312 bundle2-input-bundle: with-transaction
306 bundle2-input-bundle: with-transaction
313 bundle2-input-part: "replycaps" supported
307 bundle2-input-part: "replycaps" supported
314 bundle2-input-part: total payload size 168
308 bundle2-input-part: total payload size 168
315 bundle2-input-part: "check:phases" supported
309 bundle2-input-part: "check:phases" supported
316 bundle2-input-part: total payload size 24
310 bundle2-input-part: total payload size 24
317 bundle2-input-part: "check:heads" supported
311 bundle2-input-part: "check:heads" supported
318 bundle2-input-part: total payload size 20
312 bundle2-input-part: total payload size 20
319 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
313 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
320 adding changesets
314 adding changesets
321 add changeset ef1ea85a6374
315 add changeset ef1ea85a6374
322 add changeset f9cafe1212c8
316 add changeset f9cafe1212c8
323 add changeset 911600dab2ae
317 add changeset 911600dab2ae
324 adding manifests
318 adding manifests
325 adding file changes
319 adding file changes
326 adding foo/Bar/file.txt revisions
320 adding foo/Bar/file.txt revisions
327 adding foo/file.txt revisions
321 adding foo/file.txt revisions
328 adding quux/file.py revisions
322 adding quux/file.py revisions
329 added 3 changesets with 3 changes to 3 files
323 added 3 changesets with 3 changes to 3 files
330 calling hook pretxnchangegroup.acl: hgext.acl.hook
324 calling hook pretxnchangegroup.acl: hgext.acl.hook
331 acl: checking access for user "fred"
325 acl: checking access for user "fred"
332 acl: acl.allow.branches not enabled
326 acl: acl.allow.branches not enabled
333 acl: acl.deny.branches not enabled
327 acl: acl.deny.branches not enabled
334 acl: acl.allow enabled, 0 entries for user fred
328 acl: acl.allow enabled, 0 entries for user fred
335 acl: acl.deny not enabled
329 acl: acl.deny not enabled
336 acl: branch access granted: "ef1ea85a6374" on branch "default"
330 acl: branch access granted: "ef1ea85a6374" on branch "default"
337 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
331 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
338 bundle2-input-part: total payload size 1553
332 bundle2-input-part: total payload size 1553
333 bundle2-input-part: total payload size 24
339 bundle2-input-bundle: 4 parts total
334 bundle2-input-bundle: 4 parts total
340 transaction abort!
335 transaction abort!
341 rollback completed
336 rollback completed
342 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
337 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
343 no rollback information available
338 no rollback information available
344 0:6675d58eff77
339 0:6675d58eff77
345
340
346
341
347 fred is allowed inside foo/
342 fred is allowed inside foo/
348
343
349 $ echo 'foo/** = fred' >> $config
344 $ echo 'foo/** = fred' >> $config
350 $ do_push fred
345 $ do_push fred
351 Pushing as user fred
346 Pushing as user fred
352 hgrc = """
347 hgrc = """
353 [hooks]
348 [hooks]
354 pretxnchangegroup.acl = python:hgext.acl.hook
349 pretxnchangegroup.acl = python:hgext.acl.hook
355 [acl]
350 [acl]
356 sources = push
351 sources = push
357 [acl.allow]
352 [acl.allow]
358 foo/** = fred
353 foo/** = fred
359 """
354 """
360 pushing to ../b
355 pushing to ../b
361 query 1; heads
356 query 1; heads
362 searching for changes
357 searching for changes
363 all remote heads known locally
358 all remote heads known locally
364 listing keys for "phases"
359 listing keys for "phases"
365 checking for updated bookmarks
360 checking for updated bookmarks
366 listing keys for "bookmarks"
361 listing keys for "bookmarks"
367 listing keys for "bookmarks"
362 listing keys for "bookmarks"
368 3 changesets found
363 3 changesets found
369 list of changesets:
364 list of changesets:
370 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
365 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
371 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
366 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
372 911600dab2ae7a9baff75958b84fe606851ce955
367 911600dab2ae7a9baff75958b84fe606851ce955
373 bundle2-output-bundle: "HG20", 5 parts total
368 bundle2-output-bundle: "HG20", 5 parts total
374 bundle2-output-part: "replycaps" 168 bytes payload
369 bundle2-output-part: "replycaps" 168 bytes payload
375 bundle2-output-part: "check:phases" 24 bytes payload
370 bundle2-output-part: "check:phases" 24 bytes payload
376 bundle2-output-part: "check:heads" streamed payload
371 bundle2-output-part: "check:heads" streamed payload
377 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
372 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
378 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
373 bundle2-output-part: "phase-heads" 24 bytes payload
379 bundle2-input-bundle: with-transaction
374 bundle2-input-bundle: with-transaction
380 bundle2-input-part: "replycaps" supported
375 bundle2-input-part: "replycaps" supported
381 bundle2-input-part: total payload size 168
376 bundle2-input-part: total payload size 168
382 bundle2-input-part: "check:phases" supported
377 bundle2-input-part: "check:phases" supported
383 bundle2-input-part: total payload size 24
378 bundle2-input-part: total payload size 24
384 bundle2-input-part: "check:heads" supported
379 bundle2-input-part: "check:heads" supported
385 bundle2-input-part: total payload size 20
380 bundle2-input-part: total payload size 20
386 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
381 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
387 adding changesets
382 adding changesets
388 add changeset ef1ea85a6374
383 add changeset ef1ea85a6374
389 add changeset f9cafe1212c8
384 add changeset f9cafe1212c8
390 add changeset 911600dab2ae
385 add changeset 911600dab2ae
391 adding manifests
386 adding manifests
392 adding file changes
387 adding file changes
393 adding foo/Bar/file.txt revisions
388 adding foo/Bar/file.txt revisions
394 adding foo/file.txt revisions
389 adding foo/file.txt revisions
395 adding quux/file.py revisions
390 adding quux/file.py revisions
396 added 3 changesets with 3 changes to 3 files
391 added 3 changesets with 3 changes to 3 files
397 calling hook pretxnchangegroup.acl: hgext.acl.hook
392 calling hook pretxnchangegroup.acl: hgext.acl.hook
398 acl: checking access for user "fred"
393 acl: checking access for user "fred"
399 acl: acl.allow.branches not enabled
394 acl: acl.allow.branches not enabled
400 acl: acl.deny.branches not enabled
395 acl: acl.deny.branches not enabled
401 acl: acl.allow enabled, 1 entries for user fred
396 acl: acl.allow enabled, 1 entries for user fred
402 acl: acl.deny not enabled
397 acl: acl.deny not enabled
403 acl: branch access granted: "ef1ea85a6374" on branch "default"
398 acl: branch access granted: "ef1ea85a6374" on branch "default"
404 acl: path access granted: "ef1ea85a6374"
399 acl: path access granted: "ef1ea85a6374"
405 acl: branch access granted: "f9cafe1212c8" on branch "default"
400 acl: branch access granted: "f9cafe1212c8" on branch "default"
406 acl: path access granted: "f9cafe1212c8"
401 acl: path access granted: "f9cafe1212c8"
407 acl: branch access granted: "911600dab2ae" on branch "default"
402 acl: branch access granted: "911600dab2ae" on branch "default"
408 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
403 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
409 bundle2-input-part: total payload size 1553
404 bundle2-input-part: total payload size 1553
405 bundle2-input-part: total payload size 24
410 bundle2-input-bundle: 4 parts total
406 bundle2-input-bundle: 4 parts total
411 transaction abort!
407 transaction abort!
412 rollback completed
408 rollback completed
413 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
409 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
414 no rollback information available
410 no rollback information available
415 0:6675d58eff77
411 0:6675d58eff77
416
412
417
413
418 Empty [acl.deny]
414 Empty [acl.deny]
419
415
420 $ echo '[acl.deny]' >> $config
416 $ echo '[acl.deny]' >> $config
421 $ do_push barney
417 $ do_push barney
422 Pushing as user barney
418 Pushing as user barney
423 hgrc = """
419 hgrc = """
424 [hooks]
420 [hooks]
425 pretxnchangegroup.acl = python:hgext.acl.hook
421 pretxnchangegroup.acl = python:hgext.acl.hook
426 [acl]
422 [acl]
427 sources = push
423 sources = push
428 [acl.allow]
424 [acl.allow]
429 foo/** = fred
425 foo/** = fred
430 [acl.deny]
426 [acl.deny]
431 """
427 """
432 pushing to ../b
428 pushing to ../b
433 query 1; heads
429 query 1; heads
434 searching for changes
430 searching for changes
435 all remote heads known locally
431 all remote heads known locally
436 listing keys for "phases"
432 listing keys for "phases"
437 checking for updated bookmarks
433 checking for updated bookmarks
438 listing keys for "bookmarks"
434 listing keys for "bookmarks"
439 listing keys for "bookmarks"
435 listing keys for "bookmarks"
440 3 changesets found
436 3 changesets found
441 list of changesets:
437 list of changesets:
442 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
438 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
443 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
439 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
444 911600dab2ae7a9baff75958b84fe606851ce955
440 911600dab2ae7a9baff75958b84fe606851ce955
445 bundle2-output-bundle: "HG20", 5 parts total
441 bundle2-output-bundle: "HG20", 5 parts total
446 bundle2-output-part: "replycaps" 168 bytes payload
442 bundle2-output-part: "replycaps" 168 bytes payload
447 bundle2-output-part: "check:phases" 24 bytes payload
443 bundle2-output-part: "check:phases" 24 bytes payload
448 bundle2-output-part: "check:heads" streamed payload
444 bundle2-output-part: "check:heads" streamed payload
449 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
445 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
450 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
446 bundle2-output-part: "phase-heads" 24 bytes payload
451 bundle2-input-bundle: with-transaction
447 bundle2-input-bundle: with-transaction
452 bundle2-input-part: "replycaps" supported
448 bundle2-input-part: "replycaps" supported
453 bundle2-input-part: total payload size 168
449 bundle2-input-part: total payload size 168
454 bundle2-input-part: "check:phases" supported
450 bundle2-input-part: "check:phases" supported
455 bundle2-input-part: total payload size 24
451 bundle2-input-part: total payload size 24
456 bundle2-input-part: "check:heads" supported
452 bundle2-input-part: "check:heads" supported
457 bundle2-input-part: total payload size 20
453 bundle2-input-part: total payload size 20
458 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
454 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
459 adding changesets
455 adding changesets
460 add changeset ef1ea85a6374
456 add changeset ef1ea85a6374
461 add changeset f9cafe1212c8
457 add changeset f9cafe1212c8
462 add changeset 911600dab2ae
458 add changeset 911600dab2ae
463 adding manifests
459 adding manifests
464 adding file changes
460 adding file changes
465 adding foo/Bar/file.txt revisions
461 adding foo/Bar/file.txt revisions
466 adding foo/file.txt revisions
462 adding foo/file.txt revisions
467 adding quux/file.py revisions
463 adding quux/file.py revisions
468 added 3 changesets with 3 changes to 3 files
464 added 3 changesets with 3 changes to 3 files
469 calling hook pretxnchangegroup.acl: hgext.acl.hook
465 calling hook pretxnchangegroup.acl: hgext.acl.hook
470 acl: checking access for user "barney"
466 acl: checking access for user "barney"
471 acl: acl.allow.branches not enabled
467 acl: acl.allow.branches not enabled
472 acl: acl.deny.branches not enabled
468 acl: acl.deny.branches not enabled
473 acl: acl.allow enabled, 0 entries for user barney
469 acl: acl.allow enabled, 0 entries for user barney
474 acl: acl.deny enabled, 0 entries for user barney
470 acl: acl.deny enabled, 0 entries for user barney
475 acl: branch access granted: "ef1ea85a6374" on branch "default"
471 acl: branch access granted: "ef1ea85a6374" on branch "default"
476 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
472 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
477 bundle2-input-part: total payload size 1553
473 bundle2-input-part: total payload size 1553
474 bundle2-input-part: total payload size 24
478 bundle2-input-bundle: 4 parts total
475 bundle2-input-bundle: 4 parts total
479 transaction abort!
476 transaction abort!
480 rollback completed
477 rollback completed
481 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
478 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
482 no rollback information available
479 no rollback information available
483 0:6675d58eff77
480 0:6675d58eff77
484
481
485
482
486 fred is allowed inside foo/, but not foo/bar/ (case matters)
483 fred is allowed inside foo/, but not foo/bar/ (case matters)
487
484
488 $ echo 'foo/bar/** = fred' >> $config
485 $ echo 'foo/bar/** = fred' >> $config
489 $ do_push fred
486 $ do_push fred
490 Pushing as user fred
487 Pushing as user fred
491 hgrc = """
488 hgrc = """
492 [hooks]
489 [hooks]
493 pretxnchangegroup.acl = python:hgext.acl.hook
490 pretxnchangegroup.acl = python:hgext.acl.hook
494 [acl]
491 [acl]
495 sources = push
492 sources = push
496 [acl.allow]
493 [acl.allow]
497 foo/** = fred
494 foo/** = fred
498 [acl.deny]
495 [acl.deny]
499 foo/bar/** = fred
496 foo/bar/** = fred
500 """
497 """
501 pushing to ../b
498 pushing to ../b
502 query 1; heads
499 query 1; heads
503 searching for changes
500 searching for changes
504 all remote heads known locally
501 all remote heads known locally
505 listing keys for "phases"
502 listing keys for "phases"
506 checking for updated bookmarks
503 checking for updated bookmarks
507 listing keys for "bookmarks"
504 listing keys for "bookmarks"
508 listing keys for "bookmarks"
505 listing keys for "bookmarks"
509 3 changesets found
506 3 changesets found
510 list of changesets:
507 list of changesets:
511 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
512 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
513 911600dab2ae7a9baff75958b84fe606851ce955
510 911600dab2ae7a9baff75958b84fe606851ce955
514 bundle2-output-bundle: "HG20", 5 parts total
511 bundle2-output-bundle: "HG20", 5 parts total
515 bundle2-output-part: "replycaps" 168 bytes payload
512 bundle2-output-part: "replycaps" 168 bytes payload
516 bundle2-output-part: "check:phases" 24 bytes payload
513 bundle2-output-part: "check:phases" 24 bytes payload
517 bundle2-output-part: "check:heads" streamed payload
514 bundle2-output-part: "check:heads" streamed payload
518 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
515 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
519 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
516 bundle2-output-part: "phase-heads" 24 bytes payload
520 bundle2-input-bundle: with-transaction
517 bundle2-input-bundle: with-transaction
521 bundle2-input-part: "replycaps" supported
518 bundle2-input-part: "replycaps" supported
522 bundle2-input-part: total payload size 168
519 bundle2-input-part: total payload size 168
523 bundle2-input-part: "check:phases" supported
520 bundle2-input-part: "check:phases" supported
524 bundle2-input-part: total payload size 24
521 bundle2-input-part: total payload size 24
525 bundle2-input-part: "check:heads" supported
522 bundle2-input-part: "check:heads" supported
526 bundle2-input-part: total payload size 20
523 bundle2-input-part: total payload size 20
527 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
524 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
528 adding changesets
525 adding changesets
529 add changeset ef1ea85a6374
526 add changeset ef1ea85a6374
530 add changeset f9cafe1212c8
527 add changeset f9cafe1212c8
531 add changeset 911600dab2ae
528 add changeset 911600dab2ae
532 adding manifests
529 adding manifests
533 adding file changes
530 adding file changes
534 adding foo/Bar/file.txt revisions
531 adding foo/Bar/file.txt revisions
535 adding foo/file.txt revisions
532 adding foo/file.txt revisions
536 adding quux/file.py revisions
533 adding quux/file.py revisions
537 added 3 changesets with 3 changes to 3 files
534 added 3 changesets with 3 changes to 3 files
538 calling hook pretxnchangegroup.acl: hgext.acl.hook
535 calling hook pretxnchangegroup.acl: hgext.acl.hook
539 acl: checking access for user "fred"
536 acl: checking access for user "fred"
540 acl: acl.allow.branches not enabled
537 acl: acl.allow.branches not enabled
541 acl: acl.deny.branches not enabled
538 acl: acl.deny.branches not enabled
542 acl: acl.allow enabled, 1 entries for user fred
539 acl: acl.allow enabled, 1 entries for user fred
543 acl: acl.deny enabled, 1 entries for user fred
540 acl: acl.deny enabled, 1 entries for user fred
544 acl: branch access granted: "ef1ea85a6374" on branch "default"
541 acl: branch access granted: "ef1ea85a6374" on branch "default"
545 acl: path access granted: "ef1ea85a6374"
542 acl: path access granted: "ef1ea85a6374"
546 acl: branch access granted: "f9cafe1212c8" on branch "default"
543 acl: branch access granted: "f9cafe1212c8" on branch "default"
547 acl: path access granted: "f9cafe1212c8"
544 acl: path access granted: "f9cafe1212c8"
548 acl: branch access granted: "911600dab2ae" on branch "default"
545 acl: branch access granted: "911600dab2ae" on branch "default"
549 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
546 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
550 bundle2-input-part: total payload size 1553
547 bundle2-input-part: total payload size 1553
548 bundle2-input-part: total payload size 24
551 bundle2-input-bundle: 4 parts total
549 bundle2-input-bundle: 4 parts total
552 transaction abort!
550 transaction abort!
553 rollback completed
551 rollback completed
554 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
552 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
555 no rollback information available
553 no rollback information available
556 0:6675d58eff77
554 0:6675d58eff77
557
555
558
556
559 fred is allowed inside foo/, but not foo/Bar/
557 fred is allowed inside foo/, but not foo/Bar/
560
558
561 $ echo 'foo/Bar/** = fred' >> $config
559 $ echo 'foo/Bar/** = fred' >> $config
562 $ do_push fred
560 $ do_push fred
563 Pushing as user fred
561 Pushing as user fred
564 hgrc = """
562 hgrc = """
565 [hooks]
563 [hooks]
566 pretxnchangegroup.acl = python:hgext.acl.hook
564 pretxnchangegroup.acl = python:hgext.acl.hook
567 [acl]
565 [acl]
568 sources = push
566 sources = push
569 [acl.allow]
567 [acl.allow]
570 foo/** = fred
568 foo/** = fred
571 [acl.deny]
569 [acl.deny]
572 foo/bar/** = fred
570 foo/bar/** = fred
573 foo/Bar/** = fred
571 foo/Bar/** = fred
574 """
572 """
575 pushing to ../b
573 pushing to ../b
576 query 1; heads
574 query 1; heads
577 searching for changes
575 searching for changes
578 all remote heads known locally
576 all remote heads known locally
579 listing keys for "phases"
577 listing keys for "phases"
580 checking for updated bookmarks
578 checking for updated bookmarks
581 listing keys for "bookmarks"
579 listing keys for "bookmarks"
582 listing keys for "bookmarks"
580 listing keys for "bookmarks"
583 3 changesets found
581 3 changesets found
584 list of changesets:
582 list of changesets:
585 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
583 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
586 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
584 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
587 911600dab2ae7a9baff75958b84fe606851ce955
585 911600dab2ae7a9baff75958b84fe606851ce955
588 bundle2-output-bundle: "HG20", 5 parts total
586 bundle2-output-bundle: "HG20", 5 parts total
589 bundle2-output-part: "replycaps" 168 bytes payload
587 bundle2-output-part: "replycaps" 168 bytes payload
590 bundle2-output-part: "check:phases" 24 bytes payload
588 bundle2-output-part: "check:phases" 24 bytes payload
591 bundle2-output-part: "check:heads" streamed payload
589 bundle2-output-part: "check:heads" streamed payload
592 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
590 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
593 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
591 bundle2-output-part: "phase-heads" 24 bytes payload
594 bundle2-input-bundle: with-transaction
592 bundle2-input-bundle: with-transaction
595 bundle2-input-part: "replycaps" supported
593 bundle2-input-part: "replycaps" supported
596 bundle2-input-part: total payload size 168
594 bundle2-input-part: total payload size 168
597 bundle2-input-part: "check:phases" supported
595 bundle2-input-part: "check:phases" supported
598 bundle2-input-part: total payload size 24
596 bundle2-input-part: total payload size 24
599 bundle2-input-part: "check:heads" supported
597 bundle2-input-part: "check:heads" supported
600 bundle2-input-part: total payload size 20
598 bundle2-input-part: total payload size 20
601 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
599 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
602 adding changesets
600 adding changesets
603 add changeset ef1ea85a6374
601 add changeset ef1ea85a6374
604 add changeset f9cafe1212c8
602 add changeset f9cafe1212c8
605 add changeset 911600dab2ae
603 add changeset 911600dab2ae
606 adding manifests
604 adding manifests
607 adding file changes
605 adding file changes
608 adding foo/Bar/file.txt revisions
606 adding foo/Bar/file.txt revisions
609 adding foo/file.txt revisions
607 adding foo/file.txt revisions
610 adding quux/file.py revisions
608 adding quux/file.py revisions
611 added 3 changesets with 3 changes to 3 files
609 added 3 changesets with 3 changes to 3 files
612 calling hook pretxnchangegroup.acl: hgext.acl.hook
610 calling hook pretxnchangegroup.acl: hgext.acl.hook
613 acl: checking access for user "fred"
611 acl: checking access for user "fred"
614 acl: acl.allow.branches not enabled
612 acl: acl.allow.branches not enabled
615 acl: acl.deny.branches not enabled
613 acl: acl.deny.branches not enabled
616 acl: acl.allow enabled, 1 entries for user fred
614 acl: acl.allow enabled, 1 entries for user fred
617 acl: acl.deny enabled, 2 entries for user fred
615 acl: acl.deny enabled, 2 entries for user fred
618 acl: branch access granted: "ef1ea85a6374" on branch "default"
616 acl: branch access granted: "ef1ea85a6374" on branch "default"
619 acl: path access granted: "ef1ea85a6374"
617 acl: path access granted: "ef1ea85a6374"
620 acl: branch access granted: "f9cafe1212c8" on branch "default"
618 acl: branch access granted: "f9cafe1212c8" on branch "default"
621 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
619 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
622 bundle2-input-part: total payload size 1553
620 bundle2-input-part: total payload size 1553
621 bundle2-input-part: total payload size 24
623 bundle2-input-bundle: 4 parts total
622 bundle2-input-bundle: 4 parts total
624 transaction abort!
623 transaction abort!
625 rollback completed
624 rollback completed
626 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
625 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
627 no rollback information available
626 no rollback information available
628 0:6675d58eff77
627 0:6675d58eff77
629
628
630
629
631 $ echo 'barney is not mentioned => not allowed anywhere'
630 $ echo 'barney is not mentioned => not allowed anywhere'
632 barney is not mentioned => not allowed anywhere
631 barney is not mentioned => not allowed anywhere
633 $ do_push barney
632 $ do_push barney
634 Pushing as user barney
633 Pushing as user barney
635 hgrc = """
634 hgrc = """
636 [hooks]
635 [hooks]
637 pretxnchangegroup.acl = python:hgext.acl.hook
636 pretxnchangegroup.acl = python:hgext.acl.hook
638 [acl]
637 [acl]
639 sources = push
638 sources = push
640 [acl.allow]
639 [acl.allow]
641 foo/** = fred
640 foo/** = fred
642 [acl.deny]
641 [acl.deny]
643 foo/bar/** = fred
642 foo/bar/** = fred
644 foo/Bar/** = fred
643 foo/Bar/** = fred
645 """
644 """
646 pushing to ../b
645 pushing to ../b
647 query 1; heads
646 query 1; heads
648 searching for changes
647 searching for changes
649 all remote heads known locally
648 all remote heads known locally
650 listing keys for "phases"
649 listing keys for "phases"
651 checking for updated bookmarks
650 checking for updated bookmarks
652 listing keys for "bookmarks"
651 listing keys for "bookmarks"
653 listing keys for "bookmarks"
652 listing keys for "bookmarks"
654 3 changesets found
653 3 changesets found
655 list of changesets:
654 list of changesets:
656 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
655 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
657 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
656 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
658 911600dab2ae7a9baff75958b84fe606851ce955
657 911600dab2ae7a9baff75958b84fe606851ce955
659 bundle2-output-bundle: "HG20", 5 parts total
658 bundle2-output-bundle: "HG20", 5 parts total
660 bundle2-output-part: "replycaps" 168 bytes payload
659 bundle2-output-part: "replycaps" 168 bytes payload
661 bundle2-output-part: "check:phases" 24 bytes payload
660 bundle2-output-part: "check:phases" 24 bytes payload
662 bundle2-output-part: "check:heads" streamed payload
661 bundle2-output-part: "check:heads" streamed payload
663 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
662 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
664 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
663 bundle2-output-part: "phase-heads" 24 bytes payload
665 bundle2-input-bundle: with-transaction
664 bundle2-input-bundle: with-transaction
666 bundle2-input-part: "replycaps" supported
665 bundle2-input-part: "replycaps" supported
667 bundle2-input-part: total payload size 168
666 bundle2-input-part: total payload size 168
668 bundle2-input-part: "check:phases" supported
667 bundle2-input-part: "check:phases" supported
669 bundle2-input-part: total payload size 24
668 bundle2-input-part: total payload size 24
670 bundle2-input-part: "check:heads" supported
669 bundle2-input-part: "check:heads" supported
671 bundle2-input-part: total payload size 20
670 bundle2-input-part: total payload size 20
672 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
671 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
673 adding changesets
672 adding changesets
674 add changeset ef1ea85a6374
673 add changeset ef1ea85a6374
675 add changeset f9cafe1212c8
674 add changeset f9cafe1212c8
676 add changeset 911600dab2ae
675 add changeset 911600dab2ae
677 adding manifests
676 adding manifests
678 adding file changes
677 adding file changes
679 adding foo/Bar/file.txt revisions
678 adding foo/Bar/file.txt revisions
680 adding foo/file.txt revisions
679 adding foo/file.txt revisions
681 adding quux/file.py revisions
680 adding quux/file.py revisions
682 added 3 changesets with 3 changes to 3 files
681 added 3 changesets with 3 changes to 3 files
683 calling hook pretxnchangegroup.acl: hgext.acl.hook
682 calling hook pretxnchangegroup.acl: hgext.acl.hook
684 acl: checking access for user "barney"
683 acl: checking access for user "barney"
685 acl: acl.allow.branches not enabled
684 acl: acl.allow.branches not enabled
686 acl: acl.deny.branches not enabled
685 acl: acl.deny.branches not enabled
687 acl: acl.allow enabled, 0 entries for user barney
686 acl: acl.allow enabled, 0 entries for user barney
688 acl: acl.deny enabled, 0 entries for user barney
687 acl: acl.deny enabled, 0 entries for user barney
689 acl: branch access granted: "ef1ea85a6374" on branch "default"
688 acl: branch access granted: "ef1ea85a6374" on branch "default"
690 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
689 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
691 bundle2-input-part: total payload size 1553
690 bundle2-input-part: total payload size 1553
691 bundle2-input-part: total payload size 24
692 bundle2-input-bundle: 4 parts total
692 bundle2-input-bundle: 4 parts total
693 transaction abort!
693 transaction abort!
694 rollback completed
694 rollback completed
695 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
695 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
696 no rollback information available
696 no rollback information available
697 0:6675d58eff77
697 0:6675d58eff77
698
698
699
699
700 barney is allowed everywhere
700 barney is allowed everywhere
701
701
702 $ echo '[acl.allow]' >> $config
702 $ echo '[acl.allow]' >> $config
703 $ echo '** = barney' >> $config
703 $ echo '** = barney' >> $config
704 $ do_push barney
704 $ do_push barney
705 Pushing as user barney
705 Pushing as user barney
706 hgrc = """
706 hgrc = """
707 [hooks]
707 [hooks]
708 pretxnchangegroup.acl = python:hgext.acl.hook
708 pretxnchangegroup.acl = python:hgext.acl.hook
709 [acl]
709 [acl]
710 sources = push
710 sources = push
711 [acl.allow]
711 [acl.allow]
712 foo/** = fred
712 foo/** = fred
713 [acl.deny]
713 [acl.deny]
714 foo/bar/** = fred
714 foo/bar/** = fred
715 foo/Bar/** = fred
715 foo/Bar/** = fred
716 [acl.allow]
716 [acl.allow]
717 ** = barney
717 ** = barney
718 """
718 """
719 pushing to ../b
719 pushing to ../b
720 query 1; heads
720 query 1; heads
721 searching for changes
721 searching for changes
722 all remote heads known locally
722 all remote heads known locally
723 listing keys for "phases"
723 listing keys for "phases"
724 checking for updated bookmarks
724 checking for updated bookmarks
725 listing keys for "bookmarks"
725 listing keys for "bookmarks"
726 listing keys for "bookmarks"
726 listing keys for "bookmarks"
727 3 changesets found
727 3 changesets found
728 list of changesets:
728 list of changesets:
729 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
729 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
730 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
730 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
731 911600dab2ae7a9baff75958b84fe606851ce955
731 911600dab2ae7a9baff75958b84fe606851ce955
732 bundle2-output-bundle: "HG20", 5 parts total
732 bundle2-output-bundle: "HG20", 5 parts total
733 bundle2-output-part: "replycaps" 168 bytes payload
733 bundle2-output-part: "replycaps" 168 bytes payload
734 bundle2-output-part: "check:phases" 24 bytes payload
734 bundle2-output-part: "check:phases" 24 bytes payload
735 bundle2-output-part: "check:heads" streamed payload
735 bundle2-output-part: "check:heads" streamed payload
736 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
736 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
737 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
737 bundle2-output-part: "phase-heads" 24 bytes payload
738 bundle2-input-bundle: with-transaction
738 bundle2-input-bundle: with-transaction
739 bundle2-input-part: "replycaps" supported
739 bundle2-input-part: "replycaps" supported
740 bundle2-input-part: total payload size 168
740 bundle2-input-part: total payload size 168
741 bundle2-input-part: "check:phases" supported
741 bundle2-input-part: "check:phases" supported
742 bundle2-input-part: total payload size 24
742 bundle2-input-part: total payload size 24
743 bundle2-input-part: "check:heads" supported
743 bundle2-input-part: "check:heads" supported
744 bundle2-input-part: total payload size 20
744 bundle2-input-part: total payload size 20
745 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
745 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
746 adding changesets
746 adding changesets
747 add changeset ef1ea85a6374
747 add changeset ef1ea85a6374
748 add changeset f9cafe1212c8
748 add changeset f9cafe1212c8
749 add changeset 911600dab2ae
749 add changeset 911600dab2ae
750 adding manifests
750 adding manifests
751 adding file changes
751 adding file changes
752 adding foo/Bar/file.txt revisions
752 adding foo/Bar/file.txt revisions
753 adding foo/file.txt revisions
753 adding foo/file.txt revisions
754 adding quux/file.py revisions
754 adding quux/file.py revisions
755 added 3 changesets with 3 changes to 3 files
755 added 3 changesets with 3 changes to 3 files
756 calling hook pretxnchangegroup.acl: hgext.acl.hook
756 calling hook pretxnchangegroup.acl: hgext.acl.hook
757 acl: checking access for user "barney"
757 acl: checking access for user "barney"
758 acl: acl.allow.branches not enabled
758 acl: acl.allow.branches not enabled
759 acl: acl.deny.branches not enabled
759 acl: acl.deny.branches not enabled
760 acl: acl.allow enabled, 1 entries for user barney
760 acl: acl.allow enabled, 1 entries for user barney
761 acl: acl.deny enabled, 0 entries for user barney
761 acl: acl.deny enabled, 0 entries for user barney
762 acl: branch access granted: "ef1ea85a6374" on branch "default"
762 acl: branch access granted: "ef1ea85a6374" on branch "default"
763 acl: path access granted: "ef1ea85a6374"
763 acl: path access granted: "ef1ea85a6374"
764 acl: branch access granted: "f9cafe1212c8" on branch "default"
764 acl: branch access granted: "f9cafe1212c8" on branch "default"
765 acl: path access granted: "f9cafe1212c8"
765 acl: path access granted: "f9cafe1212c8"
766 acl: branch access granted: "911600dab2ae" on branch "default"
766 acl: branch access granted: "911600dab2ae" on branch "default"
767 acl: path access granted: "911600dab2ae"
767 acl: path access granted: "911600dab2ae"
768 bundle2-input-part: total payload size 1553
768 bundle2-input-part: total payload size 1553
769 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
769 bundle2-input-part: "phase-heads" supported
770 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
770 bundle2-input-part: total payload size 24
771 bundle2-input-bundle: 4 parts total
771 bundle2-input-bundle: 4 parts total
772 updating the branch cache
772 updating the branch cache
773 bundle2-output-bundle: "HG20", 2 parts total
773 bundle2-output-bundle: "HG20", 1 parts total
774 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
774 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
775 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
776 bundle2-input-bundle: no-transaction
775 bundle2-input-bundle: no-transaction
777 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
776 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
778 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
777 bundle2-input-bundle: 0 parts total
779 bundle2-input-bundle: 1 parts total
780 listing keys for "phases"
778 listing keys for "phases"
781 repository tip rolled back to revision 0 (undo push)
779 repository tip rolled back to revision 0 (undo push)
782 0:6675d58eff77
780 0:6675d58eff77
783
781
784
782
785 wilma can change files with a .txt extension
783 wilma can change files with a .txt extension
786
784
787 $ echo '**/*.txt = wilma' >> $config
785 $ echo '**/*.txt = wilma' >> $config
788 $ do_push wilma
786 $ do_push wilma
789 Pushing as user wilma
787 Pushing as user wilma
790 hgrc = """
788 hgrc = """
791 [hooks]
789 [hooks]
792 pretxnchangegroup.acl = python:hgext.acl.hook
790 pretxnchangegroup.acl = python:hgext.acl.hook
793 [acl]
791 [acl]
794 sources = push
792 sources = push
795 [acl.allow]
793 [acl.allow]
796 foo/** = fred
794 foo/** = fred
797 [acl.deny]
795 [acl.deny]
798 foo/bar/** = fred
796 foo/bar/** = fred
799 foo/Bar/** = fred
797 foo/Bar/** = fred
800 [acl.allow]
798 [acl.allow]
801 ** = barney
799 ** = barney
802 **/*.txt = wilma
800 **/*.txt = wilma
803 """
801 """
804 pushing to ../b
802 pushing to ../b
805 query 1; heads
803 query 1; heads
806 searching for changes
804 searching for changes
807 all remote heads known locally
805 all remote heads known locally
808 listing keys for "phases"
806 listing keys for "phases"
809 checking for updated bookmarks
807 checking for updated bookmarks
810 listing keys for "bookmarks"
808 listing keys for "bookmarks"
811 listing keys for "bookmarks"
809 listing keys for "bookmarks"
812 3 changesets found
810 3 changesets found
813 list of changesets:
811 list of changesets:
814 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
812 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
815 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
813 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
816 911600dab2ae7a9baff75958b84fe606851ce955
814 911600dab2ae7a9baff75958b84fe606851ce955
817 bundle2-output-bundle: "HG20", 5 parts total
815 bundle2-output-bundle: "HG20", 5 parts total
818 bundle2-output-part: "replycaps" 168 bytes payload
816 bundle2-output-part: "replycaps" 168 bytes payload
819 bundle2-output-part: "check:phases" 24 bytes payload
817 bundle2-output-part: "check:phases" 24 bytes payload
820 bundle2-output-part: "check:heads" streamed payload
818 bundle2-output-part: "check:heads" streamed payload
821 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
819 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
822 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
820 bundle2-output-part: "phase-heads" 24 bytes payload
823 bundle2-input-bundle: with-transaction
821 bundle2-input-bundle: with-transaction
824 bundle2-input-part: "replycaps" supported
822 bundle2-input-part: "replycaps" supported
825 bundle2-input-part: total payload size 168
823 bundle2-input-part: total payload size 168
826 bundle2-input-part: "check:phases" supported
824 bundle2-input-part: "check:phases" supported
827 bundle2-input-part: total payload size 24
825 bundle2-input-part: total payload size 24
828 bundle2-input-part: "check:heads" supported
826 bundle2-input-part: "check:heads" supported
829 bundle2-input-part: total payload size 20
827 bundle2-input-part: total payload size 20
830 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
828 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
831 adding changesets
829 adding changesets
832 add changeset ef1ea85a6374
830 add changeset ef1ea85a6374
833 add changeset f9cafe1212c8
831 add changeset f9cafe1212c8
834 add changeset 911600dab2ae
832 add changeset 911600dab2ae
835 adding manifests
833 adding manifests
836 adding file changes
834 adding file changes
837 adding foo/Bar/file.txt revisions
835 adding foo/Bar/file.txt revisions
838 adding foo/file.txt revisions
836 adding foo/file.txt revisions
839 adding quux/file.py revisions
837 adding quux/file.py revisions
840 added 3 changesets with 3 changes to 3 files
838 added 3 changesets with 3 changes to 3 files
841 calling hook pretxnchangegroup.acl: hgext.acl.hook
839 calling hook pretxnchangegroup.acl: hgext.acl.hook
842 acl: checking access for user "wilma"
840 acl: checking access for user "wilma"
843 acl: acl.allow.branches not enabled
841 acl: acl.allow.branches not enabled
844 acl: acl.deny.branches not enabled
842 acl: acl.deny.branches not enabled
845 acl: acl.allow enabled, 1 entries for user wilma
843 acl: acl.allow enabled, 1 entries for user wilma
846 acl: acl.deny enabled, 0 entries for user wilma
844 acl: acl.deny enabled, 0 entries for user wilma
847 acl: branch access granted: "ef1ea85a6374" on branch "default"
845 acl: branch access granted: "ef1ea85a6374" on branch "default"
848 acl: path access granted: "ef1ea85a6374"
846 acl: path access granted: "ef1ea85a6374"
849 acl: branch access granted: "f9cafe1212c8" on branch "default"
847 acl: branch access granted: "f9cafe1212c8" on branch "default"
850 acl: path access granted: "f9cafe1212c8"
848 acl: path access granted: "f9cafe1212c8"
851 acl: branch access granted: "911600dab2ae" on branch "default"
849 acl: branch access granted: "911600dab2ae" on branch "default"
852 error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
850 error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
853 bundle2-input-part: total payload size 1553
851 bundle2-input-part: total payload size 1553
852 bundle2-input-part: total payload size 24
854 bundle2-input-bundle: 4 parts total
853 bundle2-input-bundle: 4 parts total
855 transaction abort!
854 transaction abort!
856 rollback completed
855 rollback completed
857 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
856 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
858 no rollback information available
857 no rollback information available
859 0:6675d58eff77
858 0:6675d58eff77
860
859
861
860
862 file specified by acl.config does not exist
861 file specified by acl.config does not exist
863
862
864 $ echo '[acl]' >> $config
863 $ echo '[acl]' >> $config
865 $ echo 'config = ../acl.config' >> $config
864 $ echo 'config = ../acl.config' >> $config
866 $ do_push barney
865 $ do_push barney
867 Pushing as user barney
866 Pushing as user barney
868 hgrc = """
867 hgrc = """
869 [hooks]
868 [hooks]
870 pretxnchangegroup.acl = python:hgext.acl.hook
869 pretxnchangegroup.acl = python:hgext.acl.hook
871 [acl]
870 [acl]
872 sources = push
871 sources = push
873 [acl.allow]
872 [acl.allow]
874 foo/** = fred
873 foo/** = fred
875 [acl.deny]
874 [acl.deny]
876 foo/bar/** = fred
875 foo/bar/** = fred
877 foo/Bar/** = fred
876 foo/Bar/** = fred
878 [acl.allow]
877 [acl.allow]
879 ** = barney
878 ** = barney
880 **/*.txt = wilma
879 **/*.txt = wilma
881 [acl]
880 [acl]
882 config = ../acl.config
881 config = ../acl.config
883 """
882 """
884 pushing to ../b
883 pushing to ../b
885 query 1; heads
884 query 1; heads
886 searching for changes
885 searching for changes
887 all remote heads known locally
886 all remote heads known locally
888 listing keys for "phases"
887 listing keys for "phases"
889 checking for updated bookmarks
888 checking for updated bookmarks
890 listing keys for "bookmarks"
889 listing keys for "bookmarks"
891 listing keys for "bookmarks"
890 listing keys for "bookmarks"
892 3 changesets found
891 3 changesets found
893 list of changesets:
892 list of changesets:
894 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
893 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
895 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
894 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
896 911600dab2ae7a9baff75958b84fe606851ce955
895 911600dab2ae7a9baff75958b84fe606851ce955
897 bundle2-output-bundle: "HG20", 5 parts total
896 bundle2-output-bundle: "HG20", 5 parts total
898 bundle2-output-part: "replycaps" 168 bytes payload
897 bundle2-output-part: "replycaps" 168 bytes payload
899 bundle2-output-part: "check:phases" 24 bytes payload
898 bundle2-output-part: "check:phases" 24 bytes payload
900 bundle2-output-part: "check:heads" streamed payload
899 bundle2-output-part: "check:heads" streamed payload
901 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
900 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
902 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
901 bundle2-output-part: "phase-heads" 24 bytes payload
903 bundle2-input-bundle: with-transaction
902 bundle2-input-bundle: with-transaction
904 bundle2-input-part: "replycaps" supported
903 bundle2-input-part: "replycaps" supported
905 bundle2-input-part: total payload size 168
904 bundle2-input-part: total payload size 168
906 bundle2-input-part: "check:phases" supported
905 bundle2-input-part: "check:phases" supported
907 bundle2-input-part: total payload size 24
906 bundle2-input-part: total payload size 24
908 bundle2-input-part: "check:heads" supported
907 bundle2-input-part: "check:heads" supported
909 bundle2-input-part: total payload size 20
908 bundle2-input-part: total payload size 20
910 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
909 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
911 adding changesets
910 adding changesets
912 add changeset ef1ea85a6374
911 add changeset ef1ea85a6374
913 add changeset f9cafe1212c8
912 add changeset f9cafe1212c8
914 add changeset 911600dab2ae
913 add changeset 911600dab2ae
915 adding manifests
914 adding manifests
916 adding file changes
915 adding file changes
917 adding foo/Bar/file.txt revisions
916 adding foo/Bar/file.txt revisions
918 adding foo/file.txt revisions
917 adding foo/file.txt revisions
919 adding quux/file.py revisions
918 adding quux/file.py revisions
920 added 3 changesets with 3 changes to 3 files
919 added 3 changesets with 3 changes to 3 files
921 calling hook pretxnchangegroup.acl: hgext.acl.hook
920 calling hook pretxnchangegroup.acl: hgext.acl.hook
922 acl: checking access for user "barney"
921 acl: checking access for user "barney"
923 error: pretxnchangegroup.acl hook raised an exception: [Errno *] * (glob)
922 error: pretxnchangegroup.acl hook raised an exception: [Errno *] * (glob)
924 bundle2-input-part: total payload size 1553
923 bundle2-input-part: total payload size 1553
924 bundle2-input-part: total payload size 24
925 bundle2-input-bundle: 4 parts total
925 bundle2-input-bundle: 4 parts total
926 transaction abort!
926 transaction abort!
927 rollback completed
927 rollback completed
928 abort: No such file or directory: ../acl.config
928 abort: No such file or directory: ../acl.config
929 no rollback information available
929 no rollback information available
930 0:6675d58eff77
930 0:6675d58eff77
931
931
932
932
933 betty is allowed inside foo/ by a acl.config file
933 betty is allowed inside foo/ by a acl.config file
934
934
935 $ echo '[acl.allow]' >> acl.config
935 $ echo '[acl.allow]' >> acl.config
936 $ echo 'foo/** = betty' >> acl.config
936 $ echo 'foo/** = betty' >> acl.config
937 $ do_push betty
937 $ do_push betty
938 Pushing as user betty
938 Pushing as user betty
939 hgrc = """
939 hgrc = """
940 [hooks]
940 [hooks]
941 pretxnchangegroup.acl = python:hgext.acl.hook
941 pretxnchangegroup.acl = python:hgext.acl.hook
942 [acl]
942 [acl]
943 sources = push
943 sources = push
944 [acl.allow]
944 [acl.allow]
945 foo/** = fred
945 foo/** = fred
946 [acl.deny]
946 [acl.deny]
947 foo/bar/** = fred
947 foo/bar/** = fred
948 foo/Bar/** = fred
948 foo/Bar/** = fred
949 [acl.allow]
949 [acl.allow]
950 ** = barney
950 ** = barney
951 **/*.txt = wilma
951 **/*.txt = wilma
952 [acl]
952 [acl]
953 config = ../acl.config
953 config = ../acl.config
954 """
954 """
955 acl.config = """
955 acl.config = """
956 [acl.allow]
956 [acl.allow]
957 foo/** = betty
957 foo/** = betty
958 """
958 """
959 pushing to ../b
959 pushing to ../b
960 query 1; heads
960 query 1; heads
961 searching for changes
961 searching for changes
962 all remote heads known locally
962 all remote heads known locally
963 listing keys for "phases"
963 listing keys for "phases"
964 checking for updated bookmarks
964 checking for updated bookmarks
965 listing keys for "bookmarks"
965 listing keys for "bookmarks"
966 listing keys for "bookmarks"
966 listing keys for "bookmarks"
967 3 changesets found
967 3 changesets found
968 list of changesets:
968 list of changesets:
969 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
969 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
970 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
970 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
971 911600dab2ae7a9baff75958b84fe606851ce955
971 911600dab2ae7a9baff75958b84fe606851ce955
972 bundle2-output-bundle: "HG20", 5 parts total
972 bundle2-output-bundle: "HG20", 5 parts total
973 bundle2-output-part: "replycaps" 168 bytes payload
973 bundle2-output-part: "replycaps" 168 bytes payload
974 bundle2-output-part: "check:phases" 24 bytes payload
974 bundle2-output-part: "check:phases" 24 bytes payload
975 bundle2-output-part: "check:heads" streamed payload
975 bundle2-output-part: "check:heads" streamed payload
976 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
976 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
977 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
977 bundle2-output-part: "phase-heads" 24 bytes payload
978 bundle2-input-bundle: with-transaction
978 bundle2-input-bundle: with-transaction
979 bundle2-input-part: "replycaps" supported
979 bundle2-input-part: "replycaps" supported
980 bundle2-input-part: total payload size 168
980 bundle2-input-part: total payload size 168
981 bundle2-input-part: "check:phases" supported
981 bundle2-input-part: "check:phases" supported
982 bundle2-input-part: total payload size 24
982 bundle2-input-part: total payload size 24
983 bundle2-input-part: "check:heads" supported
983 bundle2-input-part: "check:heads" supported
984 bundle2-input-part: total payload size 20
984 bundle2-input-part: total payload size 20
985 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
985 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
986 adding changesets
986 adding changesets
987 add changeset ef1ea85a6374
987 add changeset ef1ea85a6374
988 add changeset f9cafe1212c8
988 add changeset f9cafe1212c8
989 add changeset 911600dab2ae
989 add changeset 911600dab2ae
990 adding manifests
990 adding manifests
991 adding file changes
991 adding file changes
992 adding foo/Bar/file.txt revisions
992 adding foo/Bar/file.txt revisions
993 adding foo/file.txt revisions
993 adding foo/file.txt revisions
994 adding quux/file.py revisions
994 adding quux/file.py revisions
995 added 3 changesets with 3 changes to 3 files
995 added 3 changesets with 3 changes to 3 files
996 calling hook pretxnchangegroup.acl: hgext.acl.hook
996 calling hook pretxnchangegroup.acl: hgext.acl.hook
997 acl: checking access for user "betty"
997 acl: checking access for user "betty"
998 acl: acl.allow.branches not enabled
998 acl: acl.allow.branches not enabled
999 acl: acl.deny.branches not enabled
999 acl: acl.deny.branches not enabled
1000 acl: acl.allow enabled, 1 entries for user betty
1000 acl: acl.allow enabled, 1 entries for user betty
1001 acl: acl.deny enabled, 0 entries for user betty
1001 acl: acl.deny enabled, 0 entries for user betty
1002 acl: branch access granted: "ef1ea85a6374" on branch "default"
1002 acl: branch access granted: "ef1ea85a6374" on branch "default"
1003 acl: path access granted: "ef1ea85a6374"
1003 acl: path access granted: "ef1ea85a6374"
1004 acl: branch access granted: "f9cafe1212c8" on branch "default"
1004 acl: branch access granted: "f9cafe1212c8" on branch "default"
1005 acl: path access granted: "f9cafe1212c8"
1005 acl: path access granted: "f9cafe1212c8"
1006 acl: branch access granted: "911600dab2ae" on branch "default"
1006 acl: branch access granted: "911600dab2ae" on branch "default"
1007 error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
1007 error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
1008 bundle2-input-part: total payload size 1553
1008 bundle2-input-part: total payload size 1553
1009 bundle2-input-part: total payload size 24
1009 bundle2-input-bundle: 4 parts total
1010 bundle2-input-bundle: 4 parts total
1010 transaction abort!
1011 transaction abort!
1011 rollback completed
1012 rollback completed
1012 abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
1013 abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
1013 no rollback information available
1014 no rollback information available
1014 0:6675d58eff77
1015 0:6675d58eff77
1015
1016
1016
1017
1017 acl.config can set only [acl.allow]/[acl.deny]
1018 acl.config can set only [acl.allow]/[acl.deny]
1018
1019
1019 $ echo '[hooks]' >> acl.config
1020 $ echo '[hooks]' >> acl.config
1020 $ echo 'changegroup.acl = false' >> acl.config
1021 $ echo 'changegroup.acl = false' >> acl.config
1021 $ do_push barney
1022 $ do_push barney
1022 Pushing as user barney
1023 Pushing as user barney
1023 hgrc = """
1024 hgrc = """
1024 [hooks]
1025 [hooks]
1025 pretxnchangegroup.acl = python:hgext.acl.hook
1026 pretxnchangegroup.acl = python:hgext.acl.hook
1026 [acl]
1027 [acl]
1027 sources = push
1028 sources = push
1028 [acl.allow]
1029 [acl.allow]
1029 foo/** = fred
1030 foo/** = fred
1030 [acl.deny]
1031 [acl.deny]
1031 foo/bar/** = fred
1032 foo/bar/** = fred
1032 foo/Bar/** = fred
1033 foo/Bar/** = fred
1033 [acl.allow]
1034 [acl.allow]
1034 ** = barney
1035 ** = barney
1035 **/*.txt = wilma
1036 **/*.txt = wilma
1036 [acl]
1037 [acl]
1037 config = ../acl.config
1038 config = ../acl.config
1038 """
1039 """
1039 acl.config = """
1040 acl.config = """
1040 [acl.allow]
1041 [acl.allow]
1041 foo/** = betty
1042 foo/** = betty
1042 [hooks]
1043 [hooks]
1043 changegroup.acl = false
1044 changegroup.acl = false
1044 """
1045 """
1045 pushing to ../b
1046 pushing to ../b
1046 query 1; heads
1047 query 1; heads
1047 searching for changes
1048 searching for changes
1048 all remote heads known locally
1049 all remote heads known locally
1049 listing keys for "phases"
1050 listing keys for "phases"
1050 checking for updated bookmarks
1051 checking for updated bookmarks
1051 listing keys for "bookmarks"
1052 listing keys for "bookmarks"
1052 listing keys for "bookmarks"
1053 listing keys for "bookmarks"
1053 3 changesets found
1054 3 changesets found
1054 list of changesets:
1055 list of changesets:
1055 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1056 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1056 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1057 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1057 911600dab2ae7a9baff75958b84fe606851ce955
1058 911600dab2ae7a9baff75958b84fe606851ce955
1058 bundle2-output-bundle: "HG20", 5 parts total
1059 bundle2-output-bundle: "HG20", 5 parts total
1059 bundle2-output-part: "replycaps" 168 bytes payload
1060 bundle2-output-part: "replycaps" 168 bytes payload
1060 bundle2-output-part: "check:phases" 24 bytes payload
1061 bundle2-output-part: "check:phases" 24 bytes payload
1061 bundle2-output-part: "check:heads" streamed payload
1062 bundle2-output-part: "check:heads" streamed payload
1062 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1063 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1063 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1064 bundle2-output-part: "phase-heads" 24 bytes payload
1064 bundle2-input-bundle: with-transaction
1065 bundle2-input-bundle: with-transaction
1065 bundle2-input-part: "replycaps" supported
1066 bundle2-input-part: "replycaps" supported
1066 bundle2-input-part: total payload size 168
1067 bundle2-input-part: total payload size 168
1067 bundle2-input-part: "check:phases" supported
1068 bundle2-input-part: "check:phases" supported
1068 bundle2-input-part: total payload size 24
1069 bundle2-input-part: total payload size 24
1069 bundle2-input-part: "check:heads" supported
1070 bundle2-input-part: "check:heads" supported
1070 bundle2-input-part: total payload size 20
1071 bundle2-input-part: total payload size 20
1071 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1072 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1072 adding changesets
1073 adding changesets
1073 add changeset ef1ea85a6374
1074 add changeset ef1ea85a6374
1074 add changeset f9cafe1212c8
1075 add changeset f9cafe1212c8
1075 add changeset 911600dab2ae
1076 add changeset 911600dab2ae
1076 adding manifests
1077 adding manifests
1077 adding file changes
1078 adding file changes
1078 adding foo/Bar/file.txt revisions
1079 adding foo/Bar/file.txt revisions
1079 adding foo/file.txt revisions
1080 adding foo/file.txt revisions
1080 adding quux/file.py revisions
1081 adding quux/file.py revisions
1081 added 3 changesets with 3 changes to 3 files
1082 added 3 changesets with 3 changes to 3 files
1082 calling hook pretxnchangegroup.acl: hgext.acl.hook
1083 calling hook pretxnchangegroup.acl: hgext.acl.hook
1083 acl: checking access for user "barney"
1084 acl: checking access for user "barney"
1084 acl: acl.allow.branches not enabled
1085 acl: acl.allow.branches not enabled
1085 acl: acl.deny.branches not enabled
1086 acl: acl.deny.branches not enabled
1086 acl: acl.allow enabled, 1 entries for user barney
1087 acl: acl.allow enabled, 1 entries for user barney
1087 acl: acl.deny enabled, 0 entries for user barney
1088 acl: acl.deny enabled, 0 entries for user barney
1088 acl: branch access granted: "ef1ea85a6374" on branch "default"
1089 acl: branch access granted: "ef1ea85a6374" on branch "default"
1089 acl: path access granted: "ef1ea85a6374"
1090 acl: path access granted: "ef1ea85a6374"
1090 acl: branch access granted: "f9cafe1212c8" on branch "default"
1091 acl: branch access granted: "f9cafe1212c8" on branch "default"
1091 acl: path access granted: "f9cafe1212c8"
1092 acl: path access granted: "f9cafe1212c8"
1092 acl: branch access granted: "911600dab2ae" on branch "default"
1093 acl: branch access granted: "911600dab2ae" on branch "default"
1093 acl: path access granted: "911600dab2ae"
1094 acl: path access granted: "911600dab2ae"
1094 bundle2-input-part: total payload size 1553
1095 bundle2-input-part: total payload size 1553
1095 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1096 bundle2-input-part: "phase-heads" supported
1096 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1097 bundle2-input-part: total payload size 24
1097 bundle2-input-bundle: 4 parts total
1098 bundle2-input-bundle: 4 parts total
1098 updating the branch cache
1099 updating the branch cache
1099 bundle2-output-bundle: "HG20", 2 parts total
1100 bundle2-output-bundle: "HG20", 1 parts total
1100 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1101 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1101 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1102 bundle2-input-bundle: no-transaction
1102 bundle2-input-bundle: no-transaction
1103 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1103 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1104 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1104 bundle2-input-bundle: 0 parts total
1105 bundle2-input-bundle: 1 parts total
1106 listing keys for "phases"
1105 listing keys for "phases"
1107 repository tip rolled back to revision 0 (undo push)
1106 repository tip rolled back to revision 0 (undo push)
1108 0:6675d58eff77
1107 0:6675d58eff77
1109
1108
1110
1109
1111 asterisk
1110 asterisk
1112
1111
1113 $ init_config
1112 $ init_config
1114
1113
1115 asterisk test
1114 asterisk test
1116
1115
1117 $ echo '[acl.allow]' >> $config
1116 $ echo '[acl.allow]' >> $config
1118 $ echo "** = fred" >> $config
1117 $ echo "** = fred" >> $config
1119
1118
1120 fred is always allowed
1119 fred is always allowed
1121
1120
1122 $ do_push fred
1121 $ do_push fred
1123 Pushing as user fred
1122 Pushing as user fred
1124 hgrc = """
1123 hgrc = """
1125 [hooks]
1124 [hooks]
1126 pretxnchangegroup.acl = python:hgext.acl.hook
1125 pretxnchangegroup.acl = python:hgext.acl.hook
1127 [acl]
1126 [acl]
1128 sources = push
1127 sources = push
1129 [extensions]
1128 [extensions]
1130 [acl.allow]
1129 [acl.allow]
1131 ** = fred
1130 ** = fred
1132 """
1131 """
1133 pushing to ../b
1132 pushing to ../b
1134 query 1; heads
1133 query 1; heads
1135 searching for changes
1134 searching for changes
1136 all remote heads known locally
1135 all remote heads known locally
1137 listing keys for "phases"
1136 listing keys for "phases"
1138 checking for updated bookmarks
1137 checking for updated bookmarks
1139 listing keys for "bookmarks"
1138 listing keys for "bookmarks"
1140 listing keys for "bookmarks"
1139 listing keys for "bookmarks"
1141 3 changesets found
1140 3 changesets found
1142 list of changesets:
1141 list of changesets:
1143 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1142 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1144 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1143 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1145 911600dab2ae7a9baff75958b84fe606851ce955
1144 911600dab2ae7a9baff75958b84fe606851ce955
1146 bundle2-output-bundle: "HG20", 5 parts total
1145 bundle2-output-bundle: "HG20", 5 parts total
1147 bundle2-output-part: "replycaps" 168 bytes payload
1146 bundle2-output-part: "replycaps" 168 bytes payload
1148 bundle2-output-part: "check:phases" 24 bytes payload
1147 bundle2-output-part: "check:phases" 24 bytes payload
1149 bundle2-output-part: "check:heads" streamed payload
1148 bundle2-output-part: "check:heads" streamed payload
1150 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1149 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1151 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1150 bundle2-output-part: "phase-heads" 24 bytes payload
1152 bundle2-input-bundle: with-transaction
1151 bundle2-input-bundle: with-transaction
1153 bundle2-input-part: "replycaps" supported
1152 bundle2-input-part: "replycaps" supported
1154 bundle2-input-part: total payload size 168
1153 bundle2-input-part: total payload size 168
1155 bundle2-input-part: "check:phases" supported
1154 bundle2-input-part: "check:phases" supported
1156 bundle2-input-part: total payload size 24
1155 bundle2-input-part: total payload size 24
1157 bundle2-input-part: "check:heads" supported
1156 bundle2-input-part: "check:heads" supported
1158 bundle2-input-part: total payload size 20
1157 bundle2-input-part: total payload size 20
1159 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1158 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1160 adding changesets
1159 adding changesets
1161 add changeset ef1ea85a6374
1160 add changeset ef1ea85a6374
1162 add changeset f9cafe1212c8
1161 add changeset f9cafe1212c8
1163 add changeset 911600dab2ae
1162 add changeset 911600dab2ae
1164 adding manifests
1163 adding manifests
1165 adding file changes
1164 adding file changes
1166 adding foo/Bar/file.txt revisions
1165 adding foo/Bar/file.txt revisions
1167 adding foo/file.txt revisions
1166 adding foo/file.txt revisions
1168 adding quux/file.py revisions
1167 adding quux/file.py revisions
1169 added 3 changesets with 3 changes to 3 files
1168 added 3 changesets with 3 changes to 3 files
1170 calling hook pretxnchangegroup.acl: hgext.acl.hook
1169 calling hook pretxnchangegroup.acl: hgext.acl.hook
1171 acl: checking access for user "fred"
1170 acl: checking access for user "fred"
1172 acl: acl.allow.branches not enabled
1171 acl: acl.allow.branches not enabled
1173 acl: acl.deny.branches not enabled
1172 acl: acl.deny.branches not enabled
1174 acl: acl.allow enabled, 1 entries for user fred
1173 acl: acl.allow enabled, 1 entries for user fred
1175 acl: acl.deny not enabled
1174 acl: acl.deny not enabled
1176 acl: branch access granted: "ef1ea85a6374" on branch "default"
1175 acl: branch access granted: "ef1ea85a6374" on branch "default"
1177 acl: path access granted: "ef1ea85a6374"
1176 acl: path access granted: "ef1ea85a6374"
1178 acl: branch access granted: "f9cafe1212c8" on branch "default"
1177 acl: branch access granted: "f9cafe1212c8" on branch "default"
1179 acl: path access granted: "f9cafe1212c8"
1178 acl: path access granted: "f9cafe1212c8"
1180 acl: branch access granted: "911600dab2ae" on branch "default"
1179 acl: branch access granted: "911600dab2ae" on branch "default"
1181 acl: path access granted: "911600dab2ae"
1180 acl: path access granted: "911600dab2ae"
1182 bundle2-input-part: total payload size 1553
1181 bundle2-input-part: total payload size 1553
1183 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1182 bundle2-input-part: "phase-heads" supported
1184 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1183 bundle2-input-part: total payload size 24
1185 bundle2-input-bundle: 4 parts total
1184 bundle2-input-bundle: 4 parts total
1186 updating the branch cache
1185 updating the branch cache
1187 bundle2-output-bundle: "HG20", 2 parts total
1186 bundle2-output-bundle: "HG20", 1 parts total
1188 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1187 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1189 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1190 bundle2-input-bundle: no-transaction
1188 bundle2-input-bundle: no-transaction
1191 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1189 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1192 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1190 bundle2-input-bundle: 0 parts total
1193 bundle2-input-bundle: 1 parts total
1194 listing keys for "phases"
1191 listing keys for "phases"
1195 repository tip rolled back to revision 0 (undo push)
1192 repository tip rolled back to revision 0 (undo push)
1196 0:6675d58eff77
1193 0:6675d58eff77
1197
1194
1198
1195
1199 $ echo '[acl.deny]' >> $config
1196 $ echo '[acl.deny]' >> $config
1200 $ echo "foo/Bar/** = *" >> $config
1197 $ echo "foo/Bar/** = *" >> $config
1201
1198
1202 no one is allowed inside foo/Bar/
1199 no one is allowed inside foo/Bar/
1203
1200
1204 $ do_push fred
1201 $ do_push fred
1205 Pushing as user fred
1202 Pushing as user fred
1206 hgrc = """
1203 hgrc = """
1207 [hooks]
1204 [hooks]
1208 pretxnchangegroup.acl = python:hgext.acl.hook
1205 pretxnchangegroup.acl = python:hgext.acl.hook
1209 [acl]
1206 [acl]
1210 sources = push
1207 sources = push
1211 [extensions]
1208 [extensions]
1212 [acl.allow]
1209 [acl.allow]
1213 ** = fred
1210 ** = fred
1214 [acl.deny]
1211 [acl.deny]
1215 foo/Bar/** = *
1212 foo/Bar/** = *
1216 """
1213 """
1217 pushing to ../b
1214 pushing to ../b
1218 query 1; heads
1215 query 1; heads
1219 searching for changes
1216 searching for changes
1220 all remote heads known locally
1217 all remote heads known locally
1221 listing keys for "phases"
1218 listing keys for "phases"
1222 checking for updated bookmarks
1219 checking for updated bookmarks
1223 listing keys for "bookmarks"
1220 listing keys for "bookmarks"
1224 listing keys for "bookmarks"
1221 listing keys for "bookmarks"
1225 3 changesets found
1222 3 changesets found
1226 list of changesets:
1223 list of changesets:
1227 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1224 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1228 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1225 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1229 911600dab2ae7a9baff75958b84fe606851ce955
1226 911600dab2ae7a9baff75958b84fe606851ce955
1230 bundle2-output-bundle: "HG20", 5 parts total
1227 bundle2-output-bundle: "HG20", 5 parts total
1231 bundle2-output-part: "replycaps" 168 bytes payload
1228 bundle2-output-part: "replycaps" 168 bytes payload
1232 bundle2-output-part: "check:phases" 24 bytes payload
1229 bundle2-output-part: "check:phases" 24 bytes payload
1233 bundle2-output-part: "check:heads" streamed payload
1230 bundle2-output-part: "check:heads" streamed payload
1234 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1231 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1235 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1232 bundle2-output-part: "phase-heads" 24 bytes payload
1236 bundle2-input-bundle: with-transaction
1233 bundle2-input-bundle: with-transaction
1237 bundle2-input-part: "replycaps" supported
1234 bundle2-input-part: "replycaps" supported
1238 bundle2-input-part: total payload size 168
1235 bundle2-input-part: total payload size 168
1239 bundle2-input-part: "check:phases" supported
1236 bundle2-input-part: "check:phases" supported
1240 bundle2-input-part: total payload size 24
1237 bundle2-input-part: total payload size 24
1241 bundle2-input-part: "check:heads" supported
1238 bundle2-input-part: "check:heads" supported
1242 bundle2-input-part: total payload size 20
1239 bundle2-input-part: total payload size 20
1243 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1240 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1244 adding changesets
1241 adding changesets
1245 add changeset ef1ea85a6374
1242 add changeset ef1ea85a6374
1246 add changeset f9cafe1212c8
1243 add changeset f9cafe1212c8
1247 add changeset 911600dab2ae
1244 add changeset 911600dab2ae
1248 adding manifests
1245 adding manifests
1249 adding file changes
1246 adding file changes
1250 adding foo/Bar/file.txt revisions
1247 adding foo/Bar/file.txt revisions
1251 adding foo/file.txt revisions
1248 adding foo/file.txt revisions
1252 adding quux/file.py revisions
1249 adding quux/file.py revisions
1253 added 3 changesets with 3 changes to 3 files
1250 added 3 changesets with 3 changes to 3 files
1254 calling hook pretxnchangegroup.acl: hgext.acl.hook
1251 calling hook pretxnchangegroup.acl: hgext.acl.hook
1255 acl: checking access for user "fred"
1252 acl: checking access for user "fred"
1256 acl: acl.allow.branches not enabled
1253 acl: acl.allow.branches not enabled
1257 acl: acl.deny.branches not enabled
1254 acl: acl.deny.branches not enabled
1258 acl: acl.allow enabled, 1 entries for user fred
1255 acl: acl.allow enabled, 1 entries for user fred
1259 acl: acl.deny enabled, 1 entries for user fred
1256 acl: acl.deny enabled, 1 entries for user fred
1260 acl: branch access granted: "ef1ea85a6374" on branch "default"
1257 acl: branch access granted: "ef1ea85a6374" on branch "default"
1261 acl: path access granted: "ef1ea85a6374"
1258 acl: path access granted: "ef1ea85a6374"
1262 acl: branch access granted: "f9cafe1212c8" on branch "default"
1259 acl: branch access granted: "f9cafe1212c8" on branch "default"
1263 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1260 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1264 bundle2-input-part: total payload size 1553
1261 bundle2-input-part: total payload size 1553
1262 bundle2-input-part: total payload size 24
1265 bundle2-input-bundle: 4 parts total
1263 bundle2-input-bundle: 4 parts total
1266 transaction abort!
1264 transaction abort!
1267 rollback completed
1265 rollback completed
1268 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1266 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1269 no rollback information available
1267 no rollback information available
1270 0:6675d58eff77
1268 0:6675d58eff77
1271
1269
1272
1270
1273 Groups
1271 Groups
1274
1272
1275 $ init_config
1273 $ init_config
1276
1274
1277 OS-level groups
1275 OS-level groups
1278
1276
1279 $ echo '[acl.allow]' >> $config
1277 $ echo '[acl.allow]' >> $config
1280 $ echo "** = @group1" >> $config
1278 $ echo "** = @group1" >> $config
1281
1279
1282 @group1 is always allowed
1280 @group1 is always allowed
1283
1281
1284 $ do_push fred
1282 $ do_push fred
1285 Pushing as user fred
1283 Pushing as user fred
1286 hgrc = """
1284 hgrc = """
1287 [hooks]
1285 [hooks]
1288 pretxnchangegroup.acl = python:hgext.acl.hook
1286 pretxnchangegroup.acl = python:hgext.acl.hook
1289 [acl]
1287 [acl]
1290 sources = push
1288 sources = push
1291 [extensions]
1289 [extensions]
1292 [acl.allow]
1290 [acl.allow]
1293 ** = @group1
1291 ** = @group1
1294 """
1292 """
1295 pushing to ../b
1293 pushing to ../b
1296 query 1; heads
1294 query 1; heads
1297 searching for changes
1295 searching for changes
1298 all remote heads known locally
1296 all remote heads known locally
1299 listing keys for "phases"
1297 listing keys for "phases"
1300 checking for updated bookmarks
1298 checking for updated bookmarks
1301 listing keys for "bookmarks"
1299 listing keys for "bookmarks"
1302 listing keys for "bookmarks"
1300 listing keys for "bookmarks"
1303 3 changesets found
1301 3 changesets found
1304 list of changesets:
1302 list of changesets:
1305 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1303 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1306 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1304 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1307 911600dab2ae7a9baff75958b84fe606851ce955
1305 911600dab2ae7a9baff75958b84fe606851ce955
1308 bundle2-output-bundle: "HG20", 5 parts total
1306 bundle2-output-bundle: "HG20", 5 parts total
1309 bundle2-output-part: "replycaps" 168 bytes payload
1307 bundle2-output-part: "replycaps" 168 bytes payload
1310 bundle2-output-part: "check:phases" 24 bytes payload
1308 bundle2-output-part: "check:phases" 24 bytes payload
1311 bundle2-output-part: "check:heads" streamed payload
1309 bundle2-output-part: "check:heads" streamed payload
1312 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1310 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1313 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1311 bundle2-output-part: "phase-heads" 24 bytes payload
1314 bundle2-input-bundle: with-transaction
1312 bundle2-input-bundle: with-transaction
1315 bundle2-input-part: "replycaps" supported
1313 bundle2-input-part: "replycaps" supported
1316 bundle2-input-part: total payload size 168
1314 bundle2-input-part: total payload size 168
1317 bundle2-input-part: "check:phases" supported
1315 bundle2-input-part: "check:phases" supported
1318 bundle2-input-part: total payload size 24
1316 bundle2-input-part: total payload size 24
1319 bundle2-input-part: "check:heads" supported
1317 bundle2-input-part: "check:heads" supported
1320 bundle2-input-part: total payload size 20
1318 bundle2-input-part: total payload size 20
1321 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1319 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1322 adding changesets
1320 adding changesets
1323 add changeset ef1ea85a6374
1321 add changeset ef1ea85a6374
1324 add changeset f9cafe1212c8
1322 add changeset f9cafe1212c8
1325 add changeset 911600dab2ae
1323 add changeset 911600dab2ae
1326 adding manifests
1324 adding manifests
1327 adding file changes
1325 adding file changes
1328 adding foo/Bar/file.txt revisions
1326 adding foo/Bar/file.txt revisions
1329 adding foo/file.txt revisions
1327 adding foo/file.txt revisions
1330 adding quux/file.py revisions
1328 adding quux/file.py revisions
1331 added 3 changesets with 3 changes to 3 files
1329 added 3 changesets with 3 changes to 3 files
1332 calling hook pretxnchangegroup.acl: hgext.acl.hook
1330 calling hook pretxnchangegroup.acl: hgext.acl.hook
1333 acl: checking access for user "fred"
1331 acl: checking access for user "fred"
1334 acl: acl.allow.branches not enabled
1332 acl: acl.allow.branches not enabled
1335 acl: acl.deny.branches not enabled
1333 acl: acl.deny.branches not enabled
1336 acl: "group1" not defined in [acl.groups]
1334 acl: "group1" not defined in [acl.groups]
1337 acl: acl.allow enabled, 1 entries for user fred
1335 acl: acl.allow enabled, 1 entries for user fred
1338 acl: acl.deny not enabled
1336 acl: acl.deny not enabled
1339 acl: branch access granted: "ef1ea85a6374" on branch "default"
1337 acl: branch access granted: "ef1ea85a6374" on branch "default"
1340 acl: path access granted: "ef1ea85a6374"
1338 acl: path access granted: "ef1ea85a6374"
1341 acl: branch access granted: "f9cafe1212c8" on branch "default"
1339 acl: branch access granted: "f9cafe1212c8" on branch "default"
1342 acl: path access granted: "f9cafe1212c8"
1340 acl: path access granted: "f9cafe1212c8"
1343 acl: branch access granted: "911600dab2ae" on branch "default"
1341 acl: branch access granted: "911600dab2ae" on branch "default"
1344 acl: path access granted: "911600dab2ae"
1342 acl: path access granted: "911600dab2ae"
1345 bundle2-input-part: total payload size 1553
1343 bundle2-input-part: total payload size 1553
1346 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1344 bundle2-input-part: "phase-heads" supported
1347 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1345 bundle2-input-part: total payload size 24
1348 bundle2-input-bundle: 4 parts total
1346 bundle2-input-bundle: 4 parts total
1349 updating the branch cache
1347 updating the branch cache
1350 bundle2-output-bundle: "HG20", 2 parts total
1348 bundle2-output-bundle: "HG20", 1 parts total
1351 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1349 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1352 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1353 bundle2-input-bundle: no-transaction
1350 bundle2-input-bundle: no-transaction
1354 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1351 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1355 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1352 bundle2-input-bundle: 0 parts total
1356 bundle2-input-bundle: 1 parts total
1357 listing keys for "phases"
1353 listing keys for "phases"
1358 repository tip rolled back to revision 0 (undo push)
1354 repository tip rolled back to revision 0 (undo push)
1359 0:6675d58eff77
1355 0:6675d58eff77
1360
1356
1361
1357
1362 $ echo '[acl.deny]' >> $config
1358 $ echo '[acl.deny]' >> $config
1363 $ echo "foo/Bar/** = @group1" >> $config
1359 $ echo "foo/Bar/** = @group1" >> $config
1364
1360
1365 @group is allowed inside anything but foo/Bar/
1361 @group is allowed inside anything but foo/Bar/
1366
1362
1367 $ do_push fred
1363 $ do_push fred
1368 Pushing as user fred
1364 Pushing as user fred
1369 hgrc = """
1365 hgrc = """
1370 [hooks]
1366 [hooks]
1371 pretxnchangegroup.acl = python:hgext.acl.hook
1367 pretxnchangegroup.acl = python:hgext.acl.hook
1372 [acl]
1368 [acl]
1373 sources = push
1369 sources = push
1374 [extensions]
1370 [extensions]
1375 [acl.allow]
1371 [acl.allow]
1376 ** = @group1
1372 ** = @group1
1377 [acl.deny]
1373 [acl.deny]
1378 foo/Bar/** = @group1
1374 foo/Bar/** = @group1
1379 """
1375 """
1380 pushing to ../b
1376 pushing to ../b
1381 query 1; heads
1377 query 1; heads
1382 searching for changes
1378 searching for changes
1383 all remote heads known locally
1379 all remote heads known locally
1384 listing keys for "phases"
1380 listing keys for "phases"
1385 checking for updated bookmarks
1381 checking for updated bookmarks
1386 listing keys for "bookmarks"
1382 listing keys for "bookmarks"
1387 listing keys for "bookmarks"
1383 listing keys for "bookmarks"
1388 3 changesets found
1384 3 changesets found
1389 list of changesets:
1385 list of changesets:
1390 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1386 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1391 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1387 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1392 911600dab2ae7a9baff75958b84fe606851ce955
1388 911600dab2ae7a9baff75958b84fe606851ce955
1393 bundle2-output-bundle: "HG20", 5 parts total
1389 bundle2-output-bundle: "HG20", 5 parts total
1394 bundle2-output-part: "replycaps" 168 bytes payload
1390 bundle2-output-part: "replycaps" 168 bytes payload
1395 bundle2-output-part: "check:phases" 24 bytes payload
1391 bundle2-output-part: "check:phases" 24 bytes payload
1396 bundle2-output-part: "check:heads" streamed payload
1392 bundle2-output-part: "check:heads" streamed payload
1397 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1393 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1398 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1394 bundle2-output-part: "phase-heads" 24 bytes payload
1399 bundle2-input-bundle: with-transaction
1395 bundle2-input-bundle: with-transaction
1400 bundle2-input-part: "replycaps" supported
1396 bundle2-input-part: "replycaps" supported
1401 bundle2-input-part: total payload size 168
1397 bundle2-input-part: total payload size 168
1402 bundle2-input-part: "check:phases" supported
1398 bundle2-input-part: "check:phases" supported
1403 bundle2-input-part: total payload size 24
1399 bundle2-input-part: total payload size 24
1404 bundle2-input-part: "check:heads" supported
1400 bundle2-input-part: "check:heads" supported
1405 bundle2-input-part: total payload size 20
1401 bundle2-input-part: total payload size 20
1406 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1402 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1407 adding changesets
1403 adding changesets
1408 add changeset ef1ea85a6374
1404 add changeset ef1ea85a6374
1409 add changeset f9cafe1212c8
1405 add changeset f9cafe1212c8
1410 add changeset 911600dab2ae
1406 add changeset 911600dab2ae
1411 adding manifests
1407 adding manifests
1412 adding file changes
1408 adding file changes
1413 adding foo/Bar/file.txt revisions
1409 adding foo/Bar/file.txt revisions
1414 adding foo/file.txt revisions
1410 adding foo/file.txt revisions
1415 adding quux/file.py revisions
1411 adding quux/file.py revisions
1416 added 3 changesets with 3 changes to 3 files
1412 added 3 changesets with 3 changes to 3 files
1417 calling hook pretxnchangegroup.acl: hgext.acl.hook
1413 calling hook pretxnchangegroup.acl: hgext.acl.hook
1418 acl: checking access for user "fred"
1414 acl: checking access for user "fred"
1419 acl: acl.allow.branches not enabled
1415 acl: acl.allow.branches not enabled
1420 acl: acl.deny.branches not enabled
1416 acl: acl.deny.branches not enabled
1421 acl: "group1" not defined in [acl.groups]
1417 acl: "group1" not defined in [acl.groups]
1422 acl: acl.allow enabled, 1 entries for user fred
1418 acl: acl.allow enabled, 1 entries for user fred
1423 acl: "group1" not defined in [acl.groups]
1419 acl: "group1" not defined in [acl.groups]
1424 acl: acl.deny enabled, 1 entries for user fred
1420 acl: acl.deny enabled, 1 entries for user fred
1425 acl: branch access granted: "ef1ea85a6374" on branch "default"
1421 acl: branch access granted: "ef1ea85a6374" on branch "default"
1426 acl: path access granted: "ef1ea85a6374"
1422 acl: path access granted: "ef1ea85a6374"
1427 acl: branch access granted: "f9cafe1212c8" on branch "default"
1423 acl: branch access granted: "f9cafe1212c8" on branch "default"
1428 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1424 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1429 bundle2-input-part: total payload size 1553
1425 bundle2-input-part: total payload size 1553
1426 bundle2-input-part: total payload size 24
1430 bundle2-input-bundle: 4 parts total
1427 bundle2-input-bundle: 4 parts total
1431 transaction abort!
1428 transaction abort!
1432 rollback completed
1429 rollback completed
1433 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1430 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1434 no rollback information available
1431 no rollback information available
1435 0:6675d58eff77
1432 0:6675d58eff77
1436
1433
1437
1434
1438 Invalid group
1435 Invalid group
1439
1436
1440 Disable the fakegroups trick to get real failures
1437 Disable the fakegroups trick to get real failures
1441
1438
1442 $ grep -v fakegroups $config > config.tmp
1439 $ grep -v fakegroups $config > config.tmp
1443 $ mv config.tmp $config
1440 $ mv config.tmp $config
1444 $ echo '[acl.allow]' >> $config
1441 $ echo '[acl.allow]' >> $config
1445 $ echo "** = @unlikelytoexist" >> $config
1442 $ echo "** = @unlikelytoexist" >> $config
1446 $ do_push fred 2>&1 | grep unlikelytoexist
1443 $ do_push fred 2>&1 | grep unlikelytoexist
1447 ** = @unlikelytoexist
1444 ** = @unlikelytoexist
1448 acl: "unlikelytoexist" not defined in [acl.groups]
1445 acl: "unlikelytoexist" not defined in [acl.groups]
1449 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1446 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1450 abort: group 'unlikelytoexist' is undefined
1447 abort: group 'unlikelytoexist' is undefined
1451
1448
1452
1449
1453 Branch acl tests setup
1450 Branch acl tests setup
1454
1451
1455 $ init_config
1452 $ init_config
1456 $ cd b
1453 $ cd b
1457 $ hg up
1454 $ hg up
1458 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1455 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1459 $ hg branch foobar
1456 $ hg branch foobar
1460 marked working directory as branch foobar
1457 marked working directory as branch foobar
1461 (branches are permanent and global, did you want a bookmark?)
1458 (branches are permanent and global, did you want a bookmark?)
1462 $ hg commit -m 'create foobar'
1459 $ hg commit -m 'create foobar'
1463 $ echo 'foo contents' > abc.txt
1460 $ echo 'foo contents' > abc.txt
1464 $ hg add abc.txt
1461 $ hg add abc.txt
1465 $ hg commit -m 'foobar contents'
1462 $ hg commit -m 'foobar contents'
1466 $ cd ..
1463 $ cd ..
1467 $ hg --cwd a pull ../b
1464 $ hg --cwd a pull ../b
1468 pulling from ../b
1465 pulling from ../b
1469 searching for changes
1466 searching for changes
1470 adding changesets
1467 adding changesets
1471 adding manifests
1468 adding manifests
1472 adding file changes
1469 adding file changes
1473 added 2 changesets with 1 changes to 1 files (+1 heads)
1470 added 2 changesets with 1 changes to 1 files (+1 heads)
1474 new changesets 81fbf4469322:fb35475503ef
1471 new changesets 81fbf4469322:fb35475503ef
1475 (run 'hg heads' to see heads)
1472 (run 'hg heads' to see heads)
1476
1473
1477 Create additional changeset on foobar branch
1474 Create additional changeset on foobar branch
1478
1475
1479 $ cd a
1476 $ cd a
1480 $ hg up -C foobar
1477 $ hg up -C foobar
1481 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1478 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1482 $ echo 'foo contents2' > abc.txt
1479 $ echo 'foo contents2' > abc.txt
1483 $ hg commit -m 'foobar contents2'
1480 $ hg commit -m 'foobar contents2'
1484 $ cd ..
1481 $ cd ..
1485
1482
1486
1483
1487 No branch acls specified
1484 No branch acls specified
1488
1485
1489 $ do_push astro
1486 $ do_push astro
1490 Pushing as user astro
1487 Pushing as user astro
1491 hgrc = """
1488 hgrc = """
1492 [hooks]
1489 [hooks]
1493 pretxnchangegroup.acl = python:hgext.acl.hook
1490 pretxnchangegroup.acl = python:hgext.acl.hook
1494 [acl]
1491 [acl]
1495 sources = push
1492 sources = push
1496 [extensions]
1493 [extensions]
1497 """
1494 """
1498 pushing to ../b
1495 pushing to ../b
1499 query 1; heads
1496 query 1; heads
1500 searching for changes
1497 searching for changes
1501 all remote heads known locally
1498 all remote heads known locally
1502 listing keys for "phases"
1499 listing keys for "phases"
1503 checking for updated bookmarks
1500 checking for updated bookmarks
1504 listing keys for "bookmarks"
1501 listing keys for "bookmarks"
1505 listing keys for "bookmarks"
1502 listing keys for "bookmarks"
1506 4 changesets found
1503 4 changesets found
1507 list of changesets:
1504 list of changesets:
1508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1505 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1506 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1510 911600dab2ae7a9baff75958b84fe606851ce955
1507 911600dab2ae7a9baff75958b84fe606851ce955
1511 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1508 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1512 bundle2-output-bundle: "HG20", 6 parts total
1509 bundle2-output-bundle: "HG20", 5 parts total
1513 bundle2-output-part: "replycaps" 168 bytes payload
1510 bundle2-output-part: "replycaps" 168 bytes payload
1514 bundle2-output-part: "check:phases" 48 bytes payload
1511 bundle2-output-part: "check:phases" 48 bytes payload
1515 bundle2-output-part: "check:heads" streamed payload
1512 bundle2-output-part: "check:heads" streamed payload
1516 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1513 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1517 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1514 bundle2-output-part: "phase-heads" 48 bytes payload
1518 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1519 bundle2-input-bundle: with-transaction
1515 bundle2-input-bundle: with-transaction
1520 bundle2-input-part: "replycaps" supported
1516 bundle2-input-part: "replycaps" supported
1521 bundle2-input-part: total payload size 168
1517 bundle2-input-part: total payload size 168
1522 bundle2-input-part: "check:phases" supported
1518 bundle2-input-part: "check:phases" supported
1523 bundle2-input-part: total payload size 48
1519 bundle2-input-part: total payload size 48
1524 bundle2-input-part: "check:heads" supported
1520 bundle2-input-part: "check:heads" supported
1525 bundle2-input-part: total payload size 20
1521 bundle2-input-part: total payload size 20
1526 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1522 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1527 adding changesets
1523 adding changesets
1528 add changeset ef1ea85a6374
1524 add changeset ef1ea85a6374
1529 add changeset f9cafe1212c8
1525 add changeset f9cafe1212c8
1530 add changeset 911600dab2ae
1526 add changeset 911600dab2ae
1531 add changeset e8fc755d4d82
1527 add changeset e8fc755d4d82
1532 adding manifests
1528 adding manifests
1533 adding file changes
1529 adding file changes
1534 adding abc.txt revisions
1530 adding abc.txt revisions
1535 adding foo/Bar/file.txt revisions
1531 adding foo/Bar/file.txt revisions
1536 adding foo/file.txt revisions
1532 adding foo/file.txt revisions
1537 adding quux/file.py revisions
1533 adding quux/file.py revisions
1538 added 4 changesets with 4 changes to 4 files (+1 heads)
1534 added 4 changesets with 4 changes to 4 files (+1 heads)
1539 calling hook pretxnchangegroup.acl: hgext.acl.hook
1535 calling hook pretxnchangegroup.acl: hgext.acl.hook
1540 acl: checking access for user "astro"
1536 acl: checking access for user "astro"
1541 acl: acl.allow.branches not enabled
1537 acl: acl.allow.branches not enabled
1542 acl: acl.deny.branches not enabled
1538 acl: acl.deny.branches not enabled
1543 acl: acl.allow not enabled
1539 acl: acl.allow not enabled
1544 acl: acl.deny not enabled
1540 acl: acl.deny not enabled
1545 acl: branch access granted: "ef1ea85a6374" on branch "default"
1541 acl: branch access granted: "ef1ea85a6374" on branch "default"
1546 acl: path access granted: "ef1ea85a6374"
1542 acl: path access granted: "ef1ea85a6374"
1547 acl: branch access granted: "f9cafe1212c8" on branch "default"
1543 acl: branch access granted: "f9cafe1212c8" on branch "default"
1548 acl: path access granted: "f9cafe1212c8"
1544 acl: path access granted: "f9cafe1212c8"
1549 acl: branch access granted: "911600dab2ae" on branch "default"
1545 acl: branch access granted: "911600dab2ae" on branch "default"
1550 acl: path access granted: "911600dab2ae"
1546 acl: path access granted: "911600dab2ae"
1551 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1547 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1552 acl: path access granted: "e8fc755d4d82"
1548 acl: path access granted: "e8fc755d4d82"
1553 bundle2-input-part: total payload size 2068
1549 bundle2-input-part: total payload size 2068
1554 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1550 bundle2-input-part: "phase-heads" supported
1555 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1551 bundle2-input-part: total payload size 48
1556 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1552 bundle2-input-bundle: 4 parts total
1557 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1558 bundle2-input-bundle: 5 parts total
1559 updating the branch cache
1553 updating the branch cache
1560 bundle2-output-bundle: "HG20", 3 parts total
1554 bundle2-output-bundle: "HG20", 1 parts total
1561 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1555 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1562 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1563 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1564 bundle2-input-bundle: no-transaction
1556 bundle2-input-bundle: no-transaction
1565 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1557 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1566 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1558 bundle2-input-bundle: 0 parts total
1567 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1568 bundle2-input-bundle: 2 parts total
1569 listing keys for "phases"
1559 listing keys for "phases"
1570 repository tip rolled back to revision 2 (undo push)
1560 repository tip rolled back to revision 2 (undo push)
1571 2:fb35475503ef
1561 2:fb35475503ef
1572
1562
1573
1563
1574 Branch acl deny test
1564 Branch acl deny test
1575
1565
1576 $ echo "[acl.deny.branches]" >> $config
1566 $ echo "[acl.deny.branches]" >> $config
1577 $ echo "foobar = *" >> $config
1567 $ echo "foobar = *" >> $config
1578 $ do_push astro
1568 $ do_push astro
1579 Pushing as user astro
1569 Pushing as user astro
1580 hgrc = """
1570 hgrc = """
1581 [hooks]
1571 [hooks]
1582 pretxnchangegroup.acl = python:hgext.acl.hook
1572 pretxnchangegroup.acl = python:hgext.acl.hook
1583 [acl]
1573 [acl]
1584 sources = push
1574 sources = push
1585 [extensions]
1575 [extensions]
1586 [acl.deny.branches]
1576 [acl.deny.branches]
1587 foobar = *
1577 foobar = *
1588 """
1578 """
1589 pushing to ../b
1579 pushing to ../b
1590 query 1; heads
1580 query 1; heads
1591 searching for changes
1581 searching for changes
1592 all remote heads known locally
1582 all remote heads known locally
1593 listing keys for "phases"
1583 listing keys for "phases"
1594 checking for updated bookmarks
1584 checking for updated bookmarks
1595 listing keys for "bookmarks"
1585 listing keys for "bookmarks"
1596 listing keys for "bookmarks"
1586 listing keys for "bookmarks"
1597 4 changesets found
1587 4 changesets found
1598 list of changesets:
1588 list of changesets:
1599 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1589 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1600 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1590 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1601 911600dab2ae7a9baff75958b84fe606851ce955
1591 911600dab2ae7a9baff75958b84fe606851ce955
1602 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1592 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1603 bundle2-output-bundle: "HG20", 6 parts total
1593 bundle2-output-bundle: "HG20", 5 parts total
1604 bundle2-output-part: "replycaps" 168 bytes payload
1594 bundle2-output-part: "replycaps" 168 bytes payload
1605 bundle2-output-part: "check:phases" 48 bytes payload
1595 bundle2-output-part: "check:phases" 48 bytes payload
1606 bundle2-output-part: "check:heads" streamed payload
1596 bundle2-output-part: "check:heads" streamed payload
1607 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1597 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1608 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1598 bundle2-output-part: "phase-heads" 48 bytes payload
1609 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1610 bundle2-input-bundle: with-transaction
1599 bundle2-input-bundle: with-transaction
1611 bundle2-input-part: "replycaps" supported
1600 bundle2-input-part: "replycaps" supported
1612 bundle2-input-part: total payload size 168
1601 bundle2-input-part: total payload size 168
1613 bundle2-input-part: "check:phases" supported
1602 bundle2-input-part: "check:phases" supported
1614 bundle2-input-part: total payload size 48
1603 bundle2-input-part: total payload size 48
1615 bundle2-input-part: "check:heads" supported
1604 bundle2-input-part: "check:heads" supported
1616 bundle2-input-part: total payload size 20
1605 bundle2-input-part: total payload size 20
1617 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1606 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1618 adding changesets
1607 adding changesets
1619 add changeset ef1ea85a6374
1608 add changeset ef1ea85a6374
1620 add changeset f9cafe1212c8
1609 add changeset f9cafe1212c8
1621 add changeset 911600dab2ae
1610 add changeset 911600dab2ae
1622 add changeset e8fc755d4d82
1611 add changeset e8fc755d4d82
1623 adding manifests
1612 adding manifests
1624 adding file changes
1613 adding file changes
1625 adding abc.txt revisions
1614 adding abc.txt revisions
1626 adding foo/Bar/file.txt revisions
1615 adding foo/Bar/file.txt revisions
1627 adding foo/file.txt revisions
1616 adding foo/file.txt revisions
1628 adding quux/file.py revisions
1617 adding quux/file.py revisions
1629 added 4 changesets with 4 changes to 4 files (+1 heads)
1618 added 4 changesets with 4 changes to 4 files (+1 heads)
1630 calling hook pretxnchangegroup.acl: hgext.acl.hook
1619 calling hook pretxnchangegroup.acl: hgext.acl.hook
1631 acl: checking access for user "astro"
1620 acl: checking access for user "astro"
1632 acl: acl.allow.branches not enabled
1621 acl: acl.allow.branches not enabled
1633 acl: acl.deny.branches enabled, 1 entries for user astro
1622 acl: acl.deny.branches enabled, 1 entries for user astro
1634 acl: acl.allow not enabled
1623 acl: acl.allow not enabled
1635 acl: acl.deny not enabled
1624 acl: acl.deny not enabled
1636 acl: branch access granted: "ef1ea85a6374" on branch "default"
1625 acl: branch access granted: "ef1ea85a6374" on branch "default"
1637 acl: path access granted: "ef1ea85a6374"
1626 acl: path access granted: "ef1ea85a6374"
1638 acl: branch access granted: "f9cafe1212c8" on branch "default"
1627 acl: branch access granted: "f9cafe1212c8" on branch "default"
1639 acl: path access granted: "f9cafe1212c8"
1628 acl: path access granted: "f9cafe1212c8"
1640 acl: branch access granted: "911600dab2ae" on branch "default"
1629 acl: branch access granted: "911600dab2ae" on branch "default"
1641 acl: path access granted: "911600dab2ae"
1630 acl: path access granted: "911600dab2ae"
1642 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1631 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1643 bundle2-input-part: total payload size 2068
1632 bundle2-input-part: total payload size 2068
1644 bundle2-input-bundle: 5 parts total
1633 bundle2-input-part: total payload size 48
1634 bundle2-input-bundle: 4 parts total
1645 transaction abort!
1635 transaction abort!
1646 rollback completed
1636 rollback completed
1647 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1637 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1648 no rollback information available
1638 no rollback information available
1649 2:fb35475503ef
1639 2:fb35475503ef
1650
1640
1651
1641
1652 Branch acl empty allow test
1642 Branch acl empty allow test
1653
1643
1654 $ init_config
1644 $ init_config
1655 $ echo "[acl.allow.branches]" >> $config
1645 $ echo "[acl.allow.branches]" >> $config
1656 $ do_push astro
1646 $ do_push astro
1657 Pushing as user astro
1647 Pushing as user astro
1658 hgrc = """
1648 hgrc = """
1659 [hooks]
1649 [hooks]
1660 pretxnchangegroup.acl = python:hgext.acl.hook
1650 pretxnchangegroup.acl = python:hgext.acl.hook
1661 [acl]
1651 [acl]
1662 sources = push
1652 sources = push
1663 [extensions]
1653 [extensions]
1664 [acl.allow.branches]
1654 [acl.allow.branches]
1665 """
1655 """
1666 pushing to ../b
1656 pushing to ../b
1667 query 1; heads
1657 query 1; heads
1668 searching for changes
1658 searching for changes
1669 all remote heads known locally
1659 all remote heads known locally
1670 listing keys for "phases"
1660 listing keys for "phases"
1671 checking for updated bookmarks
1661 checking for updated bookmarks
1672 listing keys for "bookmarks"
1662 listing keys for "bookmarks"
1673 listing keys for "bookmarks"
1663 listing keys for "bookmarks"
1674 4 changesets found
1664 4 changesets found
1675 list of changesets:
1665 list of changesets:
1676 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1666 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1677 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1667 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1678 911600dab2ae7a9baff75958b84fe606851ce955
1668 911600dab2ae7a9baff75958b84fe606851ce955
1679 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1669 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1680 bundle2-output-bundle: "HG20", 6 parts total
1670 bundle2-output-bundle: "HG20", 5 parts total
1681 bundle2-output-part: "replycaps" 168 bytes payload
1671 bundle2-output-part: "replycaps" 168 bytes payload
1682 bundle2-output-part: "check:phases" 48 bytes payload
1672 bundle2-output-part: "check:phases" 48 bytes payload
1683 bundle2-output-part: "check:heads" streamed payload
1673 bundle2-output-part: "check:heads" streamed payload
1684 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1674 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1685 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1675 bundle2-output-part: "phase-heads" 48 bytes payload
1686 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1687 bundle2-input-bundle: with-transaction
1676 bundle2-input-bundle: with-transaction
1688 bundle2-input-part: "replycaps" supported
1677 bundle2-input-part: "replycaps" supported
1689 bundle2-input-part: total payload size 168
1678 bundle2-input-part: total payload size 168
1690 bundle2-input-part: "check:phases" supported
1679 bundle2-input-part: "check:phases" supported
1691 bundle2-input-part: total payload size 48
1680 bundle2-input-part: total payload size 48
1692 bundle2-input-part: "check:heads" supported
1681 bundle2-input-part: "check:heads" supported
1693 bundle2-input-part: total payload size 20
1682 bundle2-input-part: total payload size 20
1694 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1683 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1695 adding changesets
1684 adding changesets
1696 add changeset ef1ea85a6374
1685 add changeset ef1ea85a6374
1697 add changeset f9cafe1212c8
1686 add changeset f9cafe1212c8
1698 add changeset 911600dab2ae
1687 add changeset 911600dab2ae
1699 add changeset e8fc755d4d82
1688 add changeset e8fc755d4d82
1700 adding manifests
1689 adding manifests
1701 adding file changes
1690 adding file changes
1702 adding abc.txt revisions
1691 adding abc.txt revisions
1703 adding foo/Bar/file.txt revisions
1692 adding foo/Bar/file.txt revisions
1704 adding foo/file.txt revisions
1693 adding foo/file.txt revisions
1705 adding quux/file.py revisions
1694 adding quux/file.py revisions
1706 added 4 changesets with 4 changes to 4 files (+1 heads)
1695 added 4 changesets with 4 changes to 4 files (+1 heads)
1707 calling hook pretxnchangegroup.acl: hgext.acl.hook
1696 calling hook pretxnchangegroup.acl: hgext.acl.hook
1708 acl: checking access for user "astro"
1697 acl: checking access for user "astro"
1709 acl: acl.allow.branches enabled, 0 entries for user astro
1698 acl: acl.allow.branches enabled, 0 entries for user astro
1710 acl: acl.deny.branches not enabled
1699 acl: acl.deny.branches not enabled
1711 acl: acl.allow not enabled
1700 acl: acl.allow not enabled
1712 acl: acl.deny not enabled
1701 acl: acl.deny not enabled
1713 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1702 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1714 bundle2-input-part: total payload size 2068
1703 bundle2-input-part: total payload size 2068
1715 bundle2-input-bundle: 5 parts total
1704 bundle2-input-part: total payload size 48
1705 bundle2-input-bundle: 4 parts total
1716 transaction abort!
1706 transaction abort!
1717 rollback completed
1707 rollback completed
1718 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1708 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1719 no rollback information available
1709 no rollback information available
1720 2:fb35475503ef
1710 2:fb35475503ef
1721
1711
1722
1712
1723 Branch acl allow other
1713 Branch acl allow other
1724
1714
1725 $ init_config
1715 $ init_config
1726 $ echo "[acl.allow.branches]" >> $config
1716 $ echo "[acl.allow.branches]" >> $config
1727 $ echo "* = george" >> $config
1717 $ echo "* = george" >> $config
1728 $ do_push astro
1718 $ do_push astro
1729 Pushing as user astro
1719 Pushing as user astro
1730 hgrc = """
1720 hgrc = """
1731 [hooks]
1721 [hooks]
1732 pretxnchangegroup.acl = python:hgext.acl.hook
1722 pretxnchangegroup.acl = python:hgext.acl.hook
1733 [acl]
1723 [acl]
1734 sources = push
1724 sources = push
1735 [extensions]
1725 [extensions]
1736 [acl.allow.branches]
1726 [acl.allow.branches]
1737 * = george
1727 * = george
1738 """
1728 """
1739 pushing to ../b
1729 pushing to ../b
1740 query 1; heads
1730 query 1; heads
1741 searching for changes
1731 searching for changes
1742 all remote heads known locally
1732 all remote heads known locally
1743 listing keys for "phases"
1733 listing keys for "phases"
1744 checking for updated bookmarks
1734 checking for updated bookmarks
1745 listing keys for "bookmarks"
1735 listing keys for "bookmarks"
1746 listing keys for "bookmarks"
1736 listing keys for "bookmarks"
1747 4 changesets found
1737 4 changesets found
1748 list of changesets:
1738 list of changesets:
1749 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1739 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1750 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1740 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1751 911600dab2ae7a9baff75958b84fe606851ce955
1741 911600dab2ae7a9baff75958b84fe606851ce955
1752 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1742 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1753 bundle2-output-bundle: "HG20", 6 parts total
1743 bundle2-output-bundle: "HG20", 5 parts total
1754 bundle2-output-part: "replycaps" 168 bytes payload
1744 bundle2-output-part: "replycaps" 168 bytes payload
1755 bundle2-output-part: "check:phases" 48 bytes payload
1745 bundle2-output-part: "check:phases" 48 bytes payload
1756 bundle2-output-part: "check:heads" streamed payload
1746 bundle2-output-part: "check:heads" streamed payload
1757 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1747 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1758 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1748 bundle2-output-part: "phase-heads" 48 bytes payload
1759 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1760 bundle2-input-bundle: with-transaction
1749 bundle2-input-bundle: with-transaction
1761 bundle2-input-part: "replycaps" supported
1750 bundle2-input-part: "replycaps" supported
1762 bundle2-input-part: total payload size 168
1751 bundle2-input-part: total payload size 168
1763 bundle2-input-part: "check:phases" supported
1752 bundle2-input-part: "check:phases" supported
1764 bundle2-input-part: total payload size 48
1753 bundle2-input-part: total payload size 48
1765 bundle2-input-part: "check:heads" supported
1754 bundle2-input-part: "check:heads" supported
1766 bundle2-input-part: total payload size 20
1755 bundle2-input-part: total payload size 20
1767 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1756 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1768 adding changesets
1757 adding changesets
1769 add changeset ef1ea85a6374
1758 add changeset ef1ea85a6374
1770 add changeset f9cafe1212c8
1759 add changeset f9cafe1212c8
1771 add changeset 911600dab2ae
1760 add changeset 911600dab2ae
1772 add changeset e8fc755d4d82
1761 add changeset e8fc755d4d82
1773 adding manifests
1762 adding manifests
1774 adding file changes
1763 adding file changes
1775 adding abc.txt revisions
1764 adding abc.txt revisions
1776 adding foo/Bar/file.txt revisions
1765 adding foo/Bar/file.txt revisions
1777 adding foo/file.txt revisions
1766 adding foo/file.txt revisions
1778 adding quux/file.py revisions
1767 adding quux/file.py revisions
1779 added 4 changesets with 4 changes to 4 files (+1 heads)
1768 added 4 changesets with 4 changes to 4 files (+1 heads)
1780 calling hook pretxnchangegroup.acl: hgext.acl.hook
1769 calling hook pretxnchangegroup.acl: hgext.acl.hook
1781 acl: checking access for user "astro"
1770 acl: checking access for user "astro"
1782 acl: acl.allow.branches enabled, 0 entries for user astro
1771 acl: acl.allow.branches enabled, 0 entries for user astro
1783 acl: acl.deny.branches not enabled
1772 acl: acl.deny.branches not enabled
1784 acl: acl.allow not enabled
1773 acl: acl.allow not enabled
1785 acl: acl.deny not enabled
1774 acl: acl.deny not enabled
1786 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1775 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1787 bundle2-input-part: total payload size 2068
1776 bundle2-input-part: total payload size 2068
1788 bundle2-input-bundle: 5 parts total
1777 bundle2-input-part: total payload size 48
1778 bundle2-input-bundle: 4 parts total
1789 transaction abort!
1779 transaction abort!
1790 rollback completed
1780 rollback completed
1791 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1781 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1792 no rollback information available
1782 no rollback information available
1793 2:fb35475503ef
1783 2:fb35475503ef
1794
1784
1795 $ do_push george
1785 $ do_push george
1796 Pushing as user george
1786 Pushing as user george
1797 hgrc = """
1787 hgrc = """
1798 [hooks]
1788 [hooks]
1799 pretxnchangegroup.acl = python:hgext.acl.hook
1789 pretxnchangegroup.acl = python:hgext.acl.hook
1800 [acl]
1790 [acl]
1801 sources = push
1791 sources = push
1802 [extensions]
1792 [extensions]
1803 [acl.allow.branches]
1793 [acl.allow.branches]
1804 * = george
1794 * = george
1805 """
1795 """
1806 pushing to ../b
1796 pushing to ../b
1807 query 1; heads
1797 query 1; heads
1808 searching for changes
1798 searching for changes
1809 all remote heads known locally
1799 all remote heads known locally
1810 listing keys for "phases"
1800 listing keys for "phases"
1811 checking for updated bookmarks
1801 checking for updated bookmarks
1812 listing keys for "bookmarks"
1802 listing keys for "bookmarks"
1813 listing keys for "bookmarks"
1803 listing keys for "bookmarks"
1814 4 changesets found
1804 4 changesets found
1815 list of changesets:
1805 list of changesets:
1816 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1806 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1817 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1807 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1818 911600dab2ae7a9baff75958b84fe606851ce955
1808 911600dab2ae7a9baff75958b84fe606851ce955
1819 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1809 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1820 bundle2-output-bundle: "HG20", 6 parts total
1810 bundle2-output-bundle: "HG20", 5 parts total
1821 bundle2-output-part: "replycaps" 168 bytes payload
1811 bundle2-output-part: "replycaps" 168 bytes payload
1822 bundle2-output-part: "check:phases" 48 bytes payload
1812 bundle2-output-part: "check:phases" 48 bytes payload
1823 bundle2-output-part: "check:heads" streamed payload
1813 bundle2-output-part: "check:heads" streamed payload
1824 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1814 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1825 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1815 bundle2-output-part: "phase-heads" 48 bytes payload
1826 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1827 bundle2-input-bundle: with-transaction
1816 bundle2-input-bundle: with-transaction
1828 bundle2-input-part: "replycaps" supported
1817 bundle2-input-part: "replycaps" supported
1829 bundle2-input-part: total payload size 168
1818 bundle2-input-part: total payload size 168
1830 bundle2-input-part: "check:phases" supported
1819 bundle2-input-part: "check:phases" supported
1831 bundle2-input-part: total payload size 48
1820 bundle2-input-part: total payload size 48
1832 bundle2-input-part: "check:heads" supported
1821 bundle2-input-part: "check:heads" supported
1833 bundle2-input-part: total payload size 20
1822 bundle2-input-part: total payload size 20
1834 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1823 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1835 adding changesets
1824 adding changesets
1836 add changeset ef1ea85a6374
1825 add changeset ef1ea85a6374
1837 add changeset f9cafe1212c8
1826 add changeset f9cafe1212c8
1838 add changeset 911600dab2ae
1827 add changeset 911600dab2ae
1839 add changeset e8fc755d4d82
1828 add changeset e8fc755d4d82
1840 adding manifests
1829 adding manifests
1841 adding file changes
1830 adding file changes
1842 adding abc.txt revisions
1831 adding abc.txt revisions
1843 adding foo/Bar/file.txt revisions
1832 adding foo/Bar/file.txt revisions
1844 adding foo/file.txt revisions
1833 adding foo/file.txt revisions
1845 adding quux/file.py revisions
1834 adding quux/file.py revisions
1846 added 4 changesets with 4 changes to 4 files (+1 heads)
1835 added 4 changesets with 4 changes to 4 files (+1 heads)
1847 calling hook pretxnchangegroup.acl: hgext.acl.hook
1836 calling hook pretxnchangegroup.acl: hgext.acl.hook
1848 acl: checking access for user "george"
1837 acl: checking access for user "george"
1849 acl: acl.allow.branches enabled, 1 entries for user george
1838 acl: acl.allow.branches enabled, 1 entries for user george
1850 acl: acl.deny.branches not enabled
1839 acl: acl.deny.branches not enabled
1851 acl: acl.allow not enabled
1840 acl: acl.allow not enabled
1852 acl: acl.deny not enabled
1841 acl: acl.deny not enabled
1853 acl: branch access granted: "ef1ea85a6374" on branch "default"
1842 acl: branch access granted: "ef1ea85a6374" on branch "default"
1854 acl: path access granted: "ef1ea85a6374"
1843 acl: path access granted: "ef1ea85a6374"
1855 acl: branch access granted: "f9cafe1212c8" on branch "default"
1844 acl: branch access granted: "f9cafe1212c8" on branch "default"
1856 acl: path access granted: "f9cafe1212c8"
1845 acl: path access granted: "f9cafe1212c8"
1857 acl: branch access granted: "911600dab2ae" on branch "default"
1846 acl: branch access granted: "911600dab2ae" on branch "default"
1858 acl: path access granted: "911600dab2ae"
1847 acl: path access granted: "911600dab2ae"
1859 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1848 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1860 acl: path access granted: "e8fc755d4d82"
1849 acl: path access granted: "e8fc755d4d82"
1861 bundle2-input-part: total payload size 2068
1850 bundle2-input-part: total payload size 2068
1862 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1851 bundle2-input-part: "phase-heads" supported
1863 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1852 bundle2-input-part: total payload size 48
1864 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1853 bundle2-input-bundle: 4 parts total
1865 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1866 bundle2-input-bundle: 5 parts total
1867 updating the branch cache
1854 updating the branch cache
1868 bundle2-output-bundle: "HG20", 3 parts total
1855 bundle2-output-bundle: "HG20", 1 parts total
1869 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1856 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1870 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1871 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1872 bundle2-input-bundle: no-transaction
1857 bundle2-input-bundle: no-transaction
1873 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1858 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1874 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1859 bundle2-input-bundle: 0 parts total
1875 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1876 bundle2-input-bundle: 2 parts total
1877 listing keys for "phases"
1860 listing keys for "phases"
1878 repository tip rolled back to revision 2 (undo push)
1861 repository tip rolled back to revision 2 (undo push)
1879 2:fb35475503ef
1862 2:fb35475503ef
1880
1863
1881
1864
1882 Branch acl conflicting allow
1865 Branch acl conflicting allow
1883 asterisk ends up applying to all branches and allowing george to
1866 asterisk ends up applying to all branches and allowing george to
1884 push foobar into the remote
1867 push foobar into the remote
1885
1868
1886 $ init_config
1869 $ init_config
1887 $ echo "[acl.allow.branches]" >> $config
1870 $ echo "[acl.allow.branches]" >> $config
1888 $ echo "foobar = astro" >> $config
1871 $ echo "foobar = astro" >> $config
1889 $ echo "* = george" >> $config
1872 $ echo "* = george" >> $config
1890 $ do_push george
1873 $ do_push george
1891 Pushing as user george
1874 Pushing as user george
1892 hgrc = """
1875 hgrc = """
1893 [hooks]
1876 [hooks]
1894 pretxnchangegroup.acl = python:hgext.acl.hook
1877 pretxnchangegroup.acl = python:hgext.acl.hook
1895 [acl]
1878 [acl]
1896 sources = push
1879 sources = push
1897 [extensions]
1880 [extensions]
1898 [acl.allow.branches]
1881 [acl.allow.branches]
1899 foobar = astro
1882 foobar = astro
1900 * = george
1883 * = george
1901 """
1884 """
1902 pushing to ../b
1885 pushing to ../b
1903 query 1; heads
1886 query 1; heads
1904 searching for changes
1887 searching for changes
1905 all remote heads known locally
1888 all remote heads known locally
1906 listing keys for "phases"
1889 listing keys for "phases"
1907 checking for updated bookmarks
1890 checking for updated bookmarks
1908 listing keys for "bookmarks"
1891 listing keys for "bookmarks"
1909 listing keys for "bookmarks"
1892 listing keys for "bookmarks"
1910 4 changesets found
1893 4 changesets found
1911 list of changesets:
1894 list of changesets:
1912 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1895 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1913 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1896 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1914 911600dab2ae7a9baff75958b84fe606851ce955
1897 911600dab2ae7a9baff75958b84fe606851ce955
1915 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1898 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1916 bundle2-output-bundle: "HG20", 6 parts total
1899 bundle2-output-bundle: "HG20", 5 parts total
1917 bundle2-output-part: "replycaps" 168 bytes payload
1900 bundle2-output-part: "replycaps" 168 bytes payload
1918 bundle2-output-part: "check:phases" 48 bytes payload
1901 bundle2-output-part: "check:phases" 48 bytes payload
1919 bundle2-output-part: "check:heads" streamed payload
1902 bundle2-output-part: "check:heads" streamed payload
1920 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1903 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1921 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1904 bundle2-output-part: "phase-heads" 48 bytes payload
1922 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1923 bundle2-input-bundle: with-transaction
1905 bundle2-input-bundle: with-transaction
1924 bundle2-input-part: "replycaps" supported
1906 bundle2-input-part: "replycaps" supported
1925 bundle2-input-part: total payload size 168
1907 bundle2-input-part: total payload size 168
1926 bundle2-input-part: "check:phases" supported
1908 bundle2-input-part: "check:phases" supported
1927 bundle2-input-part: total payload size 48
1909 bundle2-input-part: total payload size 48
1928 bundle2-input-part: "check:heads" supported
1910 bundle2-input-part: "check:heads" supported
1929 bundle2-input-part: total payload size 20
1911 bundle2-input-part: total payload size 20
1930 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1912 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1931 adding changesets
1913 adding changesets
1932 add changeset ef1ea85a6374
1914 add changeset ef1ea85a6374
1933 add changeset f9cafe1212c8
1915 add changeset f9cafe1212c8
1934 add changeset 911600dab2ae
1916 add changeset 911600dab2ae
1935 add changeset e8fc755d4d82
1917 add changeset e8fc755d4d82
1936 adding manifests
1918 adding manifests
1937 adding file changes
1919 adding file changes
1938 adding abc.txt revisions
1920 adding abc.txt revisions
1939 adding foo/Bar/file.txt revisions
1921 adding foo/Bar/file.txt revisions
1940 adding foo/file.txt revisions
1922 adding foo/file.txt revisions
1941 adding quux/file.py revisions
1923 adding quux/file.py revisions
1942 added 4 changesets with 4 changes to 4 files (+1 heads)
1924 added 4 changesets with 4 changes to 4 files (+1 heads)
1943 calling hook pretxnchangegroup.acl: hgext.acl.hook
1925 calling hook pretxnchangegroup.acl: hgext.acl.hook
1944 acl: checking access for user "george"
1926 acl: checking access for user "george"
1945 acl: acl.allow.branches enabled, 1 entries for user george
1927 acl: acl.allow.branches enabled, 1 entries for user george
1946 acl: acl.deny.branches not enabled
1928 acl: acl.deny.branches not enabled
1947 acl: acl.allow not enabled
1929 acl: acl.allow not enabled
1948 acl: acl.deny not enabled
1930 acl: acl.deny not enabled
1949 acl: branch access granted: "ef1ea85a6374" on branch "default"
1931 acl: branch access granted: "ef1ea85a6374" on branch "default"
1950 acl: path access granted: "ef1ea85a6374"
1932 acl: path access granted: "ef1ea85a6374"
1951 acl: branch access granted: "f9cafe1212c8" on branch "default"
1933 acl: branch access granted: "f9cafe1212c8" on branch "default"
1952 acl: path access granted: "f9cafe1212c8"
1934 acl: path access granted: "f9cafe1212c8"
1953 acl: branch access granted: "911600dab2ae" on branch "default"
1935 acl: branch access granted: "911600dab2ae" on branch "default"
1954 acl: path access granted: "911600dab2ae"
1936 acl: path access granted: "911600dab2ae"
1955 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1937 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1956 acl: path access granted: "e8fc755d4d82"
1938 acl: path access granted: "e8fc755d4d82"
1957 bundle2-input-part: total payload size 2068
1939 bundle2-input-part: total payload size 2068
1958 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1940 bundle2-input-part: "phase-heads" supported
1959 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1941 bundle2-input-part: total payload size 48
1960 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1942 bundle2-input-bundle: 4 parts total
1961 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1962 bundle2-input-bundle: 5 parts total
1963 updating the branch cache
1943 updating the branch cache
1964 bundle2-output-bundle: "HG20", 3 parts total
1944 bundle2-output-bundle: "HG20", 1 parts total
1965 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1945 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1966 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1967 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1968 bundle2-input-bundle: no-transaction
1946 bundle2-input-bundle: no-transaction
1969 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1947 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1970 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1948 bundle2-input-bundle: 0 parts total
1971 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1972 bundle2-input-bundle: 2 parts total
1973 listing keys for "phases"
1949 listing keys for "phases"
1974 repository tip rolled back to revision 2 (undo push)
1950 repository tip rolled back to revision 2 (undo push)
1975 2:fb35475503ef
1951 2:fb35475503ef
1976
1952
1977 Branch acl conflicting deny
1953 Branch acl conflicting deny
1978
1954
1979 $ init_config
1955 $ init_config
1980 $ echo "[acl.deny.branches]" >> $config
1956 $ echo "[acl.deny.branches]" >> $config
1981 $ echo "foobar = astro" >> $config
1957 $ echo "foobar = astro" >> $config
1982 $ echo "default = astro" >> $config
1958 $ echo "default = astro" >> $config
1983 $ echo "* = george" >> $config
1959 $ echo "* = george" >> $config
1984 $ do_push george
1960 $ do_push george
1985 Pushing as user george
1961 Pushing as user george
1986 hgrc = """
1962 hgrc = """
1987 [hooks]
1963 [hooks]
1988 pretxnchangegroup.acl = python:hgext.acl.hook
1964 pretxnchangegroup.acl = python:hgext.acl.hook
1989 [acl]
1965 [acl]
1990 sources = push
1966 sources = push
1991 [extensions]
1967 [extensions]
1992 [acl.deny.branches]
1968 [acl.deny.branches]
1993 foobar = astro
1969 foobar = astro
1994 default = astro
1970 default = astro
1995 * = george
1971 * = george
1996 """
1972 """
1997 pushing to ../b
1973 pushing to ../b
1998 query 1; heads
1974 query 1; heads
1999 searching for changes
1975 searching for changes
2000 all remote heads known locally
1976 all remote heads known locally
2001 listing keys for "phases"
1977 listing keys for "phases"
2002 checking for updated bookmarks
1978 checking for updated bookmarks
2003 listing keys for "bookmarks"
1979 listing keys for "bookmarks"
2004 listing keys for "bookmarks"
1980 listing keys for "bookmarks"
2005 4 changesets found
1981 4 changesets found
2006 list of changesets:
1982 list of changesets:
2007 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1983 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2008 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1984 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2009 911600dab2ae7a9baff75958b84fe606851ce955
1985 911600dab2ae7a9baff75958b84fe606851ce955
2010 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1986 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2011 bundle2-output-bundle: "HG20", 6 parts total
1987 bundle2-output-bundle: "HG20", 5 parts total
2012 bundle2-output-part: "replycaps" 168 bytes payload
1988 bundle2-output-part: "replycaps" 168 bytes payload
2013 bundle2-output-part: "check:phases" 48 bytes payload
1989 bundle2-output-part: "check:phases" 48 bytes payload
2014 bundle2-output-part: "check:heads" streamed payload
1990 bundle2-output-part: "check:heads" streamed payload
2015 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1991 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2016 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1992 bundle2-output-part: "phase-heads" 48 bytes payload
2017 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2018 bundle2-input-bundle: with-transaction
1993 bundle2-input-bundle: with-transaction
2019 bundle2-input-part: "replycaps" supported
1994 bundle2-input-part: "replycaps" supported
2020 bundle2-input-part: total payload size 168
1995 bundle2-input-part: total payload size 168
2021 bundle2-input-part: "check:phases" supported
1996 bundle2-input-part: "check:phases" supported
2022 bundle2-input-part: total payload size 48
1997 bundle2-input-part: total payload size 48
2023 bundle2-input-part: "check:heads" supported
1998 bundle2-input-part: "check:heads" supported
2024 bundle2-input-part: total payload size 20
1999 bundle2-input-part: total payload size 20
2025 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2000 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2026 adding changesets
2001 adding changesets
2027 add changeset ef1ea85a6374
2002 add changeset ef1ea85a6374
2028 add changeset f9cafe1212c8
2003 add changeset f9cafe1212c8
2029 add changeset 911600dab2ae
2004 add changeset 911600dab2ae
2030 add changeset e8fc755d4d82
2005 add changeset e8fc755d4d82
2031 adding manifests
2006 adding manifests
2032 adding file changes
2007 adding file changes
2033 adding abc.txt revisions
2008 adding abc.txt revisions
2034 adding foo/Bar/file.txt revisions
2009 adding foo/Bar/file.txt revisions
2035 adding foo/file.txt revisions
2010 adding foo/file.txt revisions
2036 adding quux/file.py revisions
2011 adding quux/file.py revisions
2037 added 4 changesets with 4 changes to 4 files (+1 heads)
2012 added 4 changesets with 4 changes to 4 files (+1 heads)
2038 calling hook pretxnchangegroup.acl: hgext.acl.hook
2013 calling hook pretxnchangegroup.acl: hgext.acl.hook
2039 acl: checking access for user "george"
2014 acl: checking access for user "george"
2040 acl: acl.allow.branches not enabled
2015 acl: acl.allow.branches not enabled
2041 acl: acl.deny.branches enabled, 1 entries for user george
2016 acl: acl.deny.branches enabled, 1 entries for user george
2042 acl: acl.allow not enabled
2017 acl: acl.allow not enabled
2043 acl: acl.deny not enabled
2018 acl: acl.deny not enabled
2044 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2019 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2045 bundle2-input-part: total payload size 2068
2020 bundle2-input-part: total payload size 2068
2046 bundle2-input-bundle: 5 parts total
2021 bundle2-input-part: total payload size 48
2022 bundle2-input-bundle: 4 parts total
2047 transaction abort!
2023 transaction abort!
2048 rollback completed
2024 rollback completed
2049 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2025 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2050 no rollback information available
2026 no rollback information available
2051 2:fb35475503ef
2027 2:fb35475503ef
2052
2028
2053 User 'astro' must not be denied
2029 User 'astro' must not be denied
2054
2030
2055 $ init_config
2031 $ init_config
2056 $ echo "[acl.deny.branches]" >> $config
2032 $ echo "[acl.deny.branches]" >> $config
2057 $ echo "default = !astro" >> $config
2033 $ echo "default = !astro" >> $config
2058 $ do_push astro
2034 $ do_push astro
2059 Pushing as user astro
2035 Pushing as user astro
2060 hgrc = """
2036 hgrc = """
2061 [hooks]
2037 [hooks]
2062 pretxnchangegroup.acl = python:hgext.acl.hook
2038 pretxnchangegroup.acl = python:hgext.acl.hook
2063 [acl]
2039 [acl]
2064 sources = push
2040 sources = push
2065 [extensions]
2041 [extensions]
2066 [acl.deny.branches]
2042 [acl.deny.branches]
2067 default = !astro
2043 default = !astro
2068 """
2044 """
2069 pushing to ../b
2045 pushing to ../b
2070 query 1; heads
2046 query 1; heads
2071 searching for changes
2047 searching for changes
2072 all remote heads known locally
2048 all remote heads known locally
2073 listing keys for "phases"
2049 listing keys for "phases"
2074 checking for updated bookmarks
2050 checking for updated bookmarks
2075 listing keys for "bookmarks"
2051 listing keys for "bookmarks"
2076 listing keys for "bookmarks"
2052 listing keys for "bookmarks"
2077 4 changesets found
2053 4 changesets found
2078 list of changesets:
2054 list of changesets:
2079 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2055 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2080 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2056 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2081 911600dab2ae7a9baff75958b84fe606851ce955
2057 911600dab2ae7a9baff75958b84fe606851ce955
2082 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2058 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2083 bundle2-output-bundle: "HG20", 6 parts total
2059 bundle2-output-bundle: "HG20", 5 parts total
2084 bundle2-output-part: "replycaps" 168 bytes payload
2060 bundle2-output-part: "replycaps" 168 bytes payload
2085 bundle2-output-part: "check:phases" 48 bytes payload
2061 bundle2-output-part: "check:phases" 48 bytes payload
2086 bundle2-output-part: "check:heads" streamed payload
2062 bundle2-output-part: "check:heads" streamed payload
2087 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2063 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2088 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2064 bundle2-output-part: "phase-heads" 48 bytes payload
2089 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2090 bundle2-input-bundle: with-transaction
2065 bundle2-input-bundle: with-transaction
2091 bundle2-input-part: "replycaps" supported
2066 bundle2-input-part: "replycaps" supported
2092 bundle2-input-part: total payload size 168
2067 bundle2-input-part: total payload size 168
2093 bundle2-input-part: "check:phases" supported
2068 bundle2-input-part: "check:phases" supported
2094 bundle2-input-part: total payload size 48
2069 bundle2-input-part: total payload size 48
2095 bundle2-input-part: "check:heads" supported
2070 bundle2-input-part: "check:heads" supported
2096 bundle2-input-part: total payload size 20
2071 bundle2-input-part: total payload size 20
2097 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2072 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2098 adding changesets
2073 adding changesets
2099 add changeset ef1ea85a6374
2074 add changeset ef1ea85a6374
2100 add changeset f9cafe1212c8
2075 add changeset f9cafe1212c8
2101 add changeset 911600dab2ae
2076 add changeset 911600dab2ae
2102 add changeset e8fc755d4d82
2077 add changeset e8fc755d4d82
2103 adding manifests
2078 adding manifests
2104 adding file changes
2079 adding file changes
2105 adding abc.txt revisions
2080 adding abc.txt revisions
2106 adding foo/Bar/file.txt revisions
2081 adding foo/Bar/file.txt revisions
2107 adding foo/file.txt revisions
2082 adding foo/file.txt revisions
2108 adding quux/file.py revisions
2083 adding quux/file.py revisions
2109 added 4 changesets with 4 changes to 4 files (+1 heads)
2084 added 4 changesets with 4 changes to 4 files (+1 heads)
2110 calling hook pretxnchangegroup.acl: hgext.acl.hook
2085 calling hook pretxnchangegroup.acl: hgext.acl.hook
2111 acl: checking access for user "astro"
2086 acl: checking access for user "astro"
2112 acl: acl.allow.branches not enabled
2087 acl: acl.allow.branches not enabled
2113 acl: acl.deny.branches enabled, 0 entries for user astro
2088 acl: acl.deny.branches enabled, 0 entries for user astro
2114 acl: acl.allow not enabled
2089 acl: acl.allow not enabled
2115 acl: acl.deny not enabled
2090 acl: acl.deny not enabled
2116 acl: branch access granted: "ef1ea85a6374" on branch "default"
2091 acl: branch access granted: "ef1ea85a6374" on branch "default"
2117 acl: path access granted: "ef1ea85a6374"
2092 acl: path access granted: "ef1ea85a6374"
2118 acl: branch access granted: "f9cafe1212c8" on branch "default"
2093 acl: branch access granted: "f9cafe1212c8" on branch "default"
2119 acl: path access granted: "f9cafe1212c8"
2094 acl: path access granted: "f9cafe1212c8"
2120 acl: branch access granted: "911600dab2ae" on branch "default"
2095 acl: branch access granted: "911600dab2ae" on branch "default"
2121 acl: path access granted: "911600dab2ae"
2096 acl: path access granted: "911600dab2ae"
2122 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
2097 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
2123 acl: path access granted: "e8fc755d4d82"
2098 acl: path access granted: "e8fc755d4d82"
2124 bundle2-input-part: total payload size 2068
2099 bundle2-input-part: total payload size 2068
2125 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
2100 bundle2-input-part: "phase-heads" supported
2126 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
2101 bundle2-input-part: total payload size 48
2127 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
2102 bundle2-input-bundle: 4 parts total
2128 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
2129 bundle2-input-bundle: 5 parts total
2130 updating the branch cache
2103 updating the branch cache
2131 bundle2-output-bundle: "HG20", 3 parts total
2104 bundle2-output-bundle: "HG20", 1 parts total
2132 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
2105 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
2133 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2134 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2135 bundle2-input-bundle: no-transaction
2106 bundle2-input-bundle: no-transaction
2136 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
2107 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
2137 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2108 bundle2-input-bundle: 0 parts total
2138 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2139 bundle2-input-bundle: 2 parts total
2140 listing keys for "phases"
2109 listing keys for "phases"
2141 repository tip rolled back to revision 2 (undo push)
2110 repository tip rolled back to revision 2 (undo push)
2142 2:fb35475503ef
2111 2:fb35475503ef
2143
2112
2144
2113
2145 Non-astro users must be denied
2114 Non-astro users must be denied
2146
2115
2147 $ do_push george
2116 $ do_push george
2148 Pushing as user george
2117 Pushing as user george
2149 hgrc = """
2118 hgrc = """
2150 [hooks]
2119 [hooks]
2151 pretxnchangegroup.acl = python:hgext.acl.hook
2120 pretxnchangegroup.acl = python:hgext.acl.hook
2152 [acl]
2121 [acl]
2153 sources = push
2122 sources = push
2154 [extensions]
2123 [extensions]
2155 [acl.deny.branches]
2124 [acl.deny.branches]
2156 default = !astro
2125 default = !astro
2157 """
2126 """
2158 pushing to ../b
2127 pushing to ../b
2159 query 1; heads
2128 query 1; heads
2160 searching for changes
2129 searching for changes
2161 all remote heads known locally
2130 all remote heads known locally
2162 listing keys for "phases"
2131 listing keys for "phases"
2163 checking for updated bookmarks
2132 checking for updated bookmarks
2164 listing keys for "bookmarks"
2133 listing keys for "bookmarks"
2165 listing keys for "bookmarks"
2134 listing keys for "bookmarks"
2166 4 changesets found
2135 4 changesets found
2167 list of changesets:
2136 list of changesets:
2168 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2137 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2169 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2138 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2170 911600dab2ae7a9baff75958b84fe606851ce955
2139 911600dab2ae7a9baff75958b84fe606851ce955
2171 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2140 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2172 bundle2-output-bundle: "HG20", 6 parts total
2141 bundle2-output-bundle: "HG20", 5 parts total
2173 bundle2-output-part: "replycaps" 168 bytes payload
2142 bundle2-output-part: "replycaps" 168 bytes payload
2174 bundle2-output-part: "check:phases" 48 bytes payload
2143 bundle2-output-part: "check:phases" 48 bytes payload
2175 bundle2-output-part: "check:heads" streamed payload
2144 bundle2-output-part: "check:heads" streamed payload
2176 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2145 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2177 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2146 bundle2-output-part: "phase-heads" 48 bytes payload
2178 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2179 bundle2-input-bundle: with-transaction
2147 bundle2-input-bundle: with-transaction
2180 bundle2-input-part: "replycaps" supported
2148 bundle2-input-part: "replycaps" supported
2181 bundle2-input-part: total payload size 168
2149 bundle2-input-part: total payload size 168
2182 bundle2-input-part: "check:phases" supported
2150 bundle2-input-part: "check:phases" supported
2183 bundle2-input-part: total payload size 48
2151 bundle2-input-part: total payload size 48
2184 bundle2-input-part: "check:heads" supported
2152 bundle2-input-part: "check:heads" supported
2185 bundle2-input-part: total payload size 20
2153 bundle2-input-part: total payload size 20
2186 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2154 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2187 adding changesets
2155 adding changesets
2188 add changeset ef1ea85a6374
2156 add changeset ef1ea85a6374
2189 add changeset f9cafe1212c8
2157 add changeset f9cafe1212c8
2190 add changeset 911600dab2ae
2158 add changeset 911600dab2ae
2191 add changeset e8fc755d4d82
2159 add changeset e8fc755d4d82
2192 adding manifests
2160 adding manifests
2193 adding file changes
2161 adding file changes
2194 adding abc.txt revisions
2162 adding abc.txt revisions
2195 adding foo/Bar/file.txt revisions
2163 adding foo/Bar/file.txt revisions
2196 adding foo/file.txt revisions
2164 adding foo/file.txt revisions
2197 adding quux/file.py revisions
2165 adding quux/file.py revisions
2198 added 4 changesets with 4 changes to 4 files (+1 heads)
2166 added 4 changesets with 4 changes to 4 files (+1 heads)
2199 calling hook pretxnchangegroup.acl: hgext.acl.hook
2167 calling hook pretxnchangegroup.acl: hgext.acl.hook
2200 acl: checking access for user "george"
2168 acl: checking access for user "george"
2201 acl: acl.allow.branches not enabled
2169 acl: acl.allow.branches not enabled
2202 acl: acl.deny.branches enabled, 1 entries for user george
2170 acl: acl.deny.branches enabled, 1 entries for user george
2203 acl: acl.allow not enabled
2171 acl: acl.allow not enabled
2204 acl: acl.deny not enabled
2172 acl: acl.deny not enabled
2205 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2173 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2206 bundle2-input-part: total payload size 2068
2174 bundle2-input-part: total payload size 2068
2207 bundle2-input-bundle: 5 parts total
2175 bundle2-input-part: total payload size 48
2176 bundle2-input-bundle: 4 parts total
2208 transaction abort!
2177 transaction abort!
2209 rollback completed
2178 rollback completed
2210 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2179 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2211 no rollback information available
2180 no rollback information available
2212 2:fb35475503ef
2181 2:fb35475503ef
2213
2182
2214
2183
@@ -1,1153 +1,1147
1 Test exchange of common information using bundle2
1 Test exchange of common information using bundle2
2
2
3
3
4 $ getmainid() {
4 $ getmainid() {
5 > hg -R main log --template '{node}\n' --rev "$1"
5 > hg -R main log --template '{node}\n' --rev "$1"
6 > }
6 > }
7
7
8 enable obsolescence
8 enable obsolescence
9
9
10 $ cp $HGRCPATH $TESTTMP/hgrc.orig
10 $ cp $HGRCPATH $TESTTMP/hgrc.orig
11 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
11 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
12 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
12 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
13 > hg debuglock
13 > hg debuglock
14 > EOF
14 > EOF
15
15
16 $ cat >> $HGRCPATH << EOF
16 $ cat >> $HGRCPATH << EOF
17 > [experimental]
17 > [experimental]
18 > stabilization=createmarkers,exchange
18 > stabilization=createmarkers,exchange
19 > bundle2-output-capture=True
19 > bundle2-output-capture=True
20 > [ui]
20 > [ui]
21 > ssh="$PYTHON" "$TESTDIR/dummyssh"
21 > ssh="$PYTHON" "$TESTDIR/dummyssh"
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
23 > [web]
23 > [web]
24 > push_ssl = false
24 > push_ssl = false
25 > allow_push = *
25 > allow_push = *
26 > [phases]
26 > [phases]
27 > publish=False
27 > publish=False
28 > [hooks]
28 > [hooks]
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
31 > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
31 > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
33 > EOF
33 > EOF
34
34
35 The extension requires a repo (currently unused)
35 The extension requires a repo (currently unused)
36
36
37 $ hg init main
37 $ hg init main
38 $ cd main
38 $ cd main
39 $ touch a
39 $ touch a
40 $ hg add a
40 $ hg add a
41 $ hg commit -m 'a'
41 $ hg commit -m 'a'
42 pre-close-tip:3903775176ed draft
42 pre-close-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
44 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
44 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
45
45
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
47 adding changesets
47 adding changesets
48 adding manifests
48 adding manifests
49 adding file changes
49 adding file changes
50 added 8 changesets with 7 changes to 7 files (+3 heads)
50 added 8 changesets with 7 changes to 7 files (+3 heads)
51 pre-close-tip:02de42196ebe draft
51 pre-close-tip:02de42196ebe draft
52 new changesets cd010b8cd998:02de42196ebe
52 new changesets cd010b8cd998:02de42196ebe
53 postclose-tip:02de42196ebe draft
53 postclose-tip:02de42196ebe draft
54 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:$ID$ HG_TXNNAME=unbundle
54 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:$ID$ HG_TXNNAME=unbundle
55 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
55 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
56 (run 'hg heads' to see heads, 'hg merge' to merge)
56 (run 'hg heads' to see heads, 'hg merge' to merge)
57
57
58 $ cd ..
58 $ cd ..
59
59
60 Real world exchange
60 Real world exchange
61 =====================
61 =====================
62
62
63 Add more obsolescence information
63 Add more obsolescence information
64
64
65 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
65 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
66 pre-close-tip:02de42196ebe draft
66 pre-close-tip:02de42196ebe draft
67 postclose-tip:02de42196ebe draft
67 postclose-tip:02de42196ebe draft
68 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
68 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
69 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
69 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
70 pre-close-tip:02de42196ebe draft
70 pre-close-tip:02de42196ebe draft
71 postclose-tip:02de42196ebe draft
71 postclose-tip:02de42196ebe draft
72 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
72 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
73
73
74 clone --pull
74 clone --pull
75
75
76 $ hg -R main phase --public cd010b8cd998
76 $ hg -R main phase --public cd010b8cd998
77 pre-close-tip:02de42196ebe draft
77 pre-close-tip:02de42196ebe draft
78 postclose-tip:02de42196ebe draft
78 postclose-tip:02de42196ebe draft
79 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
79 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
80 $ hg clone main other --pull --rev 9520eea781bc
80 $ hg clone main other --pull --rev 9520eea781bc
81 adding changesets
81 adding changesets
82 adding manifests
82 adding manifests
83 adding file changes
83 adding file changes
84 added 2 changesets with 2 changes to 2 files
84 added 2 changesets with 2 changes to 2 files
85 1 new obsolescence markers
85 1 new obsolescence markers
86 pre-close-tip:9520eea781bc draft
86 pre-close-tip:9520eea781bc draft
87 new changesets cd010b8cd998:9520eea781bc
87 new changesets cd010b8cd998:9520eea781bc
88 postclose-tip:9520eea781bc draft
88 postclose-tip:9520eea781bc draft
89 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=9520eea781bcca16c1e15acc0ba14335a0e8e5ba HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
89 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=9520eea781bcca16c1e15acc0ba14335a0e8e5ba HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
90 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
90 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
91 updating to branch default
91 updating to branch default
92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 $ hg -R other log -G
93 $ hg -R other log -G
94 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
94 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
95 |
95 |
96 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
96 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
97
97
98 $ hg -R other debugobsolete
98 $ hg -R other debugobsolete
99 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
99 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
100
100
101 pull
101 pull
102
102
103 $ hg -R main phase --public 9520eea781bc
103 $ hg -R main phase --public 9520eea781bc
104 pre-close-tip:02de42196ebe draft
104 pre-close-tip:02de42196ebe draft
105 postclose-tip:02de42196ebe draft
105 postclose-tip:02de42196ebe draft
106 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
106 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
107 $ hg -R other pull -r 24b6387c8c8c
107 $ hg -R other pull -r 24b6387c8c8c
108 pulling from $TESTTMP/main (glob)
108 pulling from $TESTTMP/main (glob)
109 searching for changes
109 searching for changes
110 adding changesets
110 adding changesets
111 adding manifests
111 adding manifests
112 adding file changes
112 adding file changes
113 added 1 changesets with 1 changes to 1 files (+1 heads)
113 added 1 changesets with 1 changes to 1 files (+1 heads)
114 1 new obsolescence markers
114 1 new obsolescence markers
115 pre-close-tip:24b6387c8c8c draft
115 pre-close-tip:24b6387c8c8c draft
116 new changesets 24b6387c8c8c
116 new changesets 24b6387c8c8c
117 postclose-tip:24b6387c8c8c draft
117 postclose-tip:24b6387c8c8c draft
118 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_NODE_LAST=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
118 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_NODE_LAST=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
119 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
119 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
120 (run 'hg heads' to see heads, 'hg merge' to merge)
120 (run 'hg heads' to see heads, 'hg merge' to merge)
121 $ hg -R other log -G
121 $ hg -R other log -G
122 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
122 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
123 |
123 |
124 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
124 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
125 |/
125 |/
126 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
126 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
127
127
128 $ hg -R other debugobsolete
128 $ hg -R other debugobsolete
129 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
129 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
130 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
130 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
131
131
132 pull empty (with phase movement)
132 pull empty (with phase movement)
133
133
134 $ hg -R main phase --public 24b6387c8c8c
134 $ hg -R main phase --public 24b6387c8c8c
135 pre-close-tip:02de42196ebe draft
135 pre-close-tip:02de42196ebe draft
136 postclose-tip:02de42196ebe draft
136 postclose-tip:02de42196ebe draft
137 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
137 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
138 $ hg -R other pull -r 24b6387c8c8c
138 $ hg -R other pull -r 24b6387c8c8c
139 pulling from $TESTTMP/main (glob)
139 pulling from $TESTTMP/main (glob)
140 no changes found
140 no changes found
141 pre-close-tip:24b6387c8c8c public
141 pre-close-tip:24b6387c8c8c public
142 postclose-tip:24b6387c8c8c public
142 postclose-tip:24b6387c8c8c public
143 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
143 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
144 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
144 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
145 $ hg -R other log -G
145 $ hg -R other log -G
146 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
146 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
147 |
147 |
148 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
148 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
149 |/
149 |/
150 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
150 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
151
151
152 $ hg -R other debugobsolete
152 $ hg -R other debugobsolete
153 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
153 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
154 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
154 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
155
155
156 pull empty
156 pull empty
157
157
158 $ hg -R other pull -r 24b6387c8c8c
158 $ hg -R other pull -r 24b6387c8c8c
159 pulling from $TESTTMP/main (glob)
159 pulling from $TESTTMP/main (glob)
160 no changes found
160 no changes found
161 pre-close-tip:24b6387c8c8c public
161 pre-close-tip:24b6387c8c8c public
162 postclose-tip:24b6387c8c8c public
162 postclose-tip:24b6387c8c8c public
163 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
163 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
164 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
164 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
165 $ hg -R other log -G
165 $ hg -R other log -G
166 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
166 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
167 |
167 |
168 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
168 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
169 |/
169 |/
170 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
170 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
171
171
172 $ hg -R other debugobsolete
172 $ hg -R other debugobsolete
173 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
173 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
174 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
174 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
175
175
176 add extra data to test their exchange during push
176 add extra data to test their exchange during push
177
177
178 $ hg -R main bookmark --rev eea13746799a book_eea1
178 $ hg -R main bookmark --rev eea13746799a book_eea1
179 pre-close-tip:02de42196ebe draft
179 pre-close-tip:02de42196ebe draft
180 postclose-tip:02de42196ebe draft
180 postclose-tip:02de42196ebe draft
181 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
181 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
182 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
182 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
183 pre-close-tip:02de42196ebe draft
183 pre-close-tip:02de42196ebe draft
184 postclose-tip:02de42196ebe draft
184 postclose-tip:02de42196ebe draft
185 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
185 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
186 $ hg -R main bookmark --rev 02de42196ebe book_02de
186 $ hg -R main bookmark --rev 02de42196ebe book_02de
187 pre-close-tip:02de42196ebe draft book_02de
187 pre-close-tip:02de42196ebe draft book_02de
188 postclose-tip:02de42196ebe draft book_02de
188 postclose-tip:02de42196ebe draft book_02de
189 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
189 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
190 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
190 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
191 pre-close-tip:02de42196ebe draft book_02de
191 pre-close-tip:02de42196ebe draft book_02de
192 postclose-tip:02de42196ebe draft book_02de
192 postclose-tip:02de42196ebe draft book_02de
193 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
193 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
194 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
194 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
195 pre-close-tip:02de42196ebe draft book_02de
195 pre-close-tip:02de42196ebe draft book_02de
196 postclose-tip:02de42196ebe draft book_02de
196 postclose-tip:02de42196ebe draft book_02de
197 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
197 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
198 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
198 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
199 pre-close-tip:02de42196ebe draft book_02de
199 pre-close-tip:02de42196ebe draft book_02de
200 postclose-tip:02de42196ebe draft book_02de
200 postclose-tip:02de42196ebe draft book_02de
201 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
201 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
202 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
202 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
203 pre-close-tip:02de42196ebe draft book_02de
203 pre-close-tip:02de42196ebe draft book_02de
204 postclose-tip:02de42196ebe draft book_02de
204 postclose-tip:02de42196ebe draft book_02de
205 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
205 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
206 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
206 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
207 pre-close-tip:02de42196ebe draft book_02de
207 pre-close-tip:02de42196ebe draft book_02de
208 postclose-tip:02de42196ebe draft book_02de
208 postclose-tip:02de42196ebe draft book_02de
209 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
209 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
210 $ hg -R main bookmark --rev 32af7686d403 book_32af
210 $ hg -R main bookmark --rev 32af7686d403 book_32af
211 pre-close-tip:02de42196ebe draft book_02de
211 pre-close-tip:02de42196ebe draft book_02de
212 postclose-tip:02de42196ebe draft book_02de
212 postclose-tip:02de42196ebe draft book_02de
213 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
213 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
214 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
214 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
215 pre-close-tip:02de42196ebe draft book_02de
215 pre-close-tip:02de42196ebe draft book_02de
216 postclose-tip:02de42196ebe draft book_02de
216 postclose-tip:02de42196ebe draft book_02de
217 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
217 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
218
218
219 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
219 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
220 pre-close-tip:24b6387c8c8c public
220 pre-close-tip:24b6387c8c8c public
221 postclose-tip:24b6387c8c8c public
221 postclose-tip:24b6387c8c8c public
222 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
222 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
223 $ hg -R other bookmark --rev cd010b8cd998 book_02de
223 $ hg -R other bookmark --rev cd010b8cd998 book_02de
224 pre-close-tip:24b6387c8c8c public
224 pre-close-tip:24b6387c8c8c public
225 postclose-tip:24b6387c8c8c public
225 postclose-tip:24b6387c8c8c public
226 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
226 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
227 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
227 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
228 pre-close-tip:24b6387c8c8c public
228 pre-close-tip:24b6387c8c8c public
229 postclose-tip:24b6387c8c8c public
229 postclose-tip:24b6387c8c8c public
230 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
230 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
231 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
231 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
232 pre-close-tip:24b6387c8c8c public
232 pre-close-tip:24b6387c8c8c public
233 postclose-tip:24b6387c8c8c public
233 postclose-tip:24b6387c8c8c public
234 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
234 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
235 $ hg -R other bookmark --rev cd010b8cd998 book_32af
235 $ hg -R other bookmark --rev cd010b8cd998 book_32af
236 pre-close-tip:24b6387c8c8c public
236 pre-close-tip:24b6387c8c8c public
237 postclose-tip:24b6387c8c8c public
237 postclose-tip:24b6387c8c8c public
238 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
238 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
239
239
240 $ hg -R main phase --public eea13746799a
240 $ hg -R main phase --public eea13746799a
241 pre-close-tip:02de42196ebe draft book_02de
241 pre-close-tip:02de42196ebe draft book_02de
242 postclose-tip:02de42196ebe draft book_02de
242 postclose-tip:02de42196ebe draft book_02de
243 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
243 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
244
244
245 push
245 push
246 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
246 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
247 pushing to other
247 pushing to other
248 searching for changes
248 searching for changes
249 remote: adding changesets
249 remote: adding changesets
250 remote: adding manifests
250 remote: adding manifests
251 remote: adding file changes
251 remote: adding file changes
252 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
252 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
253 remote: 1 new obsolescence markers
253 remote: 1 new obsolescence markers
254 remote: pre-close-tip:eea13746799a public book_eea1
254 remote: pre-close-tip:eea13746799a public book_eea1
255 remote: pushkey: lock state after "phases"
256 remote: lock: free
257 remote: wlock: free
258 remote: pushkey: lock state after "bookmarks"
255 remote: pushkey: lock state after "bookmarks"
259 remote: lock: free
256 remote: lock: free
260 remote: wlock: free
257 remote: wlock: free
261 remote: postclose-tip:eea13746799a public book_eea1
258 remote: postclose-tip:eea13746799a public book_eea1
262 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_NODE_LAST=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:$ID$ HG_TXNNAME=push HG_URL=file:$TESTTMP/other
259 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_NODE_LAST=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:$ID$ HG_TXNNAME=push HG_URL=file:$TESTTMP/other
263 updating bookmark book_eea1
260 updating bookmark book_eea1
264 pre-close-tip:02de42196ebe draft book_02de
261 pre-close-tip:02de42196ebe draft book_02de
265 postclose-tip:02de42196ebe draft book_02de
262 postclose-tip:02de42196ebe draft book_02de
266 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
263 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
267 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
264 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
268 $ hg -R other log -G
265 $ hg -R other log -G
269 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
266 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
270 |\
267 |\
271 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
268 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
272 | |
269 | |
273 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
270 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
274 |/
271 |/
275 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
272 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
276
273
277 $ hg -R other debugobsolete
274 $ hg -R other debugobsolete
278 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
275 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
279 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
276 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
280 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
277 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
281
278
282 pull over ssh
279 pull over ssh
283
280
284 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
281 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
285 pulling from ssh://user@dummy/main
282 pulling from ssh://user@dummy/main
286 searching for changes
283 searching for changes
287 adding changesets
284 adding changesets
288 adding manifests
285 adding manifests
289 adding file changes
286 adding file changes
290 added 1 changesets with 1 changes to 1 files (+1 heads)
287 added 1 changesets with 1 changes to 1 files (+1 heads)
291 1 new obsolescence markers
288 1 new obsolescence markers
292 updating bookmark book_02de
289 updating bookmark book_02de
293 pre-close-tip:02de42196ebe draft book_02de
290 pre-close-tip:02de42196ebe draft book_02de
294 new changesets 02de42196ebe
291 new changesets 02de42196ebe
295 postclose-tip:02de42196ebe draft book_02de
292 postclose-tip:02de42196ebe draft book_02de
296 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
293 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
297 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
294 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
298 (run 'hg heads' to see heads, 'hg merge' to merge)
295 (run 'hg heads' to see heads, 'hg merge' to merge)
299 $ hg -R other debugobsolete
296 $ hg -R other debugobsolete
300 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
297 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
301 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
298 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
302 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
299 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
303 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
300 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
304
301
305 pull over http
302 pull over http
306
303
307 $ hg serve -R main -p $HGPORT -d --pid-file=main.pid -E main-error.log
304 $ hg serve -R main -p $HGPORT -d --pid-file=main.pid -E main-error.log
308 $ cat main.pid >> $DAEMON_PIDS
305 $ cat main.pid >> $DAEMON_PIDS
309
306
310 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
307 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
311 pulling from http://localhost:$HGPORT/
308 pulling from http://localhost:$HGPORT/
312 searching for changes
309 searching for changes
313 adding changesets
310 adding changesets
314 adding manifests
311 adding manifests
315 adding file changes
312 adding file changes
316 added 1 changesets with 1 changes to 1 files (+1 heads)
313 added 1 changesets with 1 changes to 1 files (+1 heads)
317 1 new obsolescence markers
314 1 new obsolescence markers
318 updating bookmark book_42cc
315 updating bookmark book_42cc
319 pre-close-tip:42ccdea3bb16 draft book_42cc
316 pre-close-tip:42ccdea3bb16 draft book_42cc
320 new changesets 42ccdea3bb16
317 new changesets 42ccdea3bb16
321 postclose-tip:42ccdea3bb16 draft book_42cc
318 postclose-tip:42ccdea3bb16 draft book_42cc
322 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_NODE_LAST=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
319 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_NODE_LAST=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
323 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
320 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
324 (run 'hg heads .' to see heads, 'hg merge' to merge)
321 (run 'hg heads .' to see heads, 'hg merge' to merge)
325 $ cat main-error.log
322 $ cat main-error.log
326 $ hg -R other debugobsolete
323 $ hg -R other debugobsolete
327 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
324 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
328 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
325 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
329 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
326 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
330 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
327 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
331 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
328 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
332
329
333 push over ssh
330 push over ssh
334
331
335 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
332 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
336 pushing to ssh://user@dummy/other
333 pushing to ssh://user@dummy/other
337 searching for changes
334 searching for changes
338 remote: adding changesets
335 remote: adding changesets
339 remote: adding manifests
336 remote: adding manifests
340 remote: adding file changes
337 remote: adding file changes
341 remote: added 1 changesets with 1 changes to 1 files
338 remote: added 1 changesets with 1 changes to 1 files
342 remote: 1 new obsolescence markers
339 remote: 1 new obsolescence markers
343 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
340 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
344 remote: pushkey: lock state after "bookmarks"
341 remote: pushkey: lock state after "bookmarks"
345 remote: lock: free
342 remote: lock: free
346 remote: wlock: free
343 remote: wlock: free
347 remote: postclose-tip:5fddd98957c8 draft book_5fdd
344 remote: postclose-tip:5fddd98957c8 draft book_5fdd
348 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_NODE_LAST=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:ssh:$LOCALIP
345 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_NODE_LAST=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:ssh:$LOCALIP
349 updating bookmark book_5fdd
346 updating bookmark book_5fdd
350 pre-close-tip:02de42196ebe draft book_02de
347 pre-close-tip:02de42196ebe draft book_02de
351 postclose-tip:02de42196ebe draft book_02de
348 postclose-tip:02de42196ebe draft book_02de
352 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
349 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
353 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
350 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
354 $ hg -R other log -G
351 $ hg -R other log -G
355 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
352 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
356 |
353 |
357 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
354 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
358 |
355 |
359 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
356 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
360 | |
357 | |
361 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
358 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
362 | |/|
359 | |/|
363 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
360 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
364 |/ /
361 |/ /
365 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
362 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
366 |/
363 |/
367 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
364 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
368
365
369 $ hg -R other debugobsolete
366 $ hg -R other debugobsolete
370 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
367 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
371 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
368 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
372 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
369 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
373 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
370 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
374 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
371 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
375 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
372 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
376
373
377 push over http
374 push over http
378
375
379 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
376 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
380 $ cat other.pid >> $DAEMON_PIDS
377 $ cat other.pid >> $DAEMON_PIDS
381
378
382 $ hg -R main phase --public 32af7686d403
379 $ hg -R main phase --public 32af7686d403
383 pre-close-tip:02de42196ebe draft book_02de
380 pre-close-tip:02de42196ebe draft book_02de
384 postclose-tip:02de42196ebe draft book_02de
381 postclose-tip:02de42196ebe draft book_02de
385 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
382 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
386 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
383 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
387 pushing to http://localhost:$HGPORT2/
384 pushing to http://localhost:$HGPORT2/
388 searching for changes
385 searching for changes
389 remote: adding changesets
386 remote: adding changesets
390 remote: adding manifests
387 remote: adding manifests
391 remote: adding file changes
388 remote: adding file changes
392 remote: added 1 changesets with 1 changes to 1 files
389 remote: added 1 changesets with 1 changes to 1 files
393 remote: 1 new obsolescence markers
390 remote: 1 new obsolescence markers
394 remote: pre-close-tip:32af7686d403 public book_32af
391 remote: pre-close-tip:32af7686d403 public book_32af
395 remote: pushkey: lock state after "phases"
396 remote: lock: free
397 remote: wlock: free
398 remote: pushkey: lock state after "bookmarks"
392 remote: pushkey: lock state after "bookmarks"
399 remote: lock: free
393 remote: lock: free
400 remote: wlock: free
394 remote: wlock: free
401 remote: postclose-tip:32af7686d403 public book_32af
395 remote: postclose-tip:32af7686d403 public book_32af
402 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_NODE_LAST=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:http:$LOCALIP: (glob)
396 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_NODE_LAST=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:http:$LOCALIP: (glob)
403 updating bookmark book_32af
397 updating bookmark book_32af
404 pre-close-tip:02de42196ebe draft book_02de
398 pre-close-tip:02de42196ebe draft book_02de
405 postclose-tip:02de42196ebe draft book_02de
399 postclose-tip:02de42196ebe draft book_02de
406 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
400 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
407 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
401 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
408 $ cat other-error.log
402 $ cat other-error.log
409
403
410 Check final content.
404 Check final content.
411
405
412 $ hg -R other log -G
406 $ hg -R other log -G
413 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
407 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
414 |
408 |
415 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
409 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
416 |
410 |
417 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
411 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
418 |
412 |
419 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
413 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
420 | |
414 | |
421 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
415 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
422 | |/|
416 | |/|
423 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
417 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
424 |/ /
418 |/ /
425 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
419 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
426 |/
420 |/
427 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
421 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
428
422
429 $ hg -R other debugobsolete
423 $ hg -R other debugobsolete
430 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
424 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
431 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
425 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
432 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
426 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
433 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
427 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
434 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
428 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
435 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
429 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
436 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
430 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
437
431
438 (check that no 'pending' files remain)
432 (check that no 'pending' files remain)
439
433
440 $ ls -1 other/.hg/bookmarks*
434 $ ls -1 other/.hg/bookmarks*
441 other/.hg/bookmarks
435 other/.hg/bookmarks
442 $ ls -1 other/.hg/store/phaseroots*
436 $ ls -1 other/.hg/store/phaseroots*
443 other/.hg/store/phaseroots
437 other/.hg/store/phaseroots
444 $ ls -1 other/.hg/store/00changelog.i*
438 $ ls -1 other/.hg/store/00changelog.i*
445 other/.hg/store/00changelog.i
439 other/.hg/store/00changelog.i
446
440
447 Error Handling
441 Error Handling
448 ==============
442 ==============
449
443
450 Check that errors are properly returned to the client during push.
444 Check that errors are properly returned to the client during push.
451
445
452 Setting up
446 Setting up
453
447
454 $ cat > failpush.py << EOF
448 $ cat > failpush.py << EOF
455 > """A small extension that makes push fails when using bundle2
449 > """A small extension that makes push fails when using bundle2
456 >
450 >
457 > used to test error handling in bundle2
451 > used to test error handling in bundle2
458 > """
452 > """
459 >
453 >
460 > from mercurial import error
454 > from mercurial import error
461 > from mercurial import bundle2
455 > from mercurial import bundle2
462 > from mercurial import exchange
456 > from mercurial import exchange
463 > from mercurial import extensions
457 > from mercurial import extensions
464 > from mercurial import registrar
458 > from mercurial import registrar
465 > cmdtable = {}
459 > cmdtable = {}
466 > command = registrar.command(cmdtable)
460 > command = registrar.command(cmdtable)
467 >
461 >
468 > configtable = {}
462 > configtable = {}
469 > configitem = registrar.configitem(configtable)
463 > configitem = registrar.configitem(configtable)
470 > configitem('failpush', 'reason',
464 > configitem('failpush', 'reason',
471 > default=None,
465 > default=None,
472 > )
466 > )
473 >
467 >
474 > def _pushbundle2failpart(pushop, bundler):
468 > def _pushbundle2failpart(pushop, bundler):
475 > reason = pushop.ui.config('failpush', 'reason')
469 > reason = pushop.ui.config('failpush', 'reason')
476 > part = None
470 > part = None
477 > if reason == 'abort':
471 > if reason == 'abort':
478 > bundler.newpart('test:abort')
472 > bundler.newpart('test:abort')
479 > if reason == 'unknown':
473 > if reason == 'unknown':
480 > bundler.newpart('test:unknown')
474 > bundler.newpart('test:unknown')
481 > if reason == 'race':
475 > if reason == 'race':
482 > # 20 Bytes of crap
476 > # 20 Bytes of crap
483 > bundler.newpart('check:heads', data='01234567890123456789')
477 > bundler.newpart('check:heads', data='01234567890123456789')
484 >
478 >
485 > @bundle2.parthandler("test:abort")
479 > @bundle2.parthandler("test:abort")
486 > def handleabort(op, part):
480 > def handleabort(op, part):
487 > raise error.Abort('Abandon ship!', hint="don't panic")
481 > raise error.Abort('Abandon ship!', hint="don't panic")
488 >
482 >
489 > def uisetup(ui):
483 > def uisetup(ui):
490 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
484 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
491 > exchange.b2partsgenorder.insert(0, 'failpart')
485 > exchange.b2partsgenorder.insert(0, 'failpart')
492 >
486 >
493 > EOF
487 > EOF
494
488
495 $ cd main
489 $ cd main
496 $ hg up tip
490 $ hg up tip
497 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
491 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
498 $ echo 'I' > I
492 $ echo 'I' > I
499 $ hg add I
493 $ hg add I
500 $ hg ci -m 'I'
494 $ hg ci -m 'I'
501 pre-close-tip:e7ec4e813ba6 draft
495 pre-close-tip:e7ec4e813ba6 draft
502 postclose-tip:e7ec4e813ba6 draft
496 postclose-tip:e7ec4e813ba6 draft
503 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
497 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
504 $ hg id
498 $ hg id
505 e7ec4e813ba6 tip
499 e7ec4e813ba6 tip
506 $ cd ..
500 $ cd ..
507
501
508 $ cat << EOF >> $HGRCPATH
502 $ cat << EOF >> $HGRCPATH
509 > [extensions]
503 > [extensions]
510 > failpush=$TESTTMP/failpush.py
504 > failpush=$TESTTMP/failpush.py
511 > EOF
505 > EOF
512
506
513 $ killdaemons.py
507 $ killdaemons.py
514 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
508 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
515 $ cat other.pid >> $DAEMON_PIDS
509 $ cat other.pid >> $DAEMON_PIDS
516
510
517 Doing the actual push: Abort error
511 Doing the actual push: Abort error
518
512
519 $ cat << EOF >> $HGRCPATH
513 $ cat << EOF >> $HGRCPATH
520 > [failpush]
514 > [failpush]
521 > reason = abort
515 > reason = abort
522 > EOF
516 > EOF
523
517
524 $ hg -R main push other -r e7ec4e813ba6
518 $ hg -R main push other -r e7ec4e813ba6
525 pushing to other
519 pushing to other
526 searching for changes
520 searching for changes
527 abort: Abandon ship!
521 abort: Abandon ship!
528 (don't panic)
522 (don't panic)
529 [255]
523 [255]
530
524
531 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
525 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
532 pushing to ssh://user@dummy/other
526 pushing to ssh://user@dummy/other
533 searching for changes
527 searching for changes
534 remote: Abandon ship!
528 remote: Abandon ship!
535 remote: (don't panic)
529 remote: (don't panic)
536 abort: push failed on remote
530 abort: push failed on remote
537 [255]
531 [255]
538
532
539 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
533 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
540 pushing to http://localhost:$HGPORT2/
534 pushing to http://localhost:$HGPORT2/
541 searching for changes
535 searching for changes
542 remote: Abandon ship!
536 remote: Abandon ship!
543 remote: (don't panic)
537 remote: (don't panic)
544 abort: push failed on remote
538 abort: push failed on remote
545 [255]
539 [255]
546
540
547
541
548 Doing the actual push: unknown mandatory parts
542 Doing the actual push: unknown mandatory parts
549
543
550 $ cat << EOF >> $HGRCPATH
544 $ cat << EOF >> $HGRCPATH
551 > [failpush]
545 > [failpush]
552 > reason = unknown
546 > reason = unknown
553 > EOF
547 > EOF
554
548
555 $ hg -R main push other -r e7ec4e813ba6
549 $ hg -R main push other -r e7ec4e813ba6
556 pushing to other
550 pushing to other
557 searching for changes
551 searching for changes
558 abort: missing support for test:unknown
552 abort: missing support for test:unknown
559 [255]
553 [255]
560
554
561 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
555 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
562 pushing to ssh://user@dummy/other
556 pushing to ssh://user@dummy/other
563 searching for changes
557 searching for changes
564 abort: missing support for test:unknown
558 abort: missing support for test:unknown
565 [255]
559 [255]
566
560
567 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
561 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
568 pushing to http://localhost:$HGPORT2/
562 pushing to http://localhost:$HGPORT2/
569 searching for changes
563 searching for changes
570 abort: missing support for test:unknown
564 abort: missing support for test:unknown
571 [255]
565 [255]
572
566
573 Doing the actual push: race
567 Doing the actual push: race
574
568
575 $ cat << EOF >> $HGRCPATH
569 $ cat << EOF >> $HGRCPATH
576 > [failpush]
570 > [failpush]
577 > reason = race
571 > reason = race
578 > EOF
572 > EOF
579
573
580 $ hg -R main push other -r e7ec4e813ba6
574 $ hg -R main push other -r e7ec4e813ba6
581 pushing to other
575 pushing to other
582 searching for changes
576 searching for changes
583 abort: push failed:
577 abort: push failed:
584 'repository changed while pushing - please try again'
578 'repository changed while pushing - please try again'
585 [255]
579 [255]
586
580
587 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
581 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
588 pushing to ssh://user@dummy/other
582 pushing to ssh://user@dummy/other
589 searching for changes
583 searching for changes
590 abort: push failed:
584 abort: push failed:
591 'repository changed while pushing - please try again'
585 'repository changed while pushing - please try again'
592 [255]
586 [255]
593
587
594 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
588 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
595 pushing to http://localhost:$HGPORT2/
589 pushing to http://localhost:$HGPORT2/
596 searching for changes
590 searching for changes
597 abort: push failed:
591 abort: push failed:
598 'repository changed while pushing - please try again'
592 'repository changed while pushing - please try again'
599 [255]
593 [255]
600
594
601 Doing the actual push: hook abort
595 Doing the actual push: hook abort
602
596
603 $ cat << EOF >> $HGRCPATH
597 $ cat << EOF >> $HGRCPATH
604 > [failpush]
598 > [failpush]
605 > reason =
599 > reason =
606 > [hooks]
600 > [hooks]
607 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
601 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
608 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
602 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
609 > EOF
603 > EOF
610
604
611 $ killdaemons.py
605 $ killdaemons.py
612 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
606 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
613 $ cat other.pid >> $DAEMON_PIDS
607 $ cat other.pid >> $DAEMON_PIDS
614
608
615 $ hg -R main push other -r e7ec4e813ba6
609 $ hg -R main push other -r e7ec4e813ba6
616 pushing to other
610 pushing to other
617 searching for changes
611 searching for changes
618 remote: adding changesets
612 remote: adding changesets
619 remote: adding manifests
613 remote: adding manifests
620 remote: adding file changes
614 remote: adding file changes
621 remote: added 1 changesets with 1 changes to 1 files
615 remote: added 1 changesets with 1 changes to 1 files
622 remote: pre-close-tip:e7ec4e813ba6 draft
616 remote: pre-close-tip:e7ec4e813ba6 draft
623 remote: You shall not pass!
617 remote: You shall not pass!
624 remote: transaction abort!
618 remote: transaction abort!
625 remote: Cleaning up the mess...
619 remote: Cleaning up the mess...
626 remote: rollback completed
620 remote: rollback completed
627 abort: pretxnclose.failpush hook exited with status 1
621 abort: pretxnclose.failpush hook exited with status 1
628 [255]
622 [255]
629
623
630 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
624 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
631 pushing to ssh://user@dummy/other
625 pushing to ssh://user@dummy/other
632 searching for changes
626 searching for changes
633 remote: adding changesets
627 remote: adding changesets
634 remote: adding manifests
628 remote: adding manifests
635 remote: adding file changes
629 remote: adding file changes
636 remote: added 1 changesets with 1 changes to 1 files
630 remote: added 1 changesets with 1 changes to 1 files
637 remote: pre-close-tip:e7ec4e813ba6 draft
631 remote: pre-close-tip:e7ec4e813ba6 draft
638 remote: You shall not pass!
632 remote: You shall not pass!
639 remote: transaction abort!
633 remote: transaction abort!
640 remote: Cleaning up the mess...
634 remote: Cleaning up the mess...
641 remote: rollback completed
635 remote: rollback completed
642 remote: pretxnclose.failpush hook exited with status 1
636 remote: pretxnclose.failpush hook exited with status 1
643 abort: push failed on remote
637 abort: push failed on remote
644 [255]
638 [255]
645
639
646 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
640 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
647 pushing to http://localhost:$HGPORT2/
641 pushing to http://localhost:$HGPORT2/
648 searching for changes
642 searching for changes
649 remote: adding changesets
643 remote: adding changesets
650 remote: adding manifests
644 remote: adding manifests
651 remote: adding file changes
645 remote: adding file changes
652 remote: added 1 changesets with 1 changes to 1 files
646 remote: added 1 changesets with 1 changes to 1 files
653 remote: pre-close-tip:e7ec4e813ba6 draft
647 remote: pre-close-tip:e7ec4e813ba6 draft
654 remote: You shall not pass!
648 remote: You shall not pass!
655 remote: transaction abort!
649 remote: transaction abort!
656 remote: Cleaning up the mess...
650 remote: Cleaning up the mess...
657 remote: rollback completed
651 remote: rollback completed
658 remote: pretxnclose.failpush hook exited with status 1
652 remote: pretxnclose.failpush hook exited with status 1
659 abort: push failed on remote
653 abort: push failed on remote
660 [255]
654 [255]
661
655
662 (check that no 'pending' files remain)
656 (check that no 'pending' files remain)
663
657
664 $ ls -1 other/.hg/bookmarks*
658 $ ls -1 other/.hg/bookmarks*
665 other/.hg/bookmarks
659 other/.hg/bookmarks
666 $ ls -1 other/.hg/store/phaseroots*
660 $ ls -1 other/.hg/store/phaseroots*
667 other/.hg/store/phaseroots
661 other/.hg/store/phaseroots
668 $ ls -1 other/.hg/store/00changelog.i*
662 $ ls -1 other/.hg/store/00changelog.i*
669 other/.hg/store/00changelog.i
663 other/.hg/store/00changelog.i
670
664
671 Check error from hook during the unbundling process itself
665 Check error from hook during the unbundling process itself
672
666
673 $ cat << EOF >> $HGRCPATH
667 $ cat << EOF >> $HGRCPATH
674 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
668 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
675 > EOF
669 > EOF
676 $ killdaemons.py # reload http config
670 $ killdaemons.py # reload http config
677 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
671 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
678 $ cat other.pid >> $DAEMON_PIDS
672 $ cat other.pid >> $DAEMON_PIDS
679
673
680 $ hg -R main push other -r e7ec4e813ba6
674 $ hg -R main push other -r e7ec4e813ba6
681 pushing to other
675 pushing to other
682 searching for changes
676 searching for changes
683 remote: adding changesets
677 remote: adding changesets
684 remote: adding manifests
678 remote: adding manifests
685 remote: adding file changes
679 remote: adding file changes
686 remote: added 1 changesets with 1 changes to 1 files
680 remote: added 1 changesets with 1 changes to 1 files
687 remote: Fail early!
681 remote: Fail early!
688 remote: transaction abort!
682 remote: transaction abort!
689 remote: Cleaning up the mess...
683 remote: Cleaning up the mess...
690 remote: rollback completed
684 remote: rollback completed
691 abort: pretxnchangegroup hook exited with status 1
685 abort: pretxnchangegroup hook exited with status 1
692 [255]
686 [255]
693 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
687 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
694 pushing to ssh://user@dummy/other
688 pushing to ssh://user@dummy/other
695 searching for changes
689 searching for changes
696 remote: adding changesets
690 remote: adding changesets
697 remote: adding manifests
691 remote: adding manifests
698 remote: adding file changes
692 remote: adding file changes
699 remote: added 1 changesets with 1 changes to 1 files
693 remote: added 1 changesets with 1 changes to 1 files
700 remote: Fail early!
694 remote: Fail early!
701 remote: transaction abort!
695 remote: transaction abort!
702 remote: Cleaning up the mess...
696 remote: Cleaning up the mess...
703 remote: rollback completed
697 remote: rollback completed
704 remote: pretxnchangegroup hook exited with status 1
698 remote: pretxnchangegroup hook exited with status 1
705 abort: push failed on remote
699 abort: push failed on remote
706 [255]
700 [255]
707 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
701 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
708 pushing to http://localhost:$HGPORT2/
702 pushing to http://localhost:$HGPORT2/
709 searching for changes
703 searching for changes
710 remote: adding changesets
704 remote: adding changesets
711 remote: adding manifests
705 remote: adding manifests
712 remote: adding file changes
706 remote: adding file changes
713 remote: added 1 changesets with 1 changes to 1 files
707 remote: added 1 changesets with 1 changes to 1 files
714 remote: Fail early!
708 remote: Fail early!
715 remote: transaction abort!
709 remote: transaction abort!
716 remote: Cleaning up the mess...
710 remote: Cleaning up the mess...
717 remote: rollback completed
711 remote: rollback completed
718 remote: pretxnchangegroup hook exited with status 1
712 remote: pretxnchangegroup hook exited with status 1
719 abort: push failed on remote
713 abort: push failed on remote
720 [255]
714 [255]
721
715
722 Check output capture control.
716 Check output capture control.
723
717
724 (should be still forced for http, disabled for local and ssh)
718 (should be still forced for http, disabled for local and ssh)
725
719
726 $ cat >> $HGRCPATH << EOF
720 $ cat >> $HGRCPATH << EOF
727 > [experimental]
721 > [experimental]
728 > bundle2-output-capture=False
722 > bundle2-output-capture=False
729 > EOF
723 > EOF
730
724
731 $ hg -R main push other -r e7ec4e813ba6
725 $ hg -R main push other -r e7ec4e813ba6
732 pushing to other
726 pushing to other
733 searching for changes
727 searching for changes
734 adding changesets
728 adding changesets
735 adding manifests
729 adding manifests
736 adding file changes
730 adding file changes
737 added 1 changesets with 1 changes to 1 files
731 added 1 changesets with 1 changes to 1 files
738 Fail early!
732 Fail early!
739 transaction abort!
733 transaction abort!
740 Cleaning up the mess...
734 Cleaning up the mess...
741 rollback completed
735 rollback completed
742 abort: pretxnchangegroup hook exited with status 1
736 abort: pretxnchangegroup hook exited with status 1
743 [255]
737 [255]
744 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
738 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
745 pushing to ssh://user@dummy/other
739 pushing to ssh://user@dummy/other
746 searching for changes
740 searching for changes
747 remote: adding changesets
741 remote: adding changesets
748 remote: adding manifests
742 remote: adding manifests
749 remote: adding file changes
743 remote: adding file changes
750 remote: added 1 changesets with 1 changes to 1 files
744 remote: added 1 changesets with 1 changes to 1 files
751 remote: Fail early!
745 remote: Fail early!
752 remote: transaction abort!
746 remote: transaction abort!
753 remote: Cleaning up the mess...
747 remote: Cleaning up the mess...
754 remote: rollback completed
748 remote: rollback completed
755 remote: pretxnchangegroup hook exited with status 1
749 remote: pretxnchangegroup hook exited with status 1
756 abort: push failed on remote
750 abort: push failed on remote
757 [255]
751 [255]
758 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
752 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
759 pushing to http://localhost:$HGPORT2/
753 pushing to http://localhost:$HGPORT2/
760 searching for changes
754 searching for changes
761 remote: adding changesets
755 remote: adding changesets
762 remote: adding manifests
756 remote: adding manifests
763 remote: adding file changes
757 remote: adding file changes
764 remote: added 1 changesets with 1 changes to 1 files
758 remote: added 1 changesets with 1 changes to 1 files
765 remote: Fail early!
759 remote: Fail early!
766 remote: transaction abort!
760 remote: transaction abort!
767 remote: Cleaning up the mess...
761 remote: Cleaning up the mess...
768 remote: rollback completed
762 remote: rollback completed
769 remote: pretxnchangegroup hook exited with status 1
763 remote: pretxnchangegroup hook exited with status 1
770 abort: push failed on remote
764 abort: push failed on remote
771 [255]
765 [255]
772
766
773 Check abort from mandatory pushkey
767 Check abort from mandatory pushkey
774
768
775 $ cat > mandatorypart.py << EOF
769 $ cat > mandatorypart.py << EOF
776 > from mercurial import exchange
770 > from mercurial import exchange
777 > from mercurial import pushkey
771 > from mercurial import pushkey
778 > from mercurial import node
772 > from mercurial import node
779 > from mercurial import error
773 > from mercurial import error
780 > @exchange.b2partsgenerator('failingpuskey')
774 > @exchange.b2partsgenerator('failingpuskey')
781 > def addfailingpushey(pushop, bundler):
775 > def addfailingpushey(pushop, bundler):
782 > enc = pushkey.encode
776 > enc = pushkey.encode
783 > part = bundler.newpart('pushkey')
777 > part = bundler.newpart('pushkey')
784 > part.addparam('namespace', enc('phases'))
778 > part.addparam('namespace', enc('phases'))
785 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
779 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
786 > part.addparam('old', enc(str(0))) # successful update
780 > part.addparam('old', enc(str(0))) # successful update
787 > part.addparam('new', enc(str(0)))
781 > part.addparam('new', enc(str(0)))
788 > def fail(pushop, exc):
782 > def fail(pushop, exc):
789 > raise error.Abort('Correct phase push failed (because hooks)')
783 > raise error.Abort('Correct phase push failed (because hooks)')
790 > pushop.pkfailcb[part.id] = fail
784 > pushop.pkfailcb[part.id] = fail
791 > EOF
785 > EOF
792 $ cat >> $HGRCPATH << EOF
786 $ cat >> $HGRCPATH << EOF
793 > [hooks]
787 > [hooks]
794 > pretxnchangegroup=
788 > pretxnchangegroup=
795 > pretxnclose.failpush=
789 > pretxnclose.failpush=
796 > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
790 > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
797 > [extensions]
791 > [extensions]
798 > mandatorypart=$TESTTMP/mandatorypart.py
792 > mandatorypart=$TESTTMP/mandatorypart.py
799 > EOF
793 > EOF
800 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
794 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
801 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
795 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
802 $ cat other.pid >> $DAEMON_PIDS
796 $ cat other.pid >> $DAEMON_PIDS
803
797
804 (Failure from a hook)
798 (Failure from a hook)
805
799
806 $ hg -R main push other -r e7ec4e813ba6
800 $ hg -R main push other -r e7ec4e813ba6
807 pushing to other
801 pushing to other
808 searching for changes
802 searching for changes
809 adding changesets
803 adding changesets
810 adding manifests
804 adding manifests
811 adding file changes
805 adding file changes
812 added 1 changesets with 1 changes to 1 files
806 added 1 changesets with 1 changes to 1 files
813 do not push the key !
807 do not push the key !
814 pushkey-abort: prepushkey.failpush hook exited with status 1
808 pushkey-abort: prepushkey.failpush hook exited with status 1
815 transaction abort!
809 transaction abort!
816 Cleaning up the mess...
810 Cleaning up the mess...
817 rollback completed
811 rollback completed
818 abort: Correct phase push failed (because hooks)
812 abort: Correct phase push failed (because hooks)
819 [255]
813 [255]
820 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
814 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
821 pushing to ssh://user@dummy/other
815 pushing to ssh://user@dummy/other
822 searching for changes
816 searching for changes
823 remote: adding changesets
817 remote: adding changesets
824 remote: adding manifests
818 remote: adding manifests
825 remote: adding file changes
819 remote: adding file changes
826 remote: added 1 changesets with 1 changes to 1 files
820 remote: added 1 changesets with 1 changes to 1 files
827 remote: do not push the key !
821 remote: do not push the key !
828 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
822 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
829 remote: transaction abort!
823 remote: transaction abort!
830 remote: Cleaning up the mess...
824 remote: Cleaning up the mess...
831 remote: rollback completed
825 remote: rollback completed
832 abort: Correct phase push failed (because hooks)
826 abort: Correct phase push failed (because hooks)
833 [255]
827 [255]
834 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
828 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
835 pushing to http://localhost:$HGPORT2/
829 pushing to http://localhost:$HGPORT2/
836 searching for changes
830 searching for changes
837 remote: adding changesets
831 remote: adding changesets
838 remote: adding manifests
832 remote: adding manifests
839 remote: adding file changes
833 remote: adding file changes
840 remote: added 1 changesets with 1 changes to 1 files
834 remote: added 1 changesets with 1 changes to 1 files
841 remote: do not push the key !
835 remote: do not push the key !
842 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
836 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
843 remote: transaction abort!
837 remote: transaction abort!
844 remote: Cleaning up the mess...
838 remote: Cleaning up the mess...
845 remote: rollback completed
839 remote: rollback completed
846 abort: Correct phase push failed (because hooks)
840 abort: Correct phase push failed (because hooks)
847 [255]
841 [255]
848
842
849 (Failure from a the pushkey)
843 (Failure from a the pushkey)
850
844
851 $ cat > mandatorypart.py << EOF
845 $ cat > mandatorypart.py << EOF
852 > from mercurial import exchange
846 > from mercurial import exchange
853 > from mercurial import pushkey
847 > from mercurial import pushkey
854 > from mercurial import node
848 > from mercurial import node
855 > from mercurial import error
849 > from mercurial import error
856 > @exchange.b2partsgenerator('failingpuskey')
850 > @exchange.b2partsgenerator('failingpuskey')
857 > def addfailingpushey(pushop, bundler):
851 > def addfailingpushey(pushop, bundler):
858 > enc = pushkey.encode
852 > enc = pushkey.encode
859 > part = bundler.newpart('pushkey')
853 > part = bundler.newpart('pushkey')
860 > part.addparam('namespace', enc('phases'))
854 > part.addparam('namespace', enc('phases'))
861 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
855 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
862 > part.addparam('old', enc(str(4))) # will fail
856 > part.addparam('old', enc(str(4))) # will fail
863 > part.addparam('new', enc(str(3)))
857 > part.addparam('new', enc(str(3)))
864 > def fail(pushop, exc):
858 > def fail(pushop, exc):
865 > raise error.Abort('Clown phase push failed')
859 > raise error.Abort('Clown phase push failed')
866 > pushop.pkfailcb[part.id] = fail
860 > pushop.pkfailcb[part.id] = fail
867 > EOF
861 > EOF
868 $ cat >> $HGRCPATH << EOF
862 $ cat >> $HGRCPATH << EOF
869 > [hooks]
863 > [hooks]
870 > prepushkey.failpush =
864 > prepushkey.failpush =
871 > EOF
865 > EOF
872 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
866 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
873 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
867 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
874 $ cat other.pid >> $DAEMON_PIDS
868 $ cat other.pid >> $DAEMON_PIDS
875
869
876 $ hg -R main push other -r e7ec4e813ba6
870 $ hg -R main push other -r e7ec4e813ba6
877 pushing to other
871 pushing to other
878 searching for changes
872 searching for changes
879 adding changesets
873 adding changesets
880 adding manifests
874 adding manifests
881 adding file changes
875 adding file changes
882 added 1 changesets with 1 changes to 1 files
876 added 1 changesets with 1 changes to 1 files
883 transaction abort!
877 transaction abort!
884 Cleaning up the mess...
878 Cleaning up the mess...
885 rollback completed
879 rollback completed
886 pushkey: lock state after "phases"
880 pushkey: lock state after "phases"
887 lock: free
881 lock: free
888 wlock: free
882 wlock: free
889 abort: Clown phase push failed
883 abort: Clown phase push failed
890 [255]
884 [255]
891 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
885 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
892 pushing to ssh://user@dummy/other
886 pushing to ssh://user@dummy/other
893 searching for changes
887 searching for changes
894 remote: adding changesets
888 remote: adding changesets
895 remote: adding manifests
889 remote: adding manifests
896 remote: adding file changes
890 remote: adding file changes
897 remote: added 1 changesets with 1 changes to 1 files
891 remote: added 1 changesets with 1 changes to 1 files
898 remote: transaction abort!
892 remote: transaction abort!
899 remote: Cleaning up the mess...
893 remote: Cleaning up the mess...
900 remote: rollback completed
894 remote: rollback completed
901 remote: pushkey: lock state after "phases"
895 remote: pushkey: lock state after "phases"
902 remote: lock: free
896 remote: lock: free
903 remote: wlock: free
897 remote: wlock: free
904 abort: Clown phase push failed
898 abort: Clown phase push failed
905 [255]
899 [255]
906 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
900 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
907 pushing to http://localhost:$HGPORT2/
901 pushing to http://localhost:$HGPORT2/
908 searching for changes
902 searching for changes
909 remote: adding changesets
903 remote: adding changesets
910 remote: adding manifests
904 remote: adding manifests
911 remote: adding file changes
905 remote: adding file changes
912 remote: added 1 changesets with 1 changes to 1 files
906 remote: added 1 changesets with 1 changes to 1 files
913 remote: transaction abort!
907 remote: transaction abort!
914 remote: Cleaning up the mess...
908 remote: Cleaning up the mess...
915 remote: rollback completed
909 remote: rollback completed
916 remote: pushkey: lock state after "phases"
910 remote: pushkey: lock state after "phases"
917 remote: lock: free
911 remote: lock: free
918 remote: wlock: free
912 remote: wlock: free
919 abort: Clown phase push failed
913 abort: Clown phase push failed
920 [255]
914 [255]
921
915
922 Test lazily acquiring the lock during unbundle
916 Test lazily acquiring the lock during unbundle
923 $ cp $TESTTMP/hgrc.orig $HGRCPATH
917 $ cp $TESTTMP/hgrc.orig $HGRCPATH
924 $ cat >> $HGRCPATH <<EOF
918 $ cat >> $HGRCPATH <<EOF
925 > [ui]
919 > [ui]
926 > ssh="$PYTHON" "$TESTDIR/dummyssh"
920 > ssh="$PYTHON" "$TESTDIR/dummyssh"
927 > EOF
921 > EOF
928
922
929 $ cat >> $TESTTMP/locktester.py <<EOF
923 $ cat >> $TESTTMP/locktester.py <<EOF
930 > import os
924 > import os
931 > from mercurial import extensions, bundle2, util
925 > from mercurial import extensions, bundle2, util
932 > def checklock(orig, repo, *args, **kwargs):
926 > def checklock(orig, repo, *args, **kwargs):
933 > if repo.svfs.lexists("lock"):
927 > if repo.svfs.lexists("lock"):
934 > raise util.Abort("Lock should not be taken")
928 > raise util.Abort("Lock should not be taken")
935 > return orig(repo, *args, **kwargs)
929 > return orig(repo, *args, **kwargs)
936 > def extsetup(ui):
930 > def extsetup(ui):
937 > extensions.wrapfunction(bundle2, 'processbundle', checklock)
931 > extensions.wrapfunction(bundle2, 'processbundle', checklock)
938 > EOF
932 > EOF
939
933
940 $ hg init lazylock
934 $ hg init lazylock
941 $ cat >> lazylock/.hg/hgrc <<EOF
935 $ cat >> lazylock/.hg/hgrc <<EOF
942 > [extensions]
936 > [extensions]
943 > locktester=$TESTTMP/locktester.py
937 > locktester=$TESTTMP/locktester.py
944 > EOF
938 > EOF
945
939
946 $ hg clone -q ssh://user@dummy/lazylock lazylockclient
940 $ hg clone -q ssh://user@dummy/lazylock lazylockclient
947 $ cd lazylockclient
941 $ cd lazylockclient
948 $ touch a && hg ci -Aqm a
942 $ touch a && hg ci -Aqm a
949 $ hg push
943 $ hg push
950 pushing to ssh://user@dummy/lazylock
944 pushing to ssh://user@dummy/lazylock
951 searching for changes
945 searching for changes
952 remote: Lock should not be taken
946 remote: Lock should not be taken
953 abort: push failed on remote
947 abort: push failed on remote
954 [255]
948 [255]
955
949
956 $ cat >> ../lazylock/.hg/hgrc <<EOF
950 $ cat >> ../lazylock/.hg/hgrc <<EOF
957 > [experimental]
951 > [experimental]
958 > bundle2lazylocking=True
952 > bundle2lazylocking=True
959 > EOF
953 > EOF
960 $ hg push
954 $ hg push
961 pushing to ssh://user@dummy/lazylock
955 pushing to ssh://user@dummy/lazylock
962 searching for changes
956 searching for changes
963 remote: adding changesets
957 remote: adding changesets
964 remote: adding manifests
958 remote: adding manifests
965 remote: adding file changes
959 remote: adding file changes
966 remote: added 1 changesets with 1 changes to 1 files
960 remote: added 1 changesets with 1 changes to 1 files
967
961
968 $ cd ..
962 $ cd ..
969
963
970 Servers can disable bundle1 for clone/pull operations
964 Servers can disable bundle1 for clone/pull operations
971
965
972 $ killdaemons.py
966 $ killdaemons.py
973 $ hg init bundle2onlyserver
967 $ hg init bundle2onlyserver
974 $ cd bundle2onlyserver
968 $ cd bundle2onlyserver
975 $ cat > .hg/hgrc << EOF
969 $ cat > .hg/hgrc << EOF
976 > [server]
970 > [server]
977 > bundle1.pull = false
971 > bundle1.pull = false
978 > EOF
972 > EOF
979
973
980 $ touch foo
974 $ touch foo
981 $ hg -q commit -A -m initial
975 $ hg -q commit -A -m initial
982
976
983 $ hg serve -p $HGPORT -d --pid-file=hg.pid
977 $ hg serve -p $HGPORT -d --pid-file=hg.pid
984 $ cat hg.pid >> $DAEMON_PIDS
978 $ cat hg.pid >> $DAEMON_PIDS
985
979
986 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
980 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
987 requesting all changes
981 requesting all changes
988 abort: remote error:
982 abort: remote error:
989 incompatible Mercurial client; bundle2 required
983 incompatible Mercurial client; bundle2 required
990 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
984 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
991 [255]
985 [255]
992 $ killdaemons.py
986 $ killdaemons.py
993 $ cd ..
987 $ cd ..
994
988
995 bundle1 can still pull non-generaldelta repos when generaldelta bundle1 disabled
989 bundle1 can still pull non-generaldelta repos when generaldelta bundle1 disabled
996
990
997 $ hg --config format.usegeneraldelta=false init notgdserver
991 $ hg --config format.usegeneraldelta=false init notgdserver
998 $ cd notgdserver
992 $ cd notgdserver
999 $ cat > .hg/hgrc << EOF
993 $ cat > .hg/hgrc << EOF
1000 > [server]
994 > [server]
1001 > bundle1gd.pull = false
995 > bundle1gd.pull = false
1002 > EOF
996 > EOF
1003
997
1004 $ touch foo
998 $ touch foo
1005 $ hg -q commit -A -m initial
999 $ hg -q commit -A -m initial
1006 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1000 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1007 $ cat hg.pid >> $DAEMON_PIDS
1001 $ cat hg.pid >> $DAEMON_PIDS
1008
1002
1009 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-1
1003 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-1
1010 requesting all changes
1004 requesting all changes
1011 adding changesets
1005 adding changesets
1012 adding manifests
1006 adding manifests
1013 adding file changes
1007 adding file changes
1014 added 1 changesets with 1 changes to 1 files
1008 added 1 changesets with 1 changes to 1 files
1015 new changesets 96ee1d7354c4
1009 new changesets 96ee1d7354c4
1016 updating to branch default
1010 updating to branch default
1017 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1011 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1018
1012
1019 $ killdaemons.py
1013 $ killdaemons.py
1020 $ cd ../bundle2onlyserver
1014 $ cd ../bundle2onlyserver
1021
1015
1022 bundle1 pull can be disabled for generaldelta repos only
1016 bundle1 pull can be disabled for generaldelta repos only
1023
1017
1024 $ cat > .hg/hgrc << EOF
1018 $ cat > .hg/hgrc << EOF
1025 > [server]
1019 > [server]
1026 > bundle1gd.pull = false
1020 > bundle1gd.pull = false
1027 > EOF
1021 > EOF
1028
1022
1029 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1023 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1030 $ cat hg.pid >> $DAEMON_PIDS
1024 $ cat hg.pid >> $DAEMON_PIDS
1031 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1025 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1032 requesting all changes
1026 requesting all changes
1033 abort: remote error:
1027 abort: remote error:
1034 incompatible Mercurial client; bundle2 required
1028 incompatible Mercurial client; bundle2 required
1035 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1029 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1036 [255]
1030 [255]
1037
1031
1038 $ killdaemons.py
1032 $ killdaemons.py
1039
1033
1040 Verify the global server.bundle1 option works
1034 Verify the global server.bundle1 option works
1041
1035
1042 $ cd ..
1036 $ cd ..
1043 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1037 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1044 > [server]
1038 > [server]
1045 > bundle1 = false
1039 > bundle1 = false
1046 > EOF
1040 > EOF
1047 $ hg serve -R bundle2onlyserver -p $HGPORT -d --pid-file=hg.pid
1041 $ hg serve -R bundle2onlyserver -p $HGPORT -d --pid-file=hg.pid
1048 $ cat hg.pid >> $DAEMON_PIDS
1042 $ cat hg.pid >> $DAEMON_PIDS
1049 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT not-bundle2
1043 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT not-bundle2
1050 requesting all changes
1044 requesting all changes
1051 abort: remote error:
1045 abort: remote error:
1052 incompatible Mercurial client; bundle2 required
1046 incompatible Mercurial client; bundle2 required
1053 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1047 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1054 [255]
1048 [255]
1055 $ killdaemons.py
1049 $ killdaemons.py
1056
1050
1057 $ hg --config devel.legacy.exchange=bundle1 clone ssh://user@dummy/bundle2onlyserver not-bundle2-ssh
1051 $ hg --config devel.legacy.exchange=bundle1 clone ssh://user@dummy/bundle2onlyserver not-bundle2-ssh
1058 requesting all changes
1052 requesting all changes
1059 adding changesets
1053 adding changesets
1060 remote: abort: incompatible Mercurial client; bundle2 required
1054 remote: abort: incompatible Mercurial client; bundle2 required
1061 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1055 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1062 transaction abort!
1056 transaction abort!
1063 rollback completed
1057 rollback completed
1064 abort: stream ended unexpectedly (got 0 bytes, expected 4)
1058 abort: stream ended unexpectedly (got 0 bytes, expected 4)
1065 [255]
1059 [255]
1066
1060
1067 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1061 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1068 > [server]
1062 > [server]
1069 > bundle1gd = false
1063 > bundle1gd = false
1070 > EOF
1064 > EOF
1071 $ hg serve -R bundle2onlyserver -p $HGPORT -d --pid-file=hg.pid
1065 $ hg serve -R bundle2onlyserver -p $HGPORT -d --pid-file=hg.pid
1072 $ cat hg.pid >> $DAEMON_PIDS
1066 $ cat hg.pid >> $DAEMON_PIDS
1073
1067
1074 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1068 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1075 requesting all changes
1069 requesting all changes
1076 abort: remote error:
1070 abort: remote error:
1077 incompatible Mercurial client; bundle2 required
1071 incompatible Mercurial client; bundle2 required
1078 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1072 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1079 [255]
1073 [255]
1080
1074
1081 $ killdaemons.py
1075 $ killdaemons.py
1082
1076
1083 $ cd notgdserver
1077 $ cd notgdserver
1084 $ cat > .hg/hgrc << EOF
1078 $ cat > .hg/hgrc << EOF
1085 > [server]
1079 > [server]
1086 > bundle1gd = false
1080 > bundle1gd = false
1087 > EOF
1081 > EOF
1088 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1082 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1089 $ cat hg.pid >> $DAEMON_PIDS
1083 $ cat hg.pid >> $DAEMON_PIDS
1090
1084
1091 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-2
1085 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-2
1092 requesting all changes
1086 requesting all changes
1093 adding changesets
1087 adding changesets
1094 adding manifests
1088 adding manifests
1095 adding file changes
1089 adding file changes
1096 added 1 changesets with 1 changes to 1 files
1090 added 1 changesets with 1 changes to 1 files
1097 new changesets 96ee1d7354c4
1091 new changesets 96ee1d7354c4
1098 updating to branch default
1092 updating to branch default
1099 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1093 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1100
1094
1101 $ killdaemons.py
1095 $ killdaemons.py
1102 $ cd ../bundle2onlyserver
1096 $ cd ../bundle2onlyserver
1103
1097
1104 Verify bundle1 pushes can be disabled
1098 Verify bundle1 pushes can be disabled
1105
1099
1106 $ cat > .hg/hgrc << EOF
1100 $ cat > .hg/hgrc << EOF
1107 > [server]
1101 > [server]
1108 > bundle1.push = false
1102 > bundle1.push = false
1109 > [web]
1103 > [web]
1110 > allow_push = *
1104 > allow_push = *
1111 > push_ssl = false
1105 > push_ssl = false
1112 > EOF
1106 > EOF
1113
1107
1114 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E error.log
1108 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E error.log
1115 $ cat hg.pid >> $DAEMON_PIDS
1109 $ cat hg.pid >> $DAEMON_PIDS
1116 $ cd ..
1110 $ cd ..
1117
1111
1118 $ hg clone http://localhost:$HGPORT bundle2-only
1112 $ hg clone http://localhost:$HGPORT bundle2-only
1119 requesting all changes
1113 requesting all changes
1120 adding changesets
1114 adding changesets
1121 adding manifests
1115 adding manifests
1122 adding file changes
1116 adding file changes
1123 added 1 changesets with 1 changes to 1 files
1117 added 1 changesets with 1 changes to 1 files
1124 new changesets 96ee1d7354c4
1118 new changesets 96ee1d7354c4
1125 updating to branch default
1119 updating to branch default
1126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1127 $ cd bundle2-only
1121 $ cd bundle2-only
1128 $ echo commit > foo
1122 $ echo commit > foo
1129 $ hg commit -m commit
1123 $ hg commit -m commit
1130 $ hg --config devel.legacy.exchange=bundle1 push
1124 $ hg --config devel.legacy.exchange=bundle1 push
1131 pushing to http://localhost:$HGPORT/
1125 pushing to http://localhost:$HGPORT/
1132 searching for changes
1126 searching for changes
1133 abort: remote error:
1127 abort: remote error:
1134 incompatible Mercurial client; bundle2 required
1128 incompatible Mercurial client; bundle2 required
1135 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1129 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1136 [255]
1130 [255]
1137
1131
1138 (also check with ssh)
1132 (also check with ssh)
1139
1133
1140 $ hg --config devel.legacy.exchange=bundle1 push ssh://user@dummy/bundle2onlyserver
1134 $ hg --config devel.legacy.exchange=bundle1 push ssh://user@dummy/bundle2onlyserver
1141 pushing to ssh://user@dummy/bundle2onlyserver
1135 pushing to ssh://user@dummy/bundle2onlyserver
1142 searching for changes
1136 searching for changes
1143 remote: abort: incompatible Mercurial client; bundle2 required
1137 remote: abort: incompatible Mercurial client; bundle2 required
1144 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1138 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1145 [1]
1139 [1]
1146
1140
1147 $ hg push
1141 $ hg push
1148 pushing to http://localhost:$HGPORT/
1142 pushing to http://localhost:$HGPORT/
1149 searching for changes
1143 searching for changes
1150 remote: adding changesets
1144 remote: adding changesets
1151 remote: adding manifests
1145 remote: adding manifests
1152 remote: adding file changes
1146 remote: adding file changes
1153 remote: added 1 changesets with 1 changes to 1 files
1147 remote: added 1 changesets with 1 changes to 1 files
@@ -1,198 +1,198
1 #require killdaemons
1 #require killdaemons
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -Ama
6 $ hg ci -Ama
7 adding a
7 adding a
8 $ cd ..
8 $ cd ..
9 $ hg clone test test2
9 $ hg clone test test2
10 updating to branch default
10 updating to branch default
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 $ cd test2
12 $ cd test2
13 $ echo a >> a
13 $ echo a >> a
14 $ hg ci -mb
14 $ hg ci -mb
15 $ req() {
15 $ req() {
16 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
16 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
17 > cat hg.pid >> $DAEMON_PIDS
17 > cat hg.pid >> $DAEMON_PIDS
18 > hg --cwd ../test2 push http://localhost:$HGPORT/
18 > hg --cwd ../test2 push http://localhost:$HGPORT/
19 > exitstatus=$?
19 > exitstatus=$?
20 > killdaemons.py
20 > killdaemons.py
21 > echo % serve errors
21 > echo % serve errors
22 > cat errors.log
22 > cat errors.log
23 > return $exitstatus
23 > return $exitstatus
24 > }
24 > }
25 $ cd ../test
25 $ cd ../test
26
26
27 expect ssl error
27 expect ssl error
28
28
29 $ req
29 $ req
30 pushing to http://localhost:$HGPORT/
30 pushing to http://localhost:$HGPORT/
31 searching for changes
31 searching for changes
32 abort: HTTP Error 403: ssl required
32 abort: HTTP Error 403: ssl required
33 % serve errors
33 % serve errors
34 [255]
34 [255]
35
35
36 expect authorization error
36 expect authorization error
37
37
38 $ echo '[web]' > .hg/hgrc
38 $ echo '[web]' > .hg/hgrc
39 $ echo 'push_ssl = false' >> .hg/hgrc
39 $ echo 'push_ssl = false' >> .hg/hgrc
40 $ req
40 $ req
41 pushing to http://localhost:$HGPORT/
41 pushing to http://localhost:$HGPORT/
42 searching for changes
42 searching for changes
43 abort: authorization failed
43 abort: authorization failed
44 % serve errors
44 % serve errors
45 [255]
45 [255]
46
46
47 expect authorization error: must have authorized user
47 expect authorization error: must have authorized user
48
48
49 $ echo 'allow_push = unperson' >> .hg/hgrc
49 $ echo 'allow_push = unperson' >> .hg/hgrc
50 $ req
50 $ req
51 pushing to http://localhost:$HGPORT/
51 pushing to http://localhost:$HGPORT/
52 searching for changes
52 searching for changes
53 abort: authorization failed
53 abort: authorization failed
54 % serve errors
54 % serve errors
55 [255]
55 [255]
56
56
57 expect success
57 expect success
58
58
59 $ cat >> .hg/hgrc <<EOF
59 $ cat >> .hg/hgrc <<EOF
60 > allow_push = *
60 > allow_push = *
61 > [hooks]
61 > [hooks]
62 > changegroup = sh -c "printenv.py changegroup 0"
62 > changegroup = sh -c "printenv.py changegroup 0"
63 > pushkey = sh -c "printenv.py pushkey 0"
63 > pushkey = sh -c "printenv.py pushkey 0"
64 > txnclose-phase.test = echo "phase-move: \$HG_NODE: \$HG_OLDPHASE -> \$HG_PHASE"
64 > txnclose-phase.test = echo "phase-move: \$HG_NODE: \$HG_OLDPHASE -> \$HG_PHASE"
65 > EOF
65 > EOF
66 $ req
66 $ req
67 pushing to http://localhost:$HGPORT/
67 pushing to http://localhost:$HGPORT/
68 searching for changes
68 searching for changes
69 remote: adding changesets
69 remote: adding changesets
70 remote: adding manifests
70 remote: adding manifests
71 remote: adding file changes
71 remote: adding file changes
72 remote: added 1 changesets with 1 changes to 1 files
72 remote: added 1 changesets with 1 changes to 1 files
73 remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
74 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
73 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
75 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
74 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
76 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
75 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
77 % serve errors
76 % serve errors
78 $ hg rollback
77 $ hg rollback
79 repository tip rolled back to revision 0 (undo serve)
78 repository tip rolled back to revision 0 (undo serve)
80
79
81 expect success, server lacks the httpheader capability
80 expect success, server lacks the httpheader capability
82
81
83 $ CAP=httpheader
82 $ CAP=httpheader
84 $ . "$TESTDIR/notcapable"
83 $ . "$TESTDIR/notcapable"
85 $ req
84 $ req
86 pushing to http://localhost:$HGPORT/
85 pushing to http://localhost:$HGPORT/
87 searching for changes
86 searching for changes
88 remote: adding changesets
87 remote: adding changesets
89 remote: adding manifests
88 remote: adding manifests
90 remote: adding file changes
89 remote: adding file changes
91 remote: added 1 changesets with 1 changes to 1 files
90 remote: added 1 changesets with 1 changes to 1 files
92 remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
93 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
91 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
94 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
92 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
95 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
93 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
96 % serve errors
94 % serve errors
97 $ hg rollback
95 $ hg rollback
98 repository tip rolled back to revision 0 (undo serve)
96 repository tip rolled back to revision 0 (undo serve)
99
97
100 expect success, server lacks the unbundlehash capability
98 expect success, server lacks the unbundlehash capability
101
99
102 $ CAP=unbundlehash
100 $ CAP=unbundlehash
103 $ . "$TESTDIR/notcapable"
101 $ . "$TESTDIR/notcapable"
104 $ req
102 $ req
105 pushing to http://localhost:$HGPORT/
103 pushing to http://localhost:$HGPORT/
106 searching for changes
104 searching for changes
107 remote: adding changesets
105 remote: adding changesets
108 remote: adding manifests
106 remote: adding manifests
109 remote: adding file changes
107 remote: adding file changes
110 remote: added 1 changesets with 1 changes to 1 files
108 remote: added 1 changesets with 1 changes to 1 files
111 remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
112 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
109 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
113 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
110 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
114 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
111 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
115 % serve errors
112 % serve errors
116 $ hg rollback
113 $ hg rollback
117 repository tip rolled back to revision 0 (undo serve)
114 repository tip rolled back to revision 0 (undo serve)
118
115
119 expect push success, phase change failure
116 expect push success, phase change failure
120
117
121 $ cat > .hg/hgrc <<EOF
118 $ cat > .hg/hgrc <<EOF
122 > [web]
119 > [web]
123 > push_ssl = false
120 > push_ssl = false
124 > allow_push = *
121 > allow_push = *
125 > [hooks]
122 > [hooks]
126 > prepushkey = sh -c "printenv.py prepushkey 1"
123 > prepushkey = sh -c "printenv.py prepushkey 1"
124 > [devel]
125 > legacy.exchange=phases
127 > EOF
126 > EOF
128 $ req
127 $ req
129 pushing to http://localhost:$HGPORT/
128 pushing to http://localhost:$HGPORT/
130 searching for changes
129 searching for changes
131 remote: adding changesets
130 remote: adding changesets
132 remote: adding manifests
131 remote: adding manifests
133 remote: adding file changes
132 remote: adding file changes
134 remote: added 1 changesets with 1 changes to 1 files
133 remote: added 1 changesets with 1 changes to 1 files
135 remote: prepushkey hook: HG_BUNDLE2=1 HG_HOOKNAME=prepushkey HG_HOOKTYPE=prepushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
134 remote: prepushkey hook: HG_BUNDLE2=1 HG_HOOKNAME=prepushkey HG_HOOKTYPE=prepushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
136 remote: pushkey-abort: prepushkey hook exited with status 1
135 remote: pushkey-abort: prepushkey hook exited with status 1
137 remote: transaction abort!
136 remote: transaction abort!
138 remote: rollback completed
137 remote: rollback completed
139 abort: updating ba677d0156c1 to public failed
138 abort: updating ba677d0156c1 to public failed
140 % serve errors
139 % serve errors
141 [255]
140 [255]
142
141
143 expect phase change success
142 expect phase change success
144
143
145 $ cat >> .hg/hgrc <<EOF
144 $ cat >> .hg/hgrc <<EOF
146 > prepushkey = sh -c "printenv.py prepushkey 0"
145 > prepushkey = sh -c "printenv.py prepushkey 0"
146 > [devel]
147 > legacy.exchange=
147 > EOF
148 > EOF
148 $ req
149 $ req
149 pushing to http://localhost:$HGPORT/
150 pushing to http://localhost:$HGPORT/
150 searching for changes
151 searching for changes
151 remote: adding changesets
152 remote: adding changesets
152 remote: adding manifests
153 remote: adding manifests
153 remote: adding file changes
154 remote: adding file changes
154 remote: added 1 changesets with 1 changes to 1 files
155 remote: added 1 changesets with 1 changes to 1 files
155 remote: prepushkey hook: HG_BUNDLE2=1 HG_HOOKNAME=prepushkey HG_HOOKTYPE=prepushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
156 % serve errors
156 % serve errors
157 $ hg rollback
157 $ hg rollback
158 repository tip rolled back to revision 0 (undo serve)
158 repository tip rolled back to revision 0 (undo serve)
159
159
160 expect authorization error: all users denied
160 expect authorization error: all users denied
161
161
162 $ echo '[web]' > .hg/hgrc
162 $ echo '[web]' > .hg/hgrc
163 $ echo 'push_ssl = false' >> .hg/hgrc
163 $ echo 'push_ssl = false' >> .hg/hgrc
164 $ echo 'deny_push = *' >> .hg/hgrc
164 $ echo 'deny_push = *' >> .hg/hgrc
165 $ req
165 $ req
166 pushing to http://localhost:$HGPORT/
166 pushing to http://localhost:$HGPORT/
167 searching for changes
167 searching for changes
168 abort: authorization failed
168 abort: authorization failed
169 % serve errors
169 % serve errors
170 [255]
170 [255]
171
171
172 expect authorization error: some users denied, users must be authenticated
172 expect authorization error: some users denied, users must be authenticated
173
173
174 $ echo 'deny_push = unperson' >> .hg/hgrc
174 $ echo 'deny_push = unperson' >> .hg/hgrc
175 $ req
175 $ req
176 pushing to http://localhost:$HGPORT/
176 pushing to http://localhost:$HGPORT/
177 searching for changes
177 searching for changes
178 abort: authorization failed
178 abort: authorization failed
179 % serve errors
179 % serve errors
180 [255]
180 [255]
181
181
182 $ cat > .hg/hgrc <<EOF
182 $ cat > .hg/hgrc <<EOF
183 > [web]
183 > [web]
184 > push_ssl = false
184 > push_ssl = false
185 > allow_push = *
185 > allow_push = *
186 > [experimental]
186 > [experimental]
187 > httppostargs=true
187 > httppostargs=true
188 > EOF
188 > EOF
189 $ req
189 $ req
190 pushing to http://localhost:$HGPORT/
190 pushing to http://localhost:$HGPORT/
191 searching for changes
191 searching for changes
192 remote: adding changesets
192 remote: adding changesets
193 remote: adding manifests
193 remote: adding manifests
194 remote: adding file changes
194 remote: adding file changes
195 remote: added 1 changesets with 1 changes to 1 files
195 remote: added 1 changesets with 1 changes to 1 files
196 % serve errors
196 % serve errors
197
197
198 $ cd ..
198 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now