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