##// END OF EJS Templates
errors: raise InputError on bad bookmark argument...
Martin von Zweigbergk -
r46525:9acbe309 default
parent child Browse files
Show More
@@ -1,1060 +1,1060 b''
1 # Mercurial bookmark support code
1 # Mercurial bookmark support code
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.net>
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 errno
10 import errno
11 import struct
11 import struct
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 bin,
15 bin,
16 hex,
16 hex,
17 short,
17 short,
18 wdirid,
18 wdirid,
19 )
19 )
20 from .pycompat import getattr
20 from .pycompat import getattr
21 from . import (
21 from . import (
22 encoding,
22 encoding,
23 error,
23 error,
24 obsutil,
24 obsutil,
25 pycompat,
25 pycompat,
26 scmutil,
26 scmutil,
27 txnutil,
27 txnutil,
28 util,
28 util,
29 )
29 )
30
30
31 # label constants
31 # label constants
32 # until 3.5, bookmarks.current was the advertised name, not
32 # until 3.5, bookmarks.current was the advertised name, not
33 # bookmarks.active, so we must use both to avoid breaking old
33 # bookmarks.active, so we must use both to avoid breaking old
34 # custom styles
34 # custom styles
35 activebookmarklabel = b'bookmarks.active bookmarks.current'
35 activebookmarklabel = b'bookmarks.active bookmarks.current'
36
36
37 BOOKMARKS_IN_STORE_REQUIREMENT = b'bookmarksinstore'
37 BOOKMARKS_IN_STORE_REQUIREMENT = b'bookmarksinstore'
38
38
39
39
40 def bookmarksinstore(repo):
40 def bookmarksinstore(repo):
41 return BOOKMARKS_IN_STORE_REQUIREMENT in repo.requirements
41 return BOOKMARKS_IN_STORE_REQUIREMENT in repo.requirements
42
42
43
43
44 def bookmarksvfs(repo):
44 def bookmarksvfs(repo):
45 return repo.svfs if bookmarksinstore(repo) else repo.vfs
45 return repo.svfs if bookmarksinstore(repo) else repo.vfs
46
46
47
47
48 def _getbkfile(repo):
48 def _getbkfile(repo):
49 """Hook so that extensions that mess with the store can hook bm storage.
49 """Hook so that extensions that mess with the store can hook bm storage.
50
50
51 For core, this just handles wether we should see pending
51 For core, this just handles wether we should see pending
52 bookmarks or the committed ones. Other extensions (like share)
52 bookmarks or the committed ones. Other extensions (like share)
53 may need to tweak this behavior further.
53 may need to tweak this behavior further.
54 """
54 """
55 fp, pending = txnutil.trypending(
55 fp, pending = txnutil.trypending(
56 repo.root, bookmarksvfs(repo), b'bookmarks'
56 repo.root, bookmarksvfs(repo), b'bookmarks'
57 )
57 )
58 return fp
58 return fp
59
59
60
60
61 class bmstore(object):
61 class bmstore(object):
62 r"""Storage for bookmarks.
62 r"""Storage for bookmarks.
63
63
64 This object should do all bookmark-related reads and writes, so
64 This object should do all bookmark-related reads and writes, so
65 that it's fairly simple to replace the storage underlying
65 that it's fairly simple to replace the storage underlying
66 bookmarks without having to clone the logic surrounding
66 bookmarks without having to clone the logic surrounding
67 bookmarks. This type also should manage the active bookmark, if
67 bookmarks. This type also should manage the active bookmark, if
68 any.
68 any.
69
69
70 This particular bmstore implementation stores bookmarks as
70 This particular bmstore implementation stores bookmarks as
71 {hash}\s{name}\n (the same format as localtags) in
71 {hash}\s{name}\n (the same format as localtags) in
72 .hg/bookmarks. The mapping is stored as {name: nodeid}.
72 .hg/bookmarks. The mapping is stored as {name: nodeid}.
73 """
73 """
74
74
75 def __init__(self, repo):
75 def __init__(self, repo):
76 self._repo = repo
76 self._repo = repo
77 self._refmap = refmap = {} # refspec: node
77 self._refmap = refmap = {} # refspec: node
78 self._nodemap = nodemap = {} # node: sorted([refspec, ...])
78 self._nodemap = nodemap = {} # node: sorted([refspec, ...])
79 self._clean = True
79 self._clean = True
80 self._aclean = True
80 self._aclean = True
81 has_node = repo.changelog.index.has_node
81 has_node = repo.changelog.index.has_node
82 tonode = bin # force local lookup
82 tonode = bin # force local lookup
83 try:
83 try:
84 with _getbkfile(repo) as bkfile:
84 with _getbkfile(repo) as bkfile:
85 for line in bkfile:
85 for line in bkfile:
86 line = line.strip()
86 line = line.strip()
87 if not line:
87 if not line:
88 continue
88 continue
89 try:
89 try:
90 sha, refspec = line.split(b' ', 1)
90 sha, refspec = line.split(b' ', 1)
91 node = tonode(sha)
91 node = tonode(sha)
92 if has_node(node):
92 if has_node(node):
93 refspec = encoding.tolocal(refspec)
93 refspec = encoding.tolocal(refspec)
94 refmap[refspec] = node
94 refmap[refspec] = node
95 nrefs = nodemap.get(node)
95 nrefs = nodemap.get(node)
96 if nrefs is None:
96 if nrefs is None:
97 nodemap[node] = [refspec]
97 nodemap[node] = [refspec]
98 else:
98 else:
99 nrefs.append(refspec)
99 nrefs.append(refspec)
100 if nrefs[-2] > refspec:
100 if nrefs[-2] > refspec:
101 # bookmarks weren't sorted before 4.5
101 # bookmarks weren't sorted before 4.5
102 nrefs.sort()
102 nrefs.sort()
103 except (TypeError, ValueError):
103 except (TypeError, ValueError):
104 # TypeError:
104 # TypeError:
105 # - bin(...)
105 # - bin(...)
106 # ValueError:
106 # ValueError:
107 # - node in nm, for non-20-bytes entry
107 # - node in nm, for non-20-bytes entry
108 # - split(...), for string without ' '
108 # - split(...), for string without ' '
109 bookmarkspath = b'.hg/bookmarks'
109 bookmarkspath = b'.hg/bookmarks'
110 if bookmarksinstore(repo):
110 if bookmarksinstore(repo):
111 bookmarkspath = b'.hg/store/bookmarks'
111 bookmarkspath = b'.hg/store/bookmarks'
112 repo.ui.warn(
112 repo.ui.warn(
113 _(b'malformed line in %s: %r\n')
113 _(b'malformed line in %s: %r\n')
114 % (bookmarkspath, pycompat.bytestr(line))
114 % (bookmarkspath, pycompat.bytestr(line))
115 )
115 )
116 except IOError as inst:
116 except IOError as inst:
117 if inst.errno != errno.ENOENT:
117 if inst.errno != errno.ENOENT:
118 raise
118 raise
119 self._active = _readactive(repo, self)
119 self._active = _readactive(repo, self)
120
120
121 @property
121 @property
122 def active(self):
122 def active(self):
123 return self._active
123 return self._active
124
124
125 @active.setter
125 @active.setter
126 def active(self, mark):
126 def active(self, mark):
127 if mark is not None and mark not in self._refmap:
127 if mark is not None and mark not in self._refmap:
128 raise AssertionError(b'bookmark %s does not exist!' % mark)
128 raise AssertionError(b'bookmark %s does not exist!' % mark)
129
129
130 self._active = mark
130 self._active = mark
131 self._aclean = False
131 self._aclean = False
132
132
133 def __len__(self):
133 def __len__(self):
134 return len(self._refmap)
134 return len(self._refmap)
135
135
136 def __iter__(self):
136 def __iter__(self):
137 return iter(self._refmap)
137 return iter(self._refmap)
138
138
139 def iteritems(self):
139 def iteritems(self):
140 return pycompat.iteritems(self._refmap)
140 return pycompat.iteritems(self._refmap)
141
141
142 def items(self):
142 def items(self):
143 return self._refmap.items()
143 return self._refmap.items()
144
144
145 # TODO: maybe rename to allnames()?
145 # TODO: maybe rename to allnames()?
146 def keys(self):
146 def keys(self):
147 return self._refmap.keys()
147 return self._refmap.keys()
148
148
149 # TODO: maybe rename to allnodes()? but nodes would have to be deduplicated
149 # TODO: maybe rename to allnodes()? but nodes would have to be deduplicated
150 # could be self._nodemap.keys()
150 # could be self._nodemap.keys()
151 def values(self):
151 def values(self):
152 return self._refmap.values()
152 return self._refmap.values()
153
153
154 def __contains__(self, mark):
154 def __contains__(self, mark):
155 return mark in self._refmap
155 return mark in self._refmap
156
156
157 def __getitem__(self, mark):
157 def __getitem__(self, mark):
158 return self._refmap[mark]
158 return self._refmap[mark]
159
159
160 def get(self, mark, default=None):
160 def get(self, mark, default=None):
161 return self._refmap.get(mark, default)
161 return self._refmap.get(mark, default)
162
162
163 def _set(self, mark, node):
163 def _set(self, mark, node):
164 self._clean = False
164 self._clean = False
165 if mark in self._refmap:
165 if mark in self._refmap:
166 self._del(mark)
166 self._del(mark)
167 self._refmap[mark] = node
167 self._refmap[mark] = node
168 nrefs = self._nodemap.get(node)
168 nrefs = self._nodemap.get(node)
169 if nrefs is None:
169 if nrefs is None:
170 self._nodemap[node] = [mark]
170 self._nodemap[node] = [mark]
171 else:
171 else:
172 nrefs.append(mark)
172 nrefs.append(mark)
173 nrefs.sort()
173 nrefs.sort()
174
174
175 def _del(self, mark):
175 def _del(self, mark):
176 if mark not in self._refmap:
176 if mark not in self._refmap:
177 return
177 return
178 self._clean = False
178 self._clean = False
179 node = self._refmap.pop(mark)
179 node = self._refmap.pop(mark)
180 nrefs = self._nodemap[node]
180 nrefs = self._nodemap[node]
181 if len(nrefs) == 1:
181 if len(nrefs) == 1:
182 assert nrefs[0] == mark
182 assert nrefs[0] == mark
183 del self._nodemap[node]
183 del self._nodemap[node]
184 else:
184 else:
185 nrefs.remove(mark)
185 nrefs.remove(mark)
186
186
187 def names(self, node):
187 def names(self, node):
188 """Return a sorted list of bookmarks pointing to the specified node"""
188 """Return a sorted list of bookmarks pointing to the specified node"""
189 return self._nodemap.get(node, [])
189 return self._nodemap.get(node, [])
190
190
191 def applychanges(self, repo, tr, changes):
191 def applychanges(self, repo, tr, changes):
192 """Apply a list of changes to bookmarks
192 """Apply a list of changes to bookmarks
193 """
193 """
194 bmchanges = tr.changes.get(b'bookmarks')
194 bmchanges = tr.changes.get(b'bookmarks')
195 for name, node in changes:
195 for name, node in changes:
196 old = self._refmap.get(name)
196 old = self._refmap.get(name)
197 if node is None:
197 if node is None:
198 self._del(name)
198 self._del(name)
199 else:
199 else:
200 self._set(name, node)
200 self._set(name, node)
201 if bmchanges is not None:
201 if bmchanges is not None:
202 # if a previous value exist preserve the "initial" value
202 # if a previous value exist preserve the "initial" value
203 previous = bmchanges.get(name)
203 previous = bmchanges.get(name)
204 if previous is not None:
204 if previous is not None:
205 old = previous[0]
205 old = previous[0]
206 bmchanges[name] = (old, node)
206 bmchanges[name] = (old, node)
207 self._recordchange(tr)
207 self._recordchange(tr)
208
208
209 def _recordchange(self, tr):
209 def _recordchange(self, tr):
210 """record that bookmarks have been changed in a transaction
210 """record that bookmarks have been changed in a transaction
211
211
212 The transaction is then responsible for updating the file content."""
212 The transaction is then responsible for updating the file content."""
213 location = b'' if bookmarksinstore(self._repo) else b'plain'
213 location = b'' if bookmarksinstore(self._repo) else b'plain'
214 tr.addfilegenerator(
214 tr.addfilegenerator(
215 b'bookmarks', (b'bookmarks',), self._write, location=location
215 b'bookmarks', (b'bookmarks',), self._write, location=location
216 )
216 )
217 tr.hookargs[b'bookmark_moved'] = b'1'
217 tr.hookargs[b'bookmark_moved'] = b'1'
218
218
219 def _writerepo(self, repo):
219 def _writerepo(self, repo):
220 """Factored out for extensibility"""
220 """Factored out for extensibility"""
221 rbm = repo._bookmarks
221 rbm = repo._bookmarks
222 if rbm.active not in self._refmap:
222 if rbm.active not in self._refmap:
223 rbm.active = None
223 rbm.active = None
224 rbm._writeactive()
224 rbm._writeactive()
225
225
226 if bookmarksinstore(repo):
226 if bookmarksinstore(repo):
227 vfs = repo.svfs
227 vfs = repo.svfs
228 lock = repo.lock()
228 lock = repo.lock()
229 else:
229 else:
230 vfs = repo.vfs
230 vfs = repo.vfs
231 lock = repo.wlock()
231 lock = repo.wlock()
232 with lock:
232 with lock:
233 with vfs(b'bookmarks', b'w', atomictemp=True, checkambig=True) as f:
233 with vfs(b'bookmarks', b'w', atomictemp=True, checkambig=True) as f:
234 self._write(f)
234 self._write(f)
235
235
236 def _writeactive(self):
236 def _writeactive(self):
237 if self._aclean:
237 if self._aclean:
238 return
238 return
239 with self._repo.wlock():
239 with self._repo.wlock():
240 if self._active is not None:
240 if self._active is not None:
241 with self._repo.vfs(
241 with self._repo.vfs(
242 b'bookmarks.current', b'w', atomictemp=True, checkambig=True
242 b'bookmarks.current', b'w', atomictemp=True, checkambig=True
243 ) as f:
243 ) as f:
244 f.write(encoding.fromlocal(self._active))
244 f.write(encoding.fromlocal(self._active))
245 else:
245 else:
246 self._repo.vfs.tryunlink(b'bookmarks.current')
246 self._repo.vfs.tryunlink(b'bookmarks.current')
247 self._aclean = True
247 self._aclean = True
248
248
249 def _write(self, fp):
249 def _write(self, fp):
250 for name, node in sorted(pycompat.iteritems(self._refmap)):
250 for name, node in sorted(pycompat.iteritems(self._refmap)):
251 fp.write(b"%s %s\n" % (hex(node), encoding.fromlocal(name)))
251 fp.write(b"%s %s\n" % (hex(node), encoding.fromlocal(name)))
252 self._clean = True
252 self._clean = True
253 self._repo.invalidatevolatilesets()
253 self._repo.invalidatevolatilesets()
254
254
255 def expandname(self, bname):
255 def expandname(self, bname):
256 if bname == b'.':
256 if bname == b'.':
257 if self.active:
257 if self.active:
258 return self.active
258 return self.active
259 else:
259 else:
260 raise error.RepoLookupError(_(b"no active bookmark"))
260 raise error.RepoLookupError(_(b"no active bookmark"))
261 return bname
261 return bname
262
262
263 def checkconflict(self, mark, force=False, target=None):
263 def checkconflict(self, mark, force=False, target=None):
264 """check repo for a potential clash of mark with an existing bookmark,
264 """check repo for a potential clash of mark with an existing bookmark,
265 branch, or hash
265 branch, or hash
266
266
267 If target is supplied, then check that we are moving the bookmark
267 If target is supplied, then check that we are moving the bookmark
268 forward.
268 forward.
269
269
270 If force is supplied, then forcibly move the bookmark to a new commit
270 If force is supplied, then forcibly move the bookmark to a new commit
271 regardless if it is a move forward.
271 regardless if it is a move forward.
272
272
273 If divergent bookmark are to be deleted, they will be returned as list.
273 If divergent bookmark are to be deleted, they will be returned as list.
274 """
274 """
275 cur = self._repo[b'.'].node()
275 cur = self._repo[b'.'].node()
276 if mark in self._refmap and not force:
276 if mark in self._refmap and not force:
277 if target:
277 if target:
278 if self._refmap[mark] == target and target == cur:
278 if self._refmap[mark] == target and target == cur:
279 # re-activating a bookmark
279 # re-activating a bookmark
280 return []
280 return []
281 rev = self._repo[target].rev()
281 rev = self._repo[target].rev()
282 anc = self._repo.changelog.ancestors([rev])
282 anc = self._repo.changelog.ancestors([rev])
283 bmctx = self._repo[self[mark]]
283 bmctx = self._repo[self[mark]]
284 divs = [
284 divs = [
285 self._refmap[b]
285 self._refmap[b]
286 for b in self._refmap
286 for b in self._refmap
287 if b.split(b'@', 1)[0] == mark.split(b'@', 1)[0]
287 if b.split(b'@', 1)[0] == mark.split(b'@', 1)[0]
288 ]
288 ]
289
289
290 # allow resolving a single divergent bookmark even if moving
290 # allow resolving a single divergent bookmark even if moving
291 # the bookmark across branches when a revision is specified
291 # the bookmark across branches when a revision is specified
292 # that contains a divergent bookmark
292 # that contains a divergent bookmark
293 if bmctx.rev() not in anc and target in divs:
293 if bmctx.rev() not in anc and target in divs:
294 return divergent2delete(self._repo, [target], mark)
294 return divergent2delete(self._repo, [target], mark)
295
295
296 deletefrom = [
296 deletefrom = [
297 b for b in divs if self._repo[b].rev() in anc or b == target
297 b for b in divs if self._repo[b].rev() in anc or b == target
298 ]
298 ]
299 delbms = divergent2delete(self._repo, deletefrom, mark)
299 delbms = divergent2delete(self._repo, deletefrom, mark)
300 if validdest(self._repo, bmctx, self._repo[target]):
300 if validdest(self._repo, bmctx, self._repo[target]):
301 self._repo.ui.status(
301 self._repo.ui.status(
302 _(b"moving bookmark '%s' forward from %s\n")
302 _(b"moving bookmark '%s' forward from %s\n")
303 % (mark, short(bmctx.node()))
303 % (mark, short(bmctx.node()))
304 )
304 )
305 return delbms
305 return delbms
306 raise error.Abort(
306 raise error.Abort(
307 _(b"bookmark '%s' already exists (use -f to force)") % mark
307 _(b"bookmark '%s' already exists (use -f to force)") % mark
308 )
308 )
309 if (
309 if (
310 mark in self._repo.branchmap()
310 mark in self._repo.branchmap()
311 or mark == self._repo.dirstate.branch()
311 or mark == self._repo.dirstate.branch()
312 ) and not force:
312 ) and not force:
313 raise error.Abort(
313 raise error.Abort(
314 _(b"a bookmark cannot have the name of an existing branch")
314 _(b"a bookmark cannot have the name of an existing branch")
315 )
315 )
316 if len(mark) > 3 and not force:
316 if len(mark) > 3 and not force:
317 try:
317 try:
318 shadowhash = scmutil.isrevsymbol(self._repo, mark)
318 shadowhash = scmutil.isrevsymbol(self._repo, mark)
319 except error.LookupError: # ambiguous identifier
319 except error.LookupError: # ambiguous identifier
320 shadowhash = False
320 shadowhash = False
321 if shadowhash:
321 if shadowhash:
322 self._repo.ui.warn(
322 self._repo.ui.warn(
323 _(
323 _(
324 b"bookmark %s matches a changeset hash\n"
324 b"bookmark %s matches a changeset hash\n"
325 b"(did you leave a -r out of an 'hg bookmark' "
325 b"(did you leave a -r out of an 'hg bookmark' "
326 b"command?)\n"
326 b"command?)\n"
327 )
327 )
328 % mark
328 % mark
329 )
329 )
330 return []
330 return []
331
331
332
332
333 def _readactive(repo, marks):
333 def _readactive(repo, marks):
334 """
334 """
335 Get the active bookmark. We can have an active bookmark that updates
335 Get the active bookmark. We can have an active bookmark that updates
336 itself as we commit. This function returns the name of that bookmark.
336 itself as we commit. This function returns the name of that bookmark.
337 It is stored in .hg/bookmarks.current
337 It is stored in .hg/bookmarks.current
338 """
338 """
339 # No readline() in osutil.posixfile, reading everything is
339 # No readline() in osutil.posixfile, reading everything is
340 # cheap.
340 # cheap.
341 content = repo.vfs.tryread(b'bookmarks.current')
341 content = repo.vfs.tryread(b'bookmarks.current')
342 mark = encoding.tolocal((content.splitlines() or [b''])[0])
342 mark = encoding.tolocal((content.splitlines() or [b''])[0])
343 if mark == b'' or mark not in marks:
343 if mark == b'' or mark not in marks:
344 mark = None
344 mark = None
345 return mark
345 return mark
346
346
347
347
348 def activate(repo, mark):
348 def activate(repo, mark):
349 """
349 """
350 Set the given bookmark to be 'active', meaning that this bookmark will
350 Set the given bookmark to be 'active', meaning that this bookmark will
351 follow new commits that are made.
351 follow new commits that are made.
352 The name is recorded in .hg/bookmarks.current
352 The name is recorded in .hg/bookmarks.current
353 """
353 """
354 repo._bookmarks.active = mark
354 repo._bookmarks.active = mark
355 repo._bookmarks._writeactive()
355 repo._bookmarks._writeactive()
356
356
357
357
358 def deactivate(repo):
358 def deactivate(repo):
359 """
359 """
360 Unset the active bookmark in this repository.
360 Unset the active bookmark in this repository.
361 """
361 """
362 repo._bookmarks.active = None
362 repo._bookmarks.active = None
363 repo._bookmarks._writeactive()
363 repo._bookmarks._writeactive()
364
364
365
365
366 def isactivewdirparent(repo):
366 def isactivewdirparent(repo):
367 """
367 """
368 Tell whether the 'active' bookmark (the one that follows new commits)
368 Tell whether the 'active' bookmark (the one that follows new commits)
369 points to one of the parents of the current working directory (wdir).
369 points to one of the parents of the current working directory (wdir).
370
370
371 While this is normally the case, it can on occasion be false; for example,
371 While this is normally the case, it can on occasion be false; for example,
372 immediately after a pull, the active bookmark can be moved to point
372 immediately after a pull, the active bookmark can be moved to point
373 to a place different than the wdir. This is solved by running `hg update`.
373 to a place different than the wdir. This is solved by running `hg update`.
374 """
374 """
375 mark = repo._activebookmark
375 mark = repo._activebookmark
376 marks = repo._bookmarks
376 marks = repo._bookmarks
377 parents = [p.node() for p in repo[None].parents()]
377 parents = [p.node() for p in repo[None].parents()]
378 return mark in marks and marks[mark] in parents
378 return mark in marks and marks[mark] in parents
379
379
380
380
381 def divergent2delete(repo, deletefrom, bm):
381 def divergent2delete(repo, deletefrom, bm):
382 """find divergent versions of bm on nodes in deletefrom.
382 """find divergent versions of bm on nodes in deletefrom.
383
383
384 the list of bookmark to delete."""
384 the list of bookmark to delete."""
385 todelete = []
385 todelete = []
386 marks = repo._bookmarks
386 marks = repo._bookmarks
387 divergent = [
387 divergent = [
388 b for b in marks if b.split(b'@', 1)[0] == bm.split(b'@', 1)[0]
388 b for b in marks if b.split(b'@', 1)[0] == bm.split(b'@', 1)[0]
389 ]
389 ]
390 for mark in divergent:
390 for mark in divergent:
391 if mark == b'@' or b'@' not in mark:
391 if mark == b'@' or b'@' not in mark:
392 # can't be divergent by definition
392 # can't be divergent by definition
393 continue
393 continue
394 if mark and marks[mark] in deletefrom:
394 if mark and marks[mark] in deletefrom:
395 if mark != bm:
395 if mark != bm:
396 todelete.append(mark)
396 todelete.append(mark)
397 return todelete
397 return todelete
398
398
399
399
400 def headsforactive(repo):
400 def headsforactive(repo):
401 """Given a repo with an active bookmark, return divergent bookmark nodes.
401 """Given a repo with an active bookmark, return divergent bookmark nodes.
402
402
403 Args:
403 Args:
404 repo: A repository with an active bookmark.
404 repo: A repository with an active bookmark.
405
405
406 Returns:
406 Returns:
407 A list of binary node ids that is the full list of other
407 A list of binary node ids that is the full list of other
408 revisions with bookmarks divergent from the active bookmark. If
408 revisions with bookmarks divergent from the active bookmark. If
409 there were no divergent bookmarks, then this list will contain
409 there were no divergent bookmarks, then this list will contain
410 only one entry.
410 only one entry.
411 """
411 """
412 if not repo._activebookmark:
412 if not repo._activebookmark:
413 raise ValueError(
413 raise ValueError(
414 b'headsforactive() only makes sense with an active bookmark'
414 b'headsforactive() only makes sense with an active bookmark'
415 )
415 )
416 name = repo._activebookmark.split(b'@', 1)[0]
416 name = repo._activebookmark.split(b'@', 1)[0]
417 heads = []
417 heads = []
418 for mark, n in pycompat.iteritems(repo._bookmarks):
418 for mark, n in pycompat.iteritems(repo._bookmarks):
419 if mark.split(b'@', 1)[0] == name:
419 if mark.split(b'@', 1)[0] == name:
420 heads.append(n)
420 heads.append(n)
421 return heads
421 return heads
422
422
423
423
424 def calculateupdate(ui, repo):
424 def calculateupdate(ui, repo):
425 '''Return a tuple (activemark, movemarkfrom) indicating the active bookmark
425 '''Return a tuple (activemark, movemarkfrom) indicating the active bookmark
426 and where to move the active bookmark from, if needed.'''
426 and where to move the active bookmark from, if needed.'''
427 checkout, movemarkfrom = None, None
427 checkout, movemarkfrom = None, None
428 activemark = repo._activebookmark
428 activemark = repo._activebookmark
429 if isactivewdirparent(repo):
429 if isactivewdirparent(repo):
430 movemarkfrom = repo[b'.'].node()
430 movemarkfrom = repo[b'.'].node()
431 elif activemark:
431 elif activemark:
432 ui.status(_(b"updating to active bookmark %s\n") % activemark)
432 ui.status(_(b"updating to active bookmark %s\n") % activemark)
433 checkout = activemark
433 checkout = activemark
434 return (checkout, movemarkfrom)
434 return (checkout, movemarkfrom)
435
435
436
436
437 def update(repo, parents, node):
437 def update(repo, parents, node):
438 deletefrom = parents
438 deletefrom = parents
439 marks = repo._bookmarks
439 marks = repo._bookmarks
440 active = marks.active
440 active = marks.active
441 if not active:
441 if not active:
442 return False
442 return False
443
443
444 bmchanges = []
444 bmchanges = []
445 if marks[active] in parents:
445 if marks[active] in parents:
446 new = repo[node]
446 new = repo[node]
447 divs = [
447 divs = [
448 repo[marks[b]]
448 repo[marks[b]]
449 for b in marks
449 for b in marks
450 if b.split(b'@', 1)[0] == active.split(b'@', 1)[0]
450 if b.split(b'@', 1)[0] == active.split(b'@', 1)[0]
451 ]
451 ]
452 anc = repo.changelog.ancestors([new.rev()])
452 anc = repo.changelog.ancestors([new.rev()])
453 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
453 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
454 if validdest(repo, repo[marks[active]], new):
454 if validdest(repo, repo[marks[active]], new):
455 bmchanges.append((active, new.node()))
455 bmchanges.append((active, new.node()))
456
456
457 for bm in divergent2delete(repo, deletefrom, active):
457 for bm in divergent2delete(repo, deletefrom, active):
458 bmchanges.append((bm, None))
458 bmchanges.append((bm, None))
459
459
460 if bmchanges:
460 if bmchanges:
461 with repo.lock(), repo.transaction(b'bookmark') as tr:
461 with repo.lock(), repo.transaction(b'bookmark') as tr:
462 marks.applychanges(repo, tr, bmchanges)
462 marks.applychanges(repo, tr, bmchanges)
463 return bool(bmchanges)
463 return bool(bmchanges)
464
464
465
465
466 def isdivergent(b):
466 def isdivergent(b):
467 return b'@' in b and not b.endswith(b'@')
467 return b'@' in b and not b.endswith(b'@')
468
468
469
469
470 def listbinbookmarks(repo):
470 def listbinbookmarks(repo):
471 # We may try to list bookmarks on a repo type that does not
471 # We may try to list bookmarks on a repo type that does not
472 # support it (e.g., statichttprepository).
472 # support it (e.g., statichttprepository).
473 marks = getattr(repo, '_bookmarks', {})
473 marks = getattr(repo, '_bookmarks', {})
474
474
475 hasnode = repo.changelog.hasnode
475 hasnode = repo.changelog.hasnode
476 for k, v in pycompat.iteritems(marks):
476 for k, v in pycompat.iteritems(marks):
477 # don't expose local divergent bookmarks
477 # don't expose local divergent bookmarks
478 if hasnode(v) and not isdivergent(k):
478 if hasnode(v) and not isdivergent(k):
479 yield k, v
479 yield k, v
480
480
481
481
482 def listbookmarks(repo):
482 def listbookmarks(repo):
483 d = {}
483 d = {}
484 for book, node in listbinbookmarks(repo):
484 for book, node in listbinbookmarks(repo):
485 d[book] = hex(node)
485 d[book] = hex(node)
486 return d
486 return d
487
487
488
488
489 def pushbookmark(repo, key, old, new):
489 def pushbookmark(repo, key, old, new):
490 if isdivergent(key):
490 if isdivergent(key):
491 return False
491 return False
492 if bookmarksinstore(repo):
492 if bookmarksinstore(repo):
493 wlock = util.nullcontextmanager()
493 wlock = util.nullcontextmanager()
494 else:
494 else:
495 wlock = repo.wlock()
495 wlock = repo.wlock()
496 with wlock, repo.lock(), repo.transaction(b'bookmarks') as tr:
496 with wlock, repo.lock(), repo.transaction(b'bookmarks') as tr:
497 marks = repo._bookmarks
497 marks = repo._bookmarks
498 existing = hex(marks.get(key, b''))
498 existing = hex(marks.get(key, b''))
499 if existing != old and existing != new:
499 if existing != old and existing != new:
500 return False
500 return False
501 if new == b'':
501 if new == b'':
502 changes = [(key, None)]
502 changes = [(key, None)]
503 else:
503 else:
504 if new not in repo:
504 if new not in repo:
505 return False
505 return False
506 changes = [(key, repo[new].node())]
506 changes = [(key, repo[new].node())]
507 marks.applychanges(repo, tr, changes)
507 marks.applychanges(repo, tr, changes)
508 return True
508 return True
509
509
510
510
511 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
511 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
512 '''Compare bookmarks between srcmarks and dstmarks
512 '''Compare bookmarks between srcmarks and dstmarks
513
513
514 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
514 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
515 differ, invalid)", each are list of bookmarks below:
515 differ, invalid)", each are list of bookmarks below:
516
516
517 :addsrc: added on src side (removed on dst side, perhaps)
517 :addsrc: added on src side (removed on dst side, perhaps)
518 :adddst: added on dst side (removed on src side, perhaps)
518 :adddst: added on dst side (removed on src side, perhaps)
519 :advsrc: advanced on src side
519 :advsrc: advanced on src side
520 :advdst: advanced on dst side
520 :advdst: advanced on dst side
521 :diverge: diverge
521 :diverge: diverge
522 :differ: changed, but changeset referred on src is unknown on dst
522 :differ: changed, but changeset referred on src is unknown on dst
523 :invalid: unknown on both side
523 :invalid: unknown on both side
524 :same: same on both side
524 :same: same on both side
525
525
526 Each elements of lists in result tuple is tuple "(bookmark name,
526 Each elements of lists in result tuple is tuple "(bookmark name,
527 changeset ID on source side, changeset ID on destination
527 changeset ID on source side, changeset ID on destination
528 side)". Each changeset ID is a binary node or None.
528 side)". Each changeset ID is a binary node or None.
529
529
530 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
530 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
531 "invalid" list may be unknown for repo.
531 "invalid" list may be unknown for repo.
532
532
533 If "targets" is specified, only bookmarks listed in it are
533 If "targets" is specified, only bookmarks listed in it are
534 examined.
534 examined.
535 '''
535 '''
536
536
537 if targets:
537 if targets:
538 bset = set(targets)
538 bset = set(targets)
539 else:
539 else:
540 srcmarkset = set(srcmarks)
540 srcmarkset = set(srcmarks)
541 dstmarkset = set(dstmarks)
541 dstmarkset = set(dstmarks)
542 bset = srcmarkset | dstmarkset
542 bset = srcmarkset | dstmarkset
543
543
544 results = ([], [], [], [], [], [], [], [])
544 results = ([], [], [], [], [], [], [], [])
545 addsrc = results[0].append
545 addsrc = results[0].append
546 adddst = results[1].append
546 adddst = results[1].append
547 advsrc = results[2].append
547 advsrc = results[2].append
548 advdst = results[3].append
548 advdst = results[3].append
549 diverge = results[4].append
549 diverge = results[4].append
550 differ = results[5].append
550 differ = results[5].append
551 invalid = results[6].append
551 invalid = results[6].append
552 same = results[7].append
552 same = results[7].append
553
553
554 for b in sorted(bset):
554 for b in sorted(bset):
555 if b not in srcmarks:
555 if b not in srcmarks:
556 if b in dstmarks:
556 if b in dstmarks:
557 adddst((b, None, dstmarks[b]))
557 adddst((b, None, dstmarks[b]))
558 else:
558 else:
559 invalid((b, None, None))
559 invalid((b, None, None))
560 elif b not in dstmarks:
560 elif b not in dstmarks:
561 addsrc((b, srcmarks[b], None))
561 addsrc((b, srcmarks[b], None))
562 else:
562 else:
563 scid = srcmarks[b]
563 scid = srcmarks[b]
564 dcid = dstmarks[b]
564 dcid = dstmarks[b]
565 if scid == dcid:
565 if scid == dcid:
566 same((b, scid, dcid))
566 same((b, scid, dcid))
567 elif scid in repo and dcid in repo:
567 elif scid in repo and dcid in repo:
568 sctx = repo[scid]
568 sctx = repo[scid]
569 dctx = repo[dcid]
569 dctx = repo[dcid]
570 if sctx.rev() < dctx.rev():
570 if sctx.rev() < dctx.rev():
571 if validdest(repo, sctx, dctx):
571 if validdest(repo, sctx, dctx):
572 advdst((b, scid, dcid))
572 advdst((b, scid, dcid))
573 else:
573 else:
574 diverge((b, scid, dcid))
574 diverge((b, scid, dcid))
575 else:
575 else:
576 if validdest(repo, dctx, sctx):
576 if validdest(repo, dctx, sctx):
577 advsrc((b, scid, dcid))
577 advsrc((b, scid, dcid))
578 else:
578 else:
579 diverge((b, scid, dcid))
579 diverge((b, scid, dcid))
580 else:
580 else:
581 # it is too expensive to examine in detail, in this case
581 # it is too expensive to examine in detail, in this case
582 differ((b, scid, dcid))
582 differ((b, scid, dcid))
583
583
584 return results
584 return results
585
585
586
586
587 def _diverge(ui, b, path, localmarks, remotenode):
587 def _diverge(ui, b, path, localmarks, remotenode):
588 '''Return appropriate diverged bookmark for specified ``path``
588 '''Return appropriate diverged bookmark for specified ``path``
589
589
590 This returns None, if it is failed to assign any divergent
590 This returns None, if it is failed to assign any divergent
591 bookmark name.
591 bookmark name.
592
592
593 This reuses already existing one with "@number" suffix, if it
593 This reuses already existing one with "@number" suffix, if it
594 refers ``remotenode``.
594 refers ``remotenode``.
595 '''
595 '''
596 if b == b'@':
596 if b == b'@':
597 b = b''
597 b = b''
598 # try to use an @pathalias suffix
598 # try to use an @pathalias suffix
599 # if an @pathalias already exists, we overwrite (update) it
599 # if an @pathalias already exists, we overwrite (update) it
600 if path.startswith(b"file:"):
600 if path.startswith(b"file:"):
601 path = util.url(path).path
601 path = util.url(path).path
602 for p, u in ui.configitems(b"paths"):
602 for p, u in ui.configitems(b"paths"):
603 if u.startswith(b"file:"):
603 if u.startswith(b"file:"):
604 u = util.url(u).path
604 u = util.url(u).path
605 if path == u:
605 if path == u:
606 return b'%s@%s' % (b, p)
606 return b'%s@%s' % (b, p)
607
607
608 # assign a unique "@number" suffix newly
608 # assign a unique "@number" suffix newly
609 for x in range(1, 100):
609 for x in range(1, 100):
610 n = b'%s@%d' % (b, x)
610 n = b'%s@%d' % (b, x)
611 if n not in localmarks or localmarks[n] == remotenode:
611 if n not in localmarks or localmarks[n] == remotenode:
612 return n
612 return n
613
613
614 return None
614 return None
615
615
616
616
617 def unhexlifybookmarks(marks):
617 def unhexlifybookmarks(marks):
618 binremotemarks = {}
618 binremotemarks = {}
619 for name, node in marks.items():
619 for name, node in marks.items():
620 binremotemarks[name] = bin(node)
620 binremotemarks[name] = bin(node)
621 return binremotemarks
621 return binremotemarks
622
622
623
623
624 _binaryentry = struct.Struct(b'>20sH')
624 _binaryentry = struct.Struct(b'>20sH')
625
625
626
626
627 def binaryencode(bookmarks):
627 def binaryencode(bookmarks):
628 """encode a '(bookmark, node)' iterable into a binary stream
628 """encode a '(bookmark, node)' iterable into a binary stream
629
629
630 the binary format is:
630 the binary format is:
631
631
632 <node><bookmark-length><bookmark-name>
632 <node><bookmark-length><bookmark-name>
633
633
634 :node: is a 20 bytes binary node,
634 :node: is a 20 bytes binary node,
635 :bookmark-length: an unsigned short,
635 :bookmark-length: an unsigned short,
636 :bookmark-name: the name of the bookmark (of length <bookmark-length>)
636 :bookmark-name: the name of the bookmark (of length <bookmark-length>)
637
637
638 wdirid (all bits set) will be used as a special value for "missing"
638 wdirid (all bits set) will be used as a special value for "missing"
639 """
639 """
640 binarydata = []
640 binarydata = []
641 for book, node in bookmarks:
641 for book, node in bookmarks:
642 if not node: # None or ''
642 if not node: # None or ''
643 node = wdirid
643 node = wdirid
644 binarydata.append(_binaryentry.pack(node, len(book)))
644 binarydata.append(_binaryentry.pack(node, len(book)))
645 binarydata.append(book)
645 binarydata.append(book)
646 return b''.join(binarydata)
646 return b''.join(binarydata)
647
647
648
648
649 def binarydecode(stream):
649 def binarydecode(stream):
650 """decode a binary stream into an '(bookmark, node)' iterable
650 """decode a binary stream into an '(bookmark, node)' iterable
651
651
652 the binary format is:
652 the binary format is:
653
653
654 <node><bookmark-length><bookmark-name>
654 <node><bookmark-length><bookmark-name>
655
655
656 :node: is a 20 bytes binary node,
656 :node: is a 20 bytes binary node,
657 :bookmark-length: an unsigned short,
657 :bookmark-length: an unsigned short,
658 :bookmark-name: the name of the bookmark (of length <bookmark-length>))
658 :bookmark-name: the name of the bookmark (of length <bookmark-length>))
659
659
660 wdirid (all bits set) will be used as a special value for "missing"
660 wdirid (all bits set) will be used as a special value for "missing"
661 """
661 """
662 entrysize = _binaryentry.size
662 entrysize = _binaryentry.size
663 books = []
663 books = []
664 while True:
664 while True:
665 entry = stream.read(entrysize)
665 entry = stream.read(entrysize)
666 if len(entry) < entrysize:
666 if len(entry) < entrysize:
667 if entry:
667 if entry:
668 raise error.Abort(_(b'bad bookmark stream'))
668 raise error.Abort(_(b'bad bookmark stream'))
669 break
669 break
670 node, length = _binaryentry.unpack(entry)
670 node, length = _binaryentry.unpack(entry)
671 bookmark = stream.read(length)
671 bookmark = stream.read(length)
672 if len(bookmark) < length:
672 if len(bookmark) < length:
673 if entry:
673 if entry:
674 raise error.Abort(_(b'bad bookmark stream'))
674 raise error.Abort(_(b'bad bookmark stream'))
675 if node == wdirid:
675 if node == wdirid:
676 node = None
676 node = None
677 books.append((bookmark, node))
677 books.append((bookmark, node))
678 return books
678 return books
679
679
680
680
681 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
681 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
682 ui.debug(b"checking for updated bookmarks\n")
682 ui.debug(b"checking for updated bookmarks\n")
683 localmarks = repo._bookmarks
683 localmarks = repo._bookmarks
684 (
684 (
685 addsrc,
685 addsrc,
686 adddst,
686 adddst,
687 advsrc,
687 advsrc,
688 advdst,
688 advdst,
689 diverge,
689 diverge,
690 differ,
690 differ,
691 invalid,
691 invalid,
692 same,
692 same,
693 ) = comparebookmarks(repo, remotemarks, localmarks)
693 ) = comparebookmarks(repo, remotemarks, localmarks)
694
694
695 status = ui.status
695 status = ui.status
696 warn = ui.warn
696 warn = ui.warn
697 if ui.configbool(b'ui', b'quietbookmarkmove'):
697 if ui.configbool(b'ui', b'quietbookmarkmove'):
698 status = warn = ui.debug
698 status = warn = ui.debug
699
699
700 explicit = set(explicit)
700 explicit = set(explicit)
701 changed = []
701 changed = []
702 for b, scid, dcid in addsrc:
702 for b, scid, dcid in addsrc:
703 if scid in repo: # add remote bookmarks for changes we already have
703 if scid in repo: # add remote bookmarks for changes we already have
704 changed.append(
704 changed.append(
705 (b, scid, status, _(b"adding remote bookmark %s\n") % b)
705 (b, scid, status, _(b"adding remote bookmark %s\n") % b)
706 )
706 )
707 elif b in explicit:
707 elif b in explicit:
708 explicit.remove(b)
708 explicit.remove(b)
709 ui.warn(
709 ui.warn(
710 _(b"remote bookmark %s points to locally missing %s\n")
710 _(b"remote bookmark %s points to locally missing %s\n")
711 % (b, hex(scid)[:12])
711 % (b, hex(scid)[:12])
712 )
712 )
713
713
714 for b, scid, dcid in advsrc:
714 for b, scid, dcid in advsrc:
715 changed.append((b, scid, status, _(b"updating bookmark %s\n") % b))
715 changed.append((b, scid, status, _(b"updating bookmark %s\n") % b))
716 # remove normal movement from explicit set
716 # remove normal movement from explicit set
717 explicit.difference_update(d[0] for d in changed)
717 explicit.difference_update(d[0] for d in changed)
718
718
719 for b, scid, dcid in diverge:
719 for b, scid, dcid in diverge:
720 if b in explicit:
720 if b in explicit:
721 explicit.discard(b)
721 explicit.discard(b)
722 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b))
722 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b))
723 else:
723 else:
724 db = _diverge(ui, b, path, localmarks, scid)
724 db = _diverge(ui, b, path, localmarks, scid)
725 if db:
725 if db:
726 changed.append(
726 changed.append(
727 (
727 (
728 db,
728 db,
729 scid,
729 scid,
730 warn,
730 warn,
731 _(b"divergent bookmark %s stored as %s\n") % (b, db),
731 _(b"divergent bookmark %s stored as %s\n") % (b, db),
732 )
732 )
733 )
733 )
734 else:
734 else:
735 warn(
735 warn(
736 _(
736 _(
737 b"warning: failed to assign numbered name "
737 b"warning: failed to assign numbered name "
738 b"to divergent bookmark %s\n"
738 b"to divergent bookmark %s\n"
739 )
739 )
740 % b
740 % b
741 )
741 )
742 for b, scid, dcid in adddst + advdst:
742 for b, scid, dcid in adddst + advdst:
743 if b in explicit:
743 if b in explicit:
744 explicit.discard(b)
744 explicit.discard(b)
745 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b))
745 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b))
746 for b, scid, dcid in differ:
746 for b, scid, dcid in differ:
747 if b in explicit:
747 if b in explicit:
748 explicit.remove(b)
748 explicit.remove(b)
749 ui.warn(
749 ui.warn(
750 _(b"remote bookmark %s points to locally missing %s\n")
750 _(b"remote bookmark %s points to locally missing %s\n")
751 % (b, hex(scid)[:12])
751 % (b, hex(scid)[:12])
752 )
752 )
753
753
754 if changed:
754 if changed:
755 tr = trfunc()
755 tr = trfunc()
756 changes = []
756 changes = []
757 key = lambda t: (t[0], t[1] or b'')
757 key = lambda t: (t[0], t[1] or b'')
758 for b, node, writer, msg in sorted(changed, key=key):
758 for b, node, writer, msg in sorted(changed, key=key):
759 changes.append((b, node))
759 changes.append((b, node))
760 writer(msg)
760 writer(msg)
761 localmarks.applychanges(repo, tr, changes)
761 localmarks.applychanges(repo, tr, changes)
762
762
763
763
764 def incoming(ui, repo, peer):
764 def incoming(ui, repo, peer):
765 '''Show bookmarks incoming from other to repo
765 '''Show bookmarks incoming from other to repo
766 '''
766 '''
767 ui.status(_(b"searching for changed bookmarks\n"))
767 ui.status(_(b"searching for changed bookmarks\n"))
768
768
769 with peer.commandexecutor() as e:
769 with peer.commandexecutor() as e:
770 remotemarks = unhexlifybookmarks(
770 remotemarks = unhexlifybookmarks(
771 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result()
771 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result()
772 )
772 )
773
773
774 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
774 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
775 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
775 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
776
776
777 incomings = []
777 incomings = []
778 if ui.debugflag:
778 if ui.debugflag:
779 getid = lambda id: id
779 getid = lambda id: id
780 else:
780 else:
781 getid = lambda id: id[:12]
781 getid = lambda id: id[:12]
782 if ui.verbose:
782 if ui.verbose:
783
783
784 def add(b, id, st):
784 def add(b, id, st):
785 incomings.append(b" %-25s %s %s\n" % (b, getid(id), st))
785 incomings.append(b" %-25s %s %s\n" % (b, getid(id), st))
786
786
787 else:
787 else:
788
788
789 def add(b, id, st):
789 def add(b, id, st):
790 incomings.append(b" %-25s %s\n" % (b, getid(id)))
790 incomings.append(b" %-25s %s\n" % (b, getid(id)))
791
791
792 for b, scid, dcid in addsrc:
792 for b, scid, dcid in addsrc:
793 # i18n: "added" refers to a bookmark
793 # i18n: "added" refers to a bookmark
794 add(b, hex(scid), _(b'added'))
794 add(b, hex(scid), _(b'added'))
795 for b, scid, dcid in advsrc:
795 for b, scid, dcid in advsrc:
796 # i18n: "advanced" refers to a bookmark
796 # i18n: "advanced" refers to a bookmark
797 add(b, hex(scid), _(b'advanced'))
797 add(b, hex(scid), _(b'advanced'))
798 for b, scid, dcid in diverge:
798 for b, scid, dcid in diverge:
799 # i18n: "diverged" refers to a bookmark
799 # i18n: "diverged" refers to a bookmark
800 add(b, hex(scid), _(b'diverged'))
800 add(b, hex(scid), _(b'diverged'))
801 for b, scid, dcid in differ:
801 for b, scid, dcid in differ:
802 # i18n: "changed" refers to a bookmark
802 # i18n: "changed" refers to a bookmark
803 add(b, hex(scid), _(b'changed'))
803 add(b, hex(scid), _(b'changed'))
804
804
805 if not incomings:
805 if not incomings:
806 ui.status(_(b"no changed bookmarks found\n"))
806 ui.status(_(b"no changed bookmarks found\n"))
807 return 1
807 return 1
808
808
809 for s in sorted(incomings):
809 for s in sorted(incomings):
810 ui.write(s)
810 ui.write(s)
811
811
812 return 0
812 return 0
813
813
814
814
815 def outgoing(ui, repo, other):
815 def outgoing(ui, repo, other):
816 '''Show bookmarks outgoing from repo to other
816 '''Show bookmarks outgoing from repo to other
817 '''
817 '''
818 ui.status(_(b"searching for changed bookmarks\n"))
818 ui.status(_(b"searching for changed bookmarks\n"))
819
819
820 remotemarks = unhexlifybookmarks(other.listkeys(b'bookmarks'))
820 remotemarks = unhexlifybookmarks(other.listkeys(b'bookmarks'))
821 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
821 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
822 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
822 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
823
823
824 outgoings = []
824 outgoings = []
825 if ui.debugflag:
825 if ui.debugflag:
826 getid = lambda id: id
826 getid = lambda id: id
827 else:
827 else:
828 getid = lambda id: id[:12]
828 getid = lambda id: id[:12]
829 if ui.verbose:
829 if ui.verbose:
830
830
831 def add(b, id, st):
831 def add(b, id, st):
832 outgoings.append(b" %-25s %s %s\n" % (b, getid(id), st))
832 outgoings.append(b" %-25s %s %s\n" % (b, getid(id), st))
833
833
834 else:
834 else:
835
835
836 def add(b, id, st):
836 def add(b, id, st):
837 outgoings.append(b" %-25s %s\n" % (b, getid(id)))
837 outgoings.append(b" %-25s %s\n" % (b, getid(id)))
838
838
839 for b, scid, dcid in addsrc:
839 for b, scid, dcid in addsrc:
840 # i18n: "added refers to a bookmark
840 # i18n: "added refers to a bookmark
841 add(b, hex(scid), _(b'added'))
841 add(b, hex(scid), _(b'added'))
842 for b, scid, dcid in adddst:
842 for b, scid, dcid in adddst:
843 # i18n: "deleted" refers to a bookmark
843 # i18n: "deleted" refers to a bookmark
844 add(b, b' ' * 40, _(b'deleted'))
844 add(b, b' ' * 40, _(b'deleted'))
845 for b, scid, dcid in advsrc:
845 for b, scid, dcid in advsrc:
846 # i18n: "advanced" refers to a bookmark
846 # i18n: "advanced" refers to a bookmark
847 add(b, hex(scid), _(b'advanced'))
847 add(b, hex(scid), _(b'advanced'))
848 for b, scid, dcid in diverge:
848 for b, scid, dcid in diverge:
849 # i18n: "diverged" refers to a bookmark
849 # i18n: "diverged" refers to a bookmark
850 add(b, hex(scid), _(b'diverged'))
850 add(b, hex(scid), _(b'diverged'))
851 for b, scid, dcid in differ:
851 for b, scid, dcid in differ:
852 # i18n: "changed" refers to a bookmark
852 # i18n: "changed" refers to a bookmark
853 add(b, hex(scid), _(b'changed'))
853 add(b, hex(scid), _(b'changed'))
854
854
855 if not outgoings:
855 if not outgoings:
856 ui.status(_(b"no changed bookmarks found\n"))
856 ui.status(_(b"no changed bookmarks found\n"))
857 return 1
857 return 1
858
858
859 for s in sorted(outgoings):
859 for s in sorted(outgoings):
860 ui.write(s)
860 ui.write(s)
861
861
862 return 0
862 return 0
863
863
864
864
865 def summary(repo, peer):
865 def summary(repo, peer):
866 '''Compare bookmarks between repo and other for "hg summary" output
866 '''Compare bookmarks between repo and other for "hg summary" output
867
867
868 This returns "(# of incoming, # of outgoing)" tuple.
868 This returns "(# of incoming, # of outgoing)" tuple.
869 '''
869 '''
870 with peer.commandexecutor() as e:
870 with peer.commandexecutor() as e:
871 remotemarks = unhexlifybookmarks(
871 remotemarks = unhexlifybookmarks(
872 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result()
872 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result()
873 )
873 )
874
874
875 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
875 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
876 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
876 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
877 return (len(addsrc), len(adddst))
877 return (len(addsrc), len(adddst))
878
878
879
879
880 def validdest(repo, old, new):
880 def validdest(repo, old, new):
881 """Is the new bookmark destination a valid update from the old one"""
881 """Is the new bookmark destination a valid update from the old one"""
882 repo = repo.unfiltered()
882 repo = repo.unfiltered()
883 if old == new:
883 if old == new:
884 # Old == new -> nothing to update.
884 # Old == new -> nothing to update.
885 return False
885 return False
886 elif not old:
886 elif not old:
887 # old is nullrev, anything is valid.
887 # old is nullrev, anything is valid.
888 # (new != nullrev has been excluded by the previous check)
888 # (new != nullrev has been excluded by the previous check)
889 return True
889 return True
890 elif repo.obsstore:
890 elif repo.obsstore:
891 return new.node() in obsutil.foreground(repo, [old.node()])
891 return new.node() in obsutil.foreground(repo, [old.node()])
892 else:
892 else:
893 # still an independent clause as it is lazier (and therefore faster)
893 # still an independent clause as it is lazier (and therefore faster)
894 return old.isancestorof(new)
894 return old.isancestorof(new)
895
895
896
896
897 def checkformat(repo, mark):
897 def checkformat(repo, mark):
898 """return a valid version of a potential bookmark name
898 """return a valid version of a potential bookmark name
899
899
900 Raises an abort error if the bookmark name is not valid.
900 Raises an abort error if the bookmark name is not valid.
901 """
901 """
902 mark = mark.strip()
902 mark = mark.strip()
903 if not mark:
903 if not mark:
904 raise error.Abort(
904 raise error.InputError(
905 _(b"bookmark names cannot consist entirely of whitespace")
905 _(b"bookmark names cannot consist entirely of whitespace")
906 )
906 )
907 scmutil.checknewlabel(repo, mark, b'bookmark')
907 scmutil.checknewlabel(repo, mark, b'bookmark')
908 return mark
908 return mark
909
909
910
910
911 def delete(repo, tr, names):
911 def delete(repo, tr, names):
912 """remove a mark from the bookmark store
912 """remove a mark from the bookmark store
913
913
914 Raises an abort error if mark does not exist.
914 Raises an abort error if mark does not exist.
915 """
915 """
916 marks = repo._bookmarks
916 marks = repo._bookmarks
917 changes = []
917 changes = []
918 for mark in names:
918 for mark in names:
919 if mark not in marks:
919 if mark not in marks:
920 raise error.Abort(_(b"bookmark '%s' does not exist") % mark)
920 raise error.InputError(_(b"bookmark '%s' does not exist") % mark)
921 if mark == repo._activebookmark:
921 if mark == repo._activebookmark:
922 deactivate(repo)
922 deactivate(repo)
923 changes.append((mark, None))
923 changes.append((mark, None))
924 marks.applychanges(repo, tr, changes)
924 marks.applychanges(repo, tr, changes)
925
925
926
926
927 def rename(repo, tr, old, new, force=False, inactive=False):
927 def rename(repo, tr, old, new, force=False, inactive=False):
928 """rename a bookmark from old to new
928 """rename a bookmark from old to new
929
929
930 If force is specified, then the new name can overwrite an existing
930 If force is specified, then the new name can overwrite an existing
931 bookmark.
931 bookmark.
932
932
933 If inactive is specified, then do not activate the new bookmark.
933 If inactive is specified, then do not activate the new bookmark.
934
934
935 Raises an abort error if old is not in the bookmark store.
935 Raises an abort error if old is not in the bookmark store.
936 """
936 """
937 marks = repo._bookmarks
937 marks = repo._bookmarks
938 mark = checkformat(repo, new)
938 mark = checkformat(repo, new)
939 if old not in marks:
939 if old not in marks:
940 raise error.Abort(_(b"bookmark '%s' does not exist") % old)
940 raise error.InputError(_(b"bookmark '%s' does not exist") % old)
941 changes = []
941 changes = []
942 for bm in marks.checkconflict(mark, force):
942 for bm in marks.checkconflict(mark, force):
943 changes.append((bm, None))
943 changes.append((bm, None))
944 changes.extend([(mark, marks[old]), (old, None)])
944 changes.extend([(mark, marks[old]), (old, None)])
945 marks.applychanges(repo, tr, changes)
945 marks.applychanges(repo, tr, changes)
946 if repo._activebookmark == old and not inactive:
946 if repo._activebookmark == old and not inactive:
947 activate(repo, mark)
947 activate(repo, mark)
948
948
949
949
950 def addbookmarks(repo, tr, names, rev=None, force=False, inactive=False):
950 def addbookmarks(repo, tr, names, rev=None, force=False, inactive=False):
951 """add a list of bookmarks
951 """add a list of bookmarks
952
952
953 If force is specified, then the new name can overwrite an existing
953 If force is specified, then the new name can overwrite an existing
954 bookmark.
954 bookmark.
955
955
956 If inactive is specified, then do not activate any bookmark. Otherwise, the
956 If inactive is specified, then do not activate any bookmark. Otherwise, the
957 first bookmark is activated.
957 first bookmark is activated.
958
958
959 Raises an abort error if old is not in the bookmark store.
959 Raises an abort error if old is not in the bookmark store.
960 """
960 """
961 marks = repo._bookmarks
961 marks = repo._bookmarks
962 cur = repo[b'.'].node()
962 cur = repo[b'.'].node()
963 newact = None
963 newact = None
964 changes = []
964 changes = []
965
965
966 # unhide revs if any
966 # unhide revs if any
967 if rev:
967 if rev:
968 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
968 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
969
969
970 ctx = scmutil.revsingle(repo, rev, None)
970 ctx = scmutil.revsingle(repo, rev, None)
971 # bookmarking wdir means creating a bookmark on p1 and activating it
971 # bookmarking wdir means creating a bookmark on p1 and activating it
972 activatenew = not inactive and ctx.rev() is None
972 activatenew = not inactive and ctx.rev() is None
973 if ctx.node() is None:
973 if ctx.node() is None:
974 ctx = ctx.p1()
974 ctx = ctx.p1()
975 tgt = ctx.node()
975 tgt = ctx.node()
976 assert tgt
976 assert tgt
977
977
978 for mark in names:
978 for mark in names:
979 mark = checkformat(repo, mark)
979 mark = checkformat(repo, mark)
980 if newact is None:
980 if newact is None:
981 newact = mark
981 newact = mark
982 if inactive and mark == repo._activebookmark:
982 if inactive and mark == repo._activebookmark:
983 deactivate(repo)
983 deactivate(repo)
984 continue
984 continue
985 for bm in marks.checkconflict(mark, force, tgt):
985 for bm in marks.checkconflict(mark, force, tgt):
986 changes.append((bm, None))
986 changes.append((bm, None))
987 changes.append((mark, tgt))
987 changes.append((mark, tgt))
988
988
989 # nothing changed but for the one deactivated above
989 # nothing changed but for the one deactivated above
990 if not changes:
990 if not changes:
991 return
991 return
992
992
993 if ctx.hidden():
993 if ctx.hidden():
994 repo.ui.warn(_(b"bookmarking hidden changeset %s\n") % ctx.hex()[:12])
994 repo.ui.warn(_(b"bookmarking hidden changeset %s\n") % ctx.hex()[:12])
995
995
996 if ctx.obsolete():
996 if ctx.obsolete():
997 msg = obsutil._getfilteredreason(repo, ctx.hex()[:12], ctx)
997 msg = obsutil._getfilteredreason(repo, ctx.hex()[:12], ctx)
998 repo.ui.warn(b"(%s)\n" % msg)
998 repo.ui.warn(b"(%s)\n" % msg)
999
999
1000 marks.applychanges(repo, tr, changes)
1000 marks.applychanges(repo, tr, changes)
1001 if activatenew and cur == marks[newact]:
1001 if activatenew and cur == marks[newact]:
1002 activate(repo, newact)
1002 activate(repo, newact)
1003 elif cur != tgt and newact == repo._activebookmark:
1003 elif cur != tgt and newact == repo._activebookmark:
1004 deactivate(repo)
1004 deactivate(repo)
1005
1005
1006
1006
1007 def _printbookmarks(ui, repo, fm, bmarks):
1007 def _printbookmarks(ui, repo, fm, bmarks):
1008 """private method to print bookmarks
1008 """private method to print bookmarks
1009
1009
1010 Provides a way for extensions to control how bookmarks are printed (e.g.
1010 Provides a way for extensions to control how bookmarks are printed (e.g.
1011 prepend or postpend names)
1011 prepend or postpend names)
1012 """
1012 """
1013 hexfn = fm.hexfunc
1013 hexfn = fm.hexfunc
1014 if len(bmarks) == 0 and fm.isplain():
1014 if len(bmarks) == 0 and fm.isplain():
1015 ui.status(_(b"no bookmarks set\n"))
1015 ui.status(_(b"no bookmarks set\n"))
1016 for bmark, (n, prefix, label) in sorted(pycompat.iteritems(bmarks)):
1016 for bmark, (n, prefix, label) in sorted(pycompat.iteritems(bmarks)):
1017 fm.startitem()
1017 fm.startitem()
1018 fm.context(repo=repo)
1018 fm.context(repo=repo)
1019 if not ui.quiet:
1019 if not ui.quiet:
1020 fm.plain(b' %s ' % prefix, label=label)
1020 fm.plain(b' %s ' % prefix, label=label)
1021 fm.write(b'bookmark', b'%s', bmark, label=label)
1021 fm.write(b'bookmark', b'%s', bmark, label=label)
1022 pad = b" " * (25 - encoding.colwidth(bmark))
1022 pad = b" " * (25 - encoding.colwidth(bmark))
1023 fm.condwrite(
1023 fm.condwrite(
1024 not ui.quiet,
1024 not ui.quiet,
1025 b'rev node',
1025 b'rev node',
1026 pad + b' %d:%s',
1026 pad + b' %d:%s',
1027 repo.changelog.rev(n),
1027 repo.changelog.rev(n),
1028 hexfn(n),
1028 hexfn(n),
1029 label=label,
1029 label=label,
1030 )
1030 )
1031 fm.data(active=(activebookmarklabel in label))
1031 fm.data(active=(activebookmarklabel in label))
1032 fm.plain(b'\n')
1032 fm.plain(b'\n')
1033
1033
1034
1034
1035 def printbookmarks(ui, repo, fm, names=None):
1035 def printbookmarks(ui, repo, fm, names=None):
1036 """print bookmarks by the given formatter
1036 """print bookmarks by the given formatter
1037
1037
1038 Provides a way for extensions to control how bookmarks are printed.
1038 Provides a way for extensions to control how bookmarks are printed.
1039 """
1039 """
1040 marks = repo._bookmarks
1040 marks = repo._bookmarks
1041 bmarks = {}
1041 bmarks = {}
1042 for bmark in names or marks:
1042 for bmark in names or marks:
1043 if bmark not in marks:
1043 if bmark not in marks:
1044 raise error.Abort(_(b"bookmark '%s' does not exist") % bmark)
1044 raise error.InputError(_(b"bookmark '%s' does not exist") % bmark)
1045 active = repo._activebookmark
1045 active = repo._activebookmark
1046 if bmark == active:
1046 if bmark == active:
1047 prefix, label = b'*', activebookmarklabel
1047 prefix, label = b'*', activebookmarklabel
1048 else:
1048 else:
1049 prefix, label = b' ', b''
1049 prefix, label = b' ', b''
1050
1050
1051 bmarks[bmark] = (marks[bmark], prefix, label)
1051 bmarks[bmark] = (marks[bmark], prefix, label)
1052 _printbookmarks(ui, repo, fm, bmarks)
1052 _printbookmarks(ui, repo, fm, bmarks)
1053
1053
1054
1054
1055 def preparehookargs(name, old, new):
1055 def preparehookargs(name, old, new):
1056 if new is None:
1056 if new is None:
1057 new = b''
1057 new = b''
1058 if old is None:
1058 if old is None:
1059 old = b''
1059 old = b''
1060 return {b'bookmark': name, b'node': hex(new), b'oldnode': hex(old)}
1060 return {b'bookmark': name, b'node': hex(new), b'oldnode': hex(old)}
@@ -1,1257 +1,1257 b''
1
1
2 $ hg init repo
2 $ hg init repo
3 $ cd repo
3 $ cd repo
4
4
5 $ cat > $TESTTMP/hook.sh <<'EOF'
5 $ cat > $TESTTMP/hook.sh <<'EOF'
6 > echo "test-hook-bookmark: $HG_BOOKMARK: $HG_OLDNODE -> $HG_NODE"
6 > echo "test-hook-bookmark: $HG_BOOKMARK: $HG_OLDNODE -> $HG_NODE"
7 > EOF
7 > EOF
8 $ TESTHOOK="hooks.txnclose-bookmark.test=sh $TESTTMP/hook.sh"
8 $ TESTHOOK="hooks.txnclose-bookmark.test=sh $TESTTMP/hook.sh"
9
9
10 no bookmarks
10 no bookmarks
11
11
12 $ hg bookmarks
12 $ hg bookmarks
13 no bookmarks set
13 no bookmarks set
14
14
15 $ hg bookmarks -Tjson
15 $ hg bookmarks -Tjson
16 [
16 [
17 ]
17 ]
18
18
19 bookmark rev -1
19 bookmark rev -1
20
20
21 $ hg bookmark X --config "$TESTHOOK"
21 $ hg bookmark X --config "$TESTHOOK"
22 test-hook-bookmark: X: -> 0000000000000000000000000000000000000000
22 test-hook-bookmark: X: -> 0000000000000000000000000000000000000000
23
23
24 list bookmarks
24 list bookmarks
25
25
26 $ hg bookmarks
26 $ hg bookmarks
27 * X -1:000000000000
27 * X -1:000000000000
28
28
29 list bookmarks with color
29 list bookmarks with color
30
30
31 $ hg --config extensions.color= --config color.mode=ansi \
31 $ hg --config extensions.color= --config color.mode=ansi \
32 > bookmarks --color=always
32 > bookmarks --color=always
33 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
33 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
34
34
35 $ echo a > a
35 $ echo a > a
36 $ hg add a
36 $ hg add a
37 $ hg commit -m 0 --config "$TESTHOOK"
37 $ hg commit -m 0 --config "$TESTHOOK"
38 test-hook-bookmark: X: 0000000000000000000000000000000000000000 -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
38 test-hook-bookmark: X: 0000000000000000000000000000000000000000 -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
39
39
40 bookmark X moved to rev 0
40 bookmark X moved to rev 0
41
41
42 $ hg bookmarks
42 $ hg bookmarks
43 * X 0:f7b1eb17ad24
43 * X 0:f7b1eb17ad24
44
44
45 look up bookmark
45 look up bookmark
46
46
47 $ hg log -r X
47 $ hg log -r X
48 changeset: 0:f7b1eb17ad24
48 changeset: 0:f7b1eb17ad24
49 bookmark: X
49 bookmark: X
50 tag: tip
50 tag: tip
51 user: test
51 user: test
52 date: Thu Jan 01 00:00:00 1970 +0000
52 date: Thu Jan 01 00:00:00 1970 +0000
53 summary: 0
53 summary: 0
54
54
55
55
56 second bookmark for rev 0, command should work even with ui.strict on
56 second bookmark for rev 0, command should work even with ui.strict on
57
57
58 $ hg --config ui.strict=1 bookmark X2 --config "$TESTHOOK"
58 $ hg --config ui.strict=1 bookmark X2 --config "$TESTHOOK"
59 test-hook-bookmark: X2: -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
59 test-hook-bookmark: X2: -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
60
60
61 bookmark rev -1 again
61 bookmark rev -1 again
62
62
63 $ hg bookmark -r null Y
63 $ hg bookmark -r null Y
64
64
65 list bookmarks
65 list bookmarks
66
66
67 $ hg bookmarks
67 $ hg bookmarks
68 X 0:f7b1eb17ad24
68 X 0:f7b1eb17ad24
69 * X2 0:f7b1eb17ad24
69 * X2 0:f7b1eb17ad24
70 Y -1:000000000000
70 Y -1:000000000000
71 $ hg bookmarks -l
71 $ hg bookmarks -l
72 X 0:f7b1eb17ad24
72 X 0:f7b1eb17ad24
73 * X2 0:f7b1eb17ad24
73 * X2 0:f7b1eb17ad24
74 Y -1:000000000000
74 Y -1:000000000000
75 $ hg bookmarks -l X Y
75 $ hg bookmarks -l X Y
76 X 0:f7b1eb17ad24
76 X 0:f7b1eb17ad24
77 Y -1:000000000000
77 Y -1:000000000000
78 $ hg bookmarks -l .
78 $ hg bookmarks -l .
79 * X2 0:f7b1eb17ad24
79 * X2 0:f7b1eb17ad24
80 $ hg bookmarks -l X A Y
80 $ hg bookmarks -l X A Y
81 abort: bookmark 'A' does not exist
81 abort: bookmark 'A' does not exist
82 [255]
82 [10]
83 $ hg bookmarks -l -r0
83 $ hg bookmarks -l -r0
84 abort: cannot specify both --list and --rev
84 abort: cannot specify both --list and --rev
85 [10]
85 [10]
86 $ hg bookmarks -l --inactive
86 $ hg bookmarks -l --inactive
87 abort: cannot specify both --inactive and --list
87 abort: cannot specify both --inactive and --list
88 [10]
88 [10]
89
89
90 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
90 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
91 0 X
91 0 X
92 0 X2
92 0 X2
93
93
94 $ echo b > b
94 $ echo b > b
95 $ hg add b
95 $ hg add b
96 $ hg commit -m 1 --config "$TESTHOOK"
96 $ hg commit -m 1 --config "$TESTHOOK"
97 test-hook-bookmark: X2: f7b1eb17ad24730a1651fccd46c43826d1bbc2ac -> 925d80f479bb026b0fb3deb27503780b13f74123
97 test-hook-bookmark: X2: f7b1eb17ad24730a1651fccd46c43826d1bbc2ac -> 925d80f479bb026b0fb3deb27503780b13f74123
98
98
99 $ hg bookmarks -T '{rev}:{node|shortest} {bookmark} {desc|firstline}\n'
99 $ hg bookmarks -T '{rev}:{node|shortest} {bookmark} {desc|firstline}\n'
100 0:f7b1 X 0
100 0:f7b1 X 0
101 1:925d X2 1
101 1:925d X2 1
102 -1:0000 Y
102 -1:0000 Y
103
103
104 $ hg bookmarks -Tjson
104 $ hg bookmarks -Tjson
105 [
105 [
106 {
106 {
107 "active": false,
107 "active": false,
108 "bookmark": "X",
108 "bookmark": "X",
109 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
109 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
110 "rev": 0
110 "rev": 0
111 },
111 },
112 {
112 {
113 "active": true,
113 "active": true,
114 "bookmark": "X2",
114 "bookmark": "X2",
115 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
115 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
116 "rev": 1
116 "rev": 1
117 },
117 },
118 {
118 {
119 "active": false,
119 "active": false,
120 "bookmark": "Y",
120 "bookmark": "Y",
121 "node": "0000000000000000000000000000000000000000",
121 "node": "0000000000000000000000000000000000000000",
122 "rev": -1
122 "rev": -1
123 }
123 }
124 ]
124 ]
125
125
126 bookmarks revset
126 bookmarks revset
127
127
128 $ hg log -r 'bookmark()'
128 $ hg log -r 'bookmark()'
129 changeset: 0:f7b1eb17ad24
129 changeset: 0:f7b1eb17ad24
130 bookmark: X
130 bookmark: X
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:00 1970 +0000
132 date: Thu Jan 01 00:00:00 1970 +0000
133 summary: 0
133 summary: 0
134
134
135 changeset: 1:925d80f479bb
135 changeset: 1:925d80f479bb
136 bookmark: X2
136 bookmark: X2
137 tag: tip
137 tag: tip
138 user: test
138 user: test
139 date: Thu Jan 01 00:00:00 1970 +0000
139 date: Thu Jan 01 00:00:00 1970 +0000
140 summary: 1
140 summary: 1
141
141
142 $ hg log -r 'bookmark(Y)'
142 $ hg log -r 'bookmark(Y)'
143 $ hg log -r 'bookmark(X2)'
143 $ hg log -r 'bookmark(X2)'
144 changeset: 1:925d80f479bb
144 changeset: 1:925d80f479bb
145 bookmark: X2
145 bookmark: X2
146 tag: tip
146 tag: tip
147 user: test
147 user: test
148 date: Thu Jan 01 00:00:00 1970 +0000
148 date: Thu Jan 01 00:00:00 1970 +0000
149 summary: 1
149 summary: 1
150
150
151 $ hg log -r 'bookmark("re:X")'
151 $ hg log -r 'bookmark("re:X")'
152 changeset: 0:f7b1eb17ad24
152 changeset: 0:f7b1eb17ad24
153 bookmark: X
153 bookmark: X
154 user: test
154 user: test
155 date: Thu Jan 01 00:00:00 1970 +0000
155 date: Thu Jan 01 00:00:00 1970 +0000
156 summary: 0
156 summary: 0
157
157
158 changeset: 1:925d80f479bb
158 changeset: 1:925d80f479bb
159 bookmark: X2
159 bookmark: X2
160 tag: tip
160 tag: tip
161 user: test
161 user: test
162 date: Thu Jan 01 00:00:00 1970 +0000
162 date: Thu Jan 01 00:00:00 1970 +0000
163 summary: 1
163 summary: 1
164
164
165 $ hg log -r 'bookmark("literal:X")'
165 $ hg log -r 'bookmark("literal:X")'
166 changeset: 0:f7b1eb17ad24
166 changeset: 0:f7b1eb17ad24
167 bookmark: X
167 bookmark: X
168 user: test
168 user: test
169 date: Thu Jan 01 00:00:00 1970 +0000
169 date: Thu Jan 01 00:00:00 1970 +0000
170 summary: 0
170 summary: 0
171
171
172
172
173 "." is expanded to the active bookmark:
173 "." is expanded to the active bookmark:
174
174
175 $ hg log -r 'bookmark(.)'
175 $ hg log -r 'bookmark(.)'
176 changeset: 1:925d80f479bb
176 changeset: 1:925d80f479bb
177 bookmark: X2
177 bookmark: X2
178 tag: tip
178 tag: tip
179 user: test
179 user: test
180 date: Thu Jan 01 00:00:00 1970 +0000
180 date: Thu Jan 01 00:00:00 1970 +0000
181 summary: 1
181 summary: 1
182
182
183
183
184 but "literal:." is not since "." seems not a literal bookmark:
184 but "literal:." is not since "." seems not a literal bookmark:
185
185
186 $ hg log -r 'bookmark("literal:.")'
186 $ hg log -r 'bookmark("literal:.")'
187 abort: bookmark '.' does not exist
187 abort: bookmark '.' does not exist
188 [255]
188 [255]
189
189
190 "." should fail if there's no active bookmark:
190 "." should fail if there's no active bookmark:
191
191
192 $ hg bookmark --inactive
192 $ hg bookmark --inactive
193 $ hg log -r 'bookmark(.)'
193 $ hg log -r 'bookmark(.)'
194 abort: no active bookmark
194 abort: no active bookmark
195 [255]
195 [255]
196 $ hg log -r 'present(bookmark(.))'
196 $ hg log -r 'present(bookmark(.))'
197
197
198 $ hg log -r 'bookmark(unknown)'
198 $ hg log -r 'bookmark(unknown)'
199 abort: bookmark 'unknown' does not exist
199 abort: bookmark 'unknown' does not exist
200 [255]
200 [255]
201 $ hg log -r 'bookmark("literal:unknown")'
201 $ hg log -r 'bookmark("literal:unknown")'
202 abort: bookmark 'unknown' does not exist
202 abort: bookmark 'unknown' does not exist
203 [255]
203 [255]
204 $ hg log -r 'bookmark("re:unknown")'
204 $ hg log -r 'bookmark("re:unknown")'
205 $ hg log -r 'present(bookmark("literal:unknown"))'
205 $ hg log -r 'present(bookmark("literal:unknown"))'
206 $ hg log -r 'present(bookmark("re:unknown"))'
206 $ hg log -r 'present(bookmark("re:unknown"))'
207
207
208 $ hg help revsets | grep 'bookmark('
208 $ hg help revsets | grep 'bookmark('
209 "bookmark([name])"
209 "bookmark([name])"
210
210
211 reactivate "X2"
211 reactivate "X2"
212
212
213 $ hg update X2
213 $ hg update X2
214 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
215 (activating bookmark X2)
215 (activating bookmark X2)
216
216
217 bookmarks X and X2 moved to rev 1, Y at rev -1
217 bookmarks X and X2 moved to rev 1, Y at rev -1
218
218
219 $ hg bookmarks
219 $ hg bookmarks
220 X 0:f7b1eb17ad24
220 X 0:f7b1eb17ad24
221 * X2 1:925d80f479bb
221 * X2 1:925d80f479bb
222 Y -1:000000000000
222 Y -1:000000000000
223
223
224 bookmark rev 0 again
224 bookmark rev 0 again
225
225
226 $ hg bookmark -r 0 Z
226 $ hg bookmark -r 0 Z
227
227
228 $ hg update X
228 $ hg update X
229 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
229 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
230 (activating bookmark X)
230 (activating bookmark X)
231 $ echo c > c
231 $ echo c > c
232 $ hg add c
232 $ hg add c
233 $ hg commit -m 2
233 $ hg commit -m 2
234 created new head
234 created new head
235
235
236 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
236 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
237
237
238 $ hg bookmarks
238 $ hg bookmarks
239 * X 2:db815d6d32e6
239 * X 2:db815d6d32e6
240 X2 1:925d80f479bb
240 X2 1:925d80f479bb
241 Y -1:000000000000
241 Y -1:000000000000
242 Z 0:f7b1eb17ad24
242 Z 0:f7b1eb17ad24
243
243
244 rename nonexistent bookmark
244 rename nonexistent bookmark
245
245
246 $ hg bookmark -m A B
246 $ hg bookmark -m A B
247 abort: bookmark 'A' does not exist
247 abort: bookmark 'A' does not exist
248 [255]
248 [10]
249
249
250 rename to existent bookmark
250 rename to existent bookmark
251
251
252 $ hg bookmark -m X Y
252 $ hg bookmark -m X Y
253 abort: bookmark 'Y' already exists (use -f to force)
253 abort: bookmark 'Y' already exists (use -f to force)
254 [255]
254 [255]
255
255
256 force rename to existent bookmark
256 force rename to existent bookmark
257
257
258 $ hg bookmark -f -m X Y
258 $ hg bookmark -f -m X Y
259
259
260 rename bookmark using .
260 rename bookmark using .
261
261
262 $ hg book rename-me
262 $ hg book rename-me
263 $ hg book -m . renamed --config "$TESTHOOK"
263 $ hg book -m . renamed --config "$TESTHOOK"
264 test-hook-bookmark: rename-me: db815d6d32e69058eadefc8cffbad37675707975 ->
264 test-hook-bookmark: rename-me: db815d6d32e69058eadefc8cffbad37675707975 ->
265 test-hook-bookmark: renamed: -> db815d6d32e69058eadefc8cffbad37675707975
265 test-hook-bookmark: renamed: -> db815d6d32e69058eadefc8cffbad37675707975
266 $ hg bookmark
266 $ hg bookmark
267 X2 1:925d80f479bb
267 X2 1:925d80f479bb
268 Y 2:db815d6d32e6
268 Y 2:db815d6d32e6
269 Z 0:f7b1eb17ad24
269 Z 0:f7b1eb17ad24
270 * renamed 2:db815d6d32e6
270 * renamed 2:db815d6d32e6
271 $ hg up -q Y
271 $ hg up -q Y
272 $ hg book -d renamed --config "$TESTHOOK"
272 $ hg book -d renamed --config "$TESTHOOK"
273 test-hook-bookmark: renamed: db815d6d32e69058eadefc8cffbad37675707975 ->
273 test-hook-bookmark: renamed: db815d6d32e69058eadefc8cffbad37675707975 ->
274
274
275 rename bookmark using . with no active bookmark
275 rename bookmark using . with no active bookmark
276
276
277 $ hg book rename-me
277 $ hg book rename-me
278 $ hg book -i rename-me
278 $ hg book -i rename-me
279 $ hg book -m . renamed
279 $ hg book -m . renamed
280 abort: no active bookmark
280 abort: no active bookmark
281 [255]
281 [255]
282 $ hg up -q Y
282 $ hg up -q Y
283 $ hg book -d rename-me
283 $ hg book -d rename-me
284
284
285 delete bookmark using .
285 delete bookmark using .
286
286
287 $ hg book delete-me
287 $ hg book delete-me
288 $ hg book -d .
288 $ hg book -d .
289 $ hg bookmark
289 $ hg bookmark
290 X2 1:925d80f479bb
290 X2 1:925d80f479bb
291 Y 2:db815d6d32e6
291 Y 2:db815d6d32e6
292 Z 0:f7b1eb17ad24
292 Z 0:f7b1eb17ad24
293 $ hg up -q Y
293 $ hg up -q Y
294
294
295 delete bookmark using . with no active bookmark
295 delete bookmark using . with no active bookmark
296
296
297 $ hg book delete-me
297 $ hg book delete-me
298 $ hg book -i delete-me
298 $ hg book -i delete-me
299 $ hg book -d .
299 $ hg book -d .
300 abort: no active bookmark
300 abort: no active bookmark
301 [255]
301 [255]
302 $ hg up -q Y
302 $ hg up -q Y
303 $ hg book -d delete-me
303 $ hg book -d delete-me
304
304
305 list bookmarks
305 list bookmarks
306
306
307 $ hg bookmark
307 $ hg bookmark
308 X2 1:925d80f479bb
308 X2 1:925d80f479bb
309 * Y 2:db815d6d32e6
309 * Y 2:db815d6d32e6
310 Z 0:f7b1eb17ad24
310 Z 0:f7b1eb17ad24
311
311
312 bookmarks from a revset
312 bookmarks from a revset
313 $ hg bookmark -r '.^1' REVSET
313 $ hg bookmark -r '.^1' REVSET
314 $ hg bookmark -r ':tip' TIP
314 $ hg bookmark -r ':tip' TIP
315 $ hg up -q TIP
315 $ hg up -q TIP
316 $ hg bookmarks
316 $ hg bookmarks
317 REVSET 0:f7b1eb17ad24
317 REVSET 0:f7b1eb17ad24
318 * TIP 2:db815d6d32e6
318 * TIP 2:db815d6d32e6
319 X2 1:925d80f479bb
319 X2 1:925d80f479bb
320 Y 2:db815d6d32e6
320 Y 2:db815d6d32e6
321 Z 0:f7b1eb17ad24
321 Z 0:f7b1eb17ad24
322
322
323 $ hg bookmark -d REVSET
323 $ hg bookmark -d REVSET
324 $ hg bookmark -d TIP
324 $ hg bookmark -d TIP
325
325
326 rename without new name or multiple names
326 rename without new name or multiple names
327
327
328 $ hg bookmark -m Y
328 $ hg bookmark -m Y
329 abort: new bookmark name required
329 abort: new bookmark name required
330 [10]
330 [10]
331 $ hg bookmark -m Y Y2 Y3
331 $ hg bookmark -m Y Y2 Y3
332 abort: only one new bookmark name allowed
332 abort: only one new bookmark name allowed
333 [10]
333 [10]
334
334
335 delete without name
335 delete without name
336
336
337 $ hg bookmark -d
337 $ hg bookmark -d
338 abort: bookmark name required
338 abort: bookmark name required
339 [10]
339 [10]
340
340
341 delete nonexistent bookmark
341 delete nonexistent bookmark
342
342
343 $ hg bookmark -d A
343 $ hg bookmark -d A
344 abort: bookmark 'A' does not exist
344 abort: bookmark 'A' does not exist
345 [255]
345 [10]
346
346
347 delete with --inactive
347 delete with --inactive
348
348
349 $ hg bookmark -d --inactive Y
349 $ hg bookmark -d --inactive Y
350 abort: cannot specify both --inactive and --delete
350 abort: cannot specify both --inactive and --delete
351 [10]
351 [10]
352
352
353 bookmark name with spaces should be stripped
353 bookmark name with spaces should be stripped
354
354
355 $ hg bookmark ' x y '
355 $ hg bookmark ' x y '
356
356
357 list bookmarks
357 list bookmarks
358
358
359 $ hg bookmarks
359 $ hg bookmarks
360 X2 1:925d80f479bb
360 X2 1:925d80f479bb
361 Y 2:db815d6d32e6
361 Y 2:db815d6d32e6
362 Z 0:f7b1eb17ad24
362 Z 0:f7b1eb17ad24
363 * x y 2:db815d6d32e6
363 * x y 2:db815d6d32e6
364 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
364 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
365 2 Y
365 2 Y
366 2 x y
366 2 x y
367 1 X2
367 1 X2
368 0 Z
368 0 Z
369
369
370 look up stripped bookmark name
370 look up stripped bookmark name
371
371
372 $ hg log -r '"x y"'
372 $ hg log -r '"x y"'
373 changeset: 2:db815d6d32e6
373 changeset: 2:db815d6d32e6
374 bookmark: Y
374 bookmark: Y
375 bookmark: x y
375 bookmark: x y
376 tag: tip
376 tag: tip
377 parent: 0:f7b1eb17ad24
377 parent: 0:f7b1eb17ad24
378 user: test
378 user: test
379 date: Thu Jan 01 00:00:00 1970 +0000
379 date: Thu Jan 01 00:00:00 1970 +0000
380 summary: 2
380 summary: 2
381
381
382
382
383 reject bookmark name with newline
383 reject bookmark name with newline
384
384
385 $ hg bookmark '
385 $ hg bookmark '
386 > '
386 > '
387 abort: bookmark names cannot consist entirely of whitespace
387 abort: bookmark names cannot consist entirely of whitespace
388 [255]
388 [10]
389
389
390 $ hg bookmark -m Z '
390 $ hg bookmark -m Z '
391 > '
391 > '
392 abort: bookmark names cannot consist entirely of whitespace
392 abort: bookmark names cannot consist entirely of whitespace
393 [255]
393 [10]
394
394
395 bookmark with reserved name
395 bookmark with reserved name
396
396
397 $ hg bookmark tip
397 $ hg bookmark tip
398 abort: the name 'tip' is reserved
398 abort: the name 'tip' is reserved
399 [10]
399 [10]
400
400
401 $ hg bookmark .
401 $ hg bookmark .
402 abort: the name '.' is reserved
402 abort: the name '.' is reserved
403 [10]
403 [10]
404
404
405 $ hg bookmark null
405 $ hg bookmark null
406 abort: the name 'null' is reserved
406 abort: the name 'null' is reserved
407 [10]
407 [10]
408
408
409
409
410 bookmark with existing name
410 bookmark with existing name
411
411
412 $ hg bookmark X2
412 $ hg bookmark X2
413 abort: bookmark 'X2' already exists (use -f to force)
413 abort: bookmark 'X2' already exists (use -f to force)
414 [255]
414 [255]
415
415
416 $ hg bookmark -m Y Z
416 $ hg bookmark -m Y Z
417 abort: bookmark 'Z' already exists (use -f to force)
417 abort: bookmark 'Z' already exists (use -f to force)
418 [255]
418 [255]
419
419
420 bookmark with name of branch
420 bookmark with name of branch
421
421
422 $ hg bookmark default
422 $ hg bookmark default
423 abort: a bookmark cannot have the name of an existing branch
423 abort: a bookmark cannot have the name of an existing branch
424 [255]
424 [255]
425
425
426 $ hg bookmark -m Y default
426 $ hg bookmark -m Y default
427 abort: a bookmark cannot have the name of an existing branch
427 abort: a bookmark cannot have the name of an existing branch
428 [255]
428 [255]
429
429
430 bookmark with integer name
430 bookmark with integer name
431
431
432 $ hg bookmark 10
432 $ hg bookmark 10
433 abort: cannot use an integer as a name
433 abort: cannot use an integer as a name
434 [10]
434 [10]
435
435
436 bookmark with a name that matches a node id
436 bookmark with a name that matches a node id
437 $ hg bookmark 925d80f479bb db815d6d32e6 --config "$TESTHOOK"
437 $ hg bookmark 925d80f479bb db815d6d32e6 --config "$TESTHOOK"
438 bookmark 925d80f479bb matches a changeset hash
438 bookmark 925d80f479bb matches a changeset hash
439 (did you leave a -r out of an 'hg bookmark' command?)
439 (did you leave a -r out of an 'hg bookmark' command?)
440 bookmark db815d6d32e6 matches a changeset hash
440 bookmark db815d6d32e6 matches a changeset hash
441 (did you leave a -r out of an 'hg bookmark' command?)
441 (did you leave a -r out of an 'hg bookmark' command?)
442 test-hook-bookmark: 925d80f479bb: -> db815d6d32e69058eadefc8cffbad37675707975
442 test-hook-bookmark: 925d80f479bb: -> db815d6d32e69058eadefc8cffbad37675707975
443 test-hook-bookmark: db815d6d32e6: -> db815d6d32e69058eadefc8cffbad37675707975
443 test-hook-bookmark: db815d6d32e6: -> db815d6d32e69058eadefc8cffbad37675707975
444 $ hg bookmark -d 925d80f479bb
444 $ hg bookmark -d 925d80f479bb
445 $ hg bookmark -d db815d6d32e6
445 $ hg bookmark -d db815d6d32e6
446
446
447 $ cd ..
447 $ cd ..
448
448
449 bookmark with a name that matches an ambiguous node id
449 bookmark with a name that matches an ambiguous node id
450
450
451 $ hg init ambiguous
451 $ hg init ambiguous
452 $ cd ambiguous
452 $ cd ambiguous
453 $ echo 0 > a
453 $ echo 0 > a
454 $ hg ci -qAm 0
454 $ hg ci -qAm 0
455 $ for i in 1057 2857 4025; do
455 $ for i in 1057 2857 4025; do
456 > hg up -q 0
456 > hg up -q 0
457 > echo $i > a
457 > echo $i > a
458 > hg ci -qm $i
458 > hg ci -qm $i
459 > done
459 > done
460 $ hg up -q null
460 $ hg up -q null
461 $ hg log -r0: -T '{rev}:{node}\n'
461 $ hg log -r0: -T '{rev}:{node}\n'
462 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
462 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
463 1:c56256a09cd28e5764f32e8e2810d0f01e2e357a
463 1:c56256a09cd28e5764f32e8e2810d0f01e2e357a
464 2:c5623987d205cd6d9d8389bfc40fff9dbb670b48
464 2:c5623987d205cd6d9d8389bfc40fff9dbb670b48
465 3:c562ddd9c94164376c20b86b0b4991636a3bf84f
465 3:c562ddd9c94164376c20b86b0b4991636a3bf84f
466
466
467 $ hg bookmark -r0 c562
467 $ hg bookmark -r0 c562
468 $ hg bookmarks
468 $ hg bookmarks
469 c562 0:b4e73ffab476
469 c562 0:b4e73ffab476
470
470
471 $ cd ..
471 $ cd ..
472
472
473 incompatible options
473 incompatible options
474
474
475 $ cd repo
475 $ cd repo
476
476
477 $ hg bookmark -m Y -d Z
477 $ hg bookmark -m Y -d Z
478 abort: cannot specify both --delete and --rename
478 abort: cannot specify both --delete and --rename
479 [10]
479 [10]
480
480
481 $ hg bookmark -r 1 -d Z
481 $ hg bookmark -r 1 -d Z
482 abort: cannot specify both --delete and --rev
482 abort: cannot specify both --delete and --rev
483 [10]
483 [10]
484
484
485 $ hg bookmark -r 1 -m Z Y
485 $ hg bookmark -r 1 -m Z Y
486 abort: cannot specify both --rename and --rev
486 abort: cannot specify both --rename and --rev
487 [10]
487 [10]
488
488
489 force bookmark with existing name
489 force bookmark with existing name
490
490
491 $ hg bookmark -f X2 --config "$TESTHOOK"
491 $ hg bookmark -f X2 --config "$TESTHOOK"
492 test-hook-bookmark: X2: 925d80f479bb026b0fb3deb27503780b13f74123 -> db815d6d32e69058eadefc8cffbad37675707975
492 test-hook-bookmark: X2: 925d80f479bb026b0fb3deb27503780b13f74123 -> db815d6d32e69058eadefc8cffbad37675707975
493
493
494 force bookmark back to where it was, should deactivate it
494 force bookmark back to where it was, should deactivate it
495
495
496 $ hg bookmark -fr1 X2
496 $ hg bookmark -fr1 X2
497 $ hg bookmarks
497 $ hg bookmarks
498 X2 1:925d80f479bb
498 X2 1:925d80f479bb
499 Y 2:db815d6d32e6
499 Y 2:db815d6d32e6
500 Z 0:f7b1eb17ad24
500 Z 0:f7b1eb17ad24
501 x y 2:db815d6d32e6
501 x y 2:db815d6d32e6
502
502
503 forward bookmark to descendant without --force
503 forward bookmark to descendant without --force
504
504
505 $ hg bookmark Z
505 $ hg bookmark Z
506 moving bookmark 'Z' forward from f7b1eb17ad24
506 moving bookmark 'Z' forward from f7b1eb17ad24
507
507
508 list bookmarks
508 list bookmarks
509
509
510 $ hg bookmark
510 $ hg bookmark
511 X2 1:925d80f479bb
511 X2 1:925d80f479bb
512 Y 2:db815d6d32e6
512 Y 2:db815d6d32e6
513 * Z 2:db815d6d32e6
513 * Z 2:db815d6d32e6
514 x y 2:db815d6d32e6
514 x y 2:db815d6d32e6
515 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
515 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
516 2 Y
516 2 Y
517 2 Z
517 2 Z
518 2 x y
518 2 x y
519 1 X2
519 1 X2
520
520
521 revision but no bookmark name
521 revision but no bookmark name
522
522
523 $ hg bookmark -r .
523 $ hg bookmark -r .
524 abort: bookmark name required
524 abort: bookmark name required
525 [10]
525 [10]
526
526
527 bookmark name with whitespace only
527 bookmark name with whitespace only
528
528
529 $ hg bookmark ' '
529 $ hg bookmark ' '
530 abort: bookmark names cannot consist entirely of whitespace
530 abort: bookmark names cannot consist entirely of whitespace
531 [255]
531 [10]
532
532
533 $ hg bookmark -m Y ' '
533 $ hg bookmark -m Y ' '
534 abort: bookmark names cannot consist entirely of whitespace
534 abort: bookmark names cannot consist entirely of whitespace
535 [255]
535 [10]
536
536
537 invalid bookmark
537 invalid bookmark
538
538
539 $ hg bookmark 'foo:bar'
539 $ hg bookmark 'foo:bar'
540 abort: ':' cannot be used in a name
540 abort: ':' cannot be used in a name
541 [10]
541 [10]
542
542
543 $ hg bookmark 'foo
543 $ hg bookmark 'foo
544 > bar'
544 > bar'
545 abort: '\n' cannot be used in a name
545 abort: '\n' cannot be used in a name
546 [10]
546 [10]
547
547
548 the bookmark extension should be ignored now that it is part of core
548 the bookmark extension should be ignored now that it is part of core
549
549
550 $ echo "[extensions]" >> $HGRCPATH
550 $ echo "[extensions]" >> $HGRCPATH
551 $ echo "bookmarks=" >> $HGRCPATH
551 $ echo "bookmarks=" >> $HGRCPATH
552 $ hg bookmarks
552 $ hg bookmarks
553 X2 1:925d80f479bb
553 X2 1:925d80f479bb
554 Y 2:db815d6d32e6
554 Y 2:db815d6d32e6
555 * Z 2:db815d6d32e6
555 * Z 2:db815d6d32e6
556 x y 2:db815d6d32e6
556 x y 2:db815d6d32e6
557
557
558 test summary
558 test summary
559
559
560 $ hg summary
560 $ hg summary
561 parent: 2:db815d6d32e6 tip
561 parent: 2:db815d6d32e6 tip
562 2
562 2
563 branch: default
563 branch: default
564 bookmarks: *Z Y x y
564 bookmarks: *Z Y x y
565 commit: (clean)
565 commit: (clean)
566 update: 1 new changesets, 2 branch heads (merge)
566 update: 1 new changesets, 2 branch heads (merge)
567 phases: 3 draft
567 phases: 3 draft
568
568
569 test id
569 test id
570
570
571 $ hg id
571 $ hg id
572 db815d6d32e6 tip Y/Z/x y
572 db815d6d32e6 tip Y/Z/x y
573
573
574 test rollback
574 test rollback
575
575
576 $ echo foo > f1
576 $ echo foo > f1
577 $ hg bookmark tmp-rollback
577 $ hg bookmark tmp-rollback
578 $ hg ci -Amr
578 $ hg ci -Amr
579 adding f1
579 adding f1
580 $ hg bookmarks
580 $ hg bookmarks
581 X2 1:925d80f479bb
581 X2 1:925d80f479bb
582 Y 2:db815d6d32e6
582 Y 2:db815d6d32e6
583 Z 2:db815d6d32e6
583 Z 2:db815d6d32e6
584 * tmp-rollback 3:2bf5cfec5864
584 * tmp-rollback 3:2bf5cfec5864
585 x y 2:db815d6d32e6
585 x y 2:db815d6d32e6
586 $ hg rollback
586 $ hg rollback
587 repository tip rolled back to revision 2 (undo commit)
587 repository tip rolled back to revision 2 (undo commit)
588 working directory now based on revision 2
588 working directory now based on revision 2
589 $ hg bookmarks
589 $ hg bookmarks
590 X2 1:925d80f479bb
590 X2 1:925d80f479bb
591 Y 2:db815d6d32e6
591 Y 2:db815d6d32e6
592 Z 2:db815d6d32e6
592 Z 2:db815d6d32e6
593 * tmp-rollback 2:db815d6d32e6
593 * tmp-rollback 2:db815d6d32e6
594 x y 2:db815d6d32e6
594 x y 2:db815d6d32e6
595 $ hg bookmark -f Z -r 1
595 $ hg bookmark -f Z -r 1
596 $ hg rollback
596 $ hg rollback
597 repository tip rolled back to revision 2 (undo bookmark)
597 repository tip rolled back to revision 2 (undo bookmark)
598 $ hg bookmarks
598 $ hg bookmarks
599 X2 1:925d80f479bb
599 X2 1:925d80f479bb
600 Y 2:db815d6d32e6
600 Y 2:db815d6d32e6
601 Z 2:db815d6d32e6
601 Z 2:db815d6d32e6
602 * tmp-rollback 2:db815d6d32e6
602 * tmp-rollback 2:db815d6d32e6
603 x y 2:db815d6d32e6
603 x y 2:db815d6d32e6
604 $ hg bookmark -d tmp-rollback
604 $ hg bookmark -d tmp-rollback
605
605
606 activate bookmark on working dir parent without --force
606 activate bookmark on working dir parent without --force
607
607
608 $ hg bookmark --inactive Z
608 $ hg bookmark --inactive Z
609 $ hg bookmark Z
609 $ hg bookmark Z
610
610
611 deactivate current 'Z', but also add 'Y'
611 deactivate current 'Z', but also add 'Y'
612
612
613 $ hg bookmark -d Y
613 $ hg bookmark -d Y
614 $ hg bookmark --inactive Z Y
614 $ hg bookmark --inactive Z Y
615 $ hg bookmark -l
615 $ hg bookmark -l
616 X2 1:925d80f479bb
616 X2 1:925d80f479bb
617 Y 2:db815d6d32e6
617 Y 2:db815d6d32e6
618 Z 2:db815d6d32e6
618 Z 2:db815d6d32e6
619 x y 2:db815d6d32e6
619 x y 2:db815d6d32e6
620 $ hg bookmark Z
620 $ hg bookmark Z
621
621
622 bookmark wdir to activate it (issue6218)
622 bookmark wdir to activate it (issue6218)
623
623
624 $ hg bookmark -d Z
624 $ hg bookmark -d Z
625 $ hg bookmark -r 'wdir()' Z
625 $ hg bookmark -r 'wdir()' Z
626 $ hg bookmark -l
626 $ hg bookmark -l
627 X2 1:925d80f479bb
627 X2 1:925d80f479bb
628 Y 2:db815d6d32e6
628 Y 2:db815d6d32e6
629 * Z 2:db815d6d32e6
629 * Z 2:db815d6d32e6
630 x y 2:db815d6d32e6
630 x y 2:db815d6d32e6
631
631
632 test clone
632 test clone
633
633
634 $ hg bookmark -r 2 -i @
634 $ hg bookmark -r 2 -i @
635 $ hg bookmark -r 2 -i a@
635 $ hg bookmark -r 2 -i a@
636 $ hg bookmarks
636 $ hg bookmarks
637 @ 2:db815d6d32e6
637 @ 2:db815d6d32e6
638 X2 1:925d80f479bb
638 X2 1:925d80f479bb
639 Y 2:db815d6d32e6
639 Y 2:db815d6d32e6
640 * Z 2:db815d6d32e6
640 * Z 2:db815d6d32e6
641 a@ 2:db815d6d32e6
641 a@ 2:db815d6d32e6
642 x y 2:db815d6d32e6
642 x y 2:db815d6d32e6
643 $ hg clone . cloned-bookmarks
643 $ hg clone . cloned-bookmarks
644 updating to bookmark @
644 updating to bookmark @
645 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
646 $ hg -R cloned-bookmarks bookmarks
646 $ hg -R cloned-bookmarks bookmarks
647 * @ 2:db815d6d32e6
647 * @ 2:db815d6d32e6
648 X2 1:925d80f479bb
648 X2 1:925d80f479bb
649 Y 2:db815d6d32e6
649 Y 2:db815d6d32e6
650 Z 2:db815d6d32e6
650 Z 2:db815d6d32e6
651 a@ 2:db815d6d32e6
651 a@ 2:db815d6d32e6
652 x y 2:db815d6d32e6
652 x y 2:db815d6d32e6
653
653
654 test clone with pull protocol
654 test clone with pull protocol
655
655
656 $ hg clone --pull . cloned-bookmarks-pull
656 $ hg clone --pull . cloned-bookmarks-pull
657 requesting all changes
657 requesting all changes
658 adding changesets
658 adding changesets
659 adding manifests
659 adding manifests
660 adding file changes
660 adding file changes
661 added 3 changesets with 3 changes to 3 files (+1 heads)
661 added 3 changesets with 3 changes to 3 files (+1 heads)
662 new changesets f7b1eb17ad24:db815d6d32e6
662 new changesets f7b1eb17ad24:db815d6d32e6
663 updating to bookmark @
663 updating to bookmark @
664 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
664 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
665 $ hg -R cloned-bookmarks-pull bookmarks
665 $ hg -R cloned-bookmarks-pull bookmarks
666 * @ 2:db815d6d32e6
666 * @ 2:db815d6d32e6
667 X2 1:925d80f479bb
667 X2 1:925d80f479bb
668 Y 2:db815d6d32e6
668 Y 2:db815d6d32e6
669 Z 2:db815d6d32e6
669 Z 2:db815d6d32e6
670 a@ 2:db815d6d32e6
670 a@ 2:db815d6d32e6
671 x y 2:db815d6d32e6
671 x y 2:db815d6d32e6
672
672
673 delete multiple bookmarks at once
673 delete multiple bookmarks at once
674
674
675 $ hg bookmark -d @ a@
675 $ hg bookmark -d @ a@
676
676
677 test clone with a bookmark named "default" (issue3677)
677 test clone with a bookmark named "default" (issue3677)
678
678
679 $ hg bookmark -r 1 -f -i default
679 $ hg bookmark -r 1 -f -i default
680 $ hg clone . cloned-bookmark-default
680 $ hg clone . cloned-bookmark-default
681 updating to branch default
681 updating to branch default
682 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
682 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
683 $ hg -R cloned-bookmark-default bookmarks
683 $ hg -R cloned-bookmark-default bookmarks
684 X2 1:925d80f479bb
684 X2 1:925d80f479bb
685 Y 2:db815d6d32e6
685 Y 2:db815d6d32e6
686 Z 2:db815d6d32e6
686 Z 2:db815d6d32e6
687 default 1:925d80f479bb
687 default 1:925d80f479bb
688 x y 2:db815d6d32e6
688 x y 2:db815d6d32e6
689 $ hg -R cloned-bookmark-default parents -q
689 $ hg -R cloned-bookmark-default parents -q
690 2:db815d6d32e6
690 2:db815d6d32e6
691 $ hg bookmark -d default
691 $ hg bookmark -d default
692
692
693 test clone with a specific revision
693 test clone with a specific revision
694
694
695 $ hg clone -r 925d80 . cloned-bookmarks-rev
695 $ hg clone -r 925d80 . cloned-bookmarks-rev
696 adding changesets
696 adding changesets
697 adding manifests
697 adding manifests
698 adding file changes
698 adding file changes
699 added 2 changesets with 2 changes to 2 files
699 added 2 changesets with 2 changes to 2 files
700 new changesets f7b1eb17ad24:925d80f479bb
700 new changesets f7b1eb17ad24:925d80f479bb
701 updating to branch default
701 updating to branch default
702 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
702 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
703 $ hg -R cloned-bookmarks-rev bookmarks
703 $ hg -R cloned-bookmarks-rev bookmarks
704 X2 1:925d80f479bb
704 X2 1:925d80f479bb
705
705
706 test clone with update to a bookmark
706 test clone with update to a bookmark
707
707
708 $ hg clone -u Z . ../cloned-bookmarks-update
708 $ hg clone -u Z . ../cloned-bookmarks-update
709 updating to branch default
709 updating to branch default
710 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
710 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
711 $ hg -R ../cloned-bookmarks-update bookmarks
711 $ hg -R ../cloned-bookmarks-update bookmarks
712 X2 1:925d80f479bb
712 X2 1:925d80f479bb
713 Y 2:db815d6d32e6
713 Y 2:db815d6d32e6
714 * Z 2:db815d6d32e6
714 * Z 2:db815d6d32e6
715 x y 2:db815d6d32e6
715 x y 2:db815d6d32e6
716
716
717 create bundle with two heads
717 create bundle with two heads
718
718
719 $ hg clone . tobundle
719 $ hg clone . tobundle
720 updating to branch default
720 updating to branch default
721 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
722 $ echo x > tobundle/x
722 $ echo x > tobundle/x
723 $ hg -R tobundle add tobundle/x
723 $ hg -R tobundle add tobundle/x
724 $ hg -R tobundle commit -m'x'
724 $ hg -R tobundle commit -m'x'
725 $ hg -R tobundle update -r -2
725 $ hg -R tobundle update -r -2
726 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
726 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
727 $ echo y > tobundle/y
727 $ echo y > tobundle/y
728 $ hg -R tobundle branch test
728 $ hg -R tobundle branch test
729 marked working directory as branch test
729 marked working directory as branch test
730 (branches are permanent and global, did you want a bookmark?)
730 (branches are permanent and global, did you want a bookmark?)
731 $ hg -R tobundle add tobundle/y
731 $ hg -R tobundle add tobundle/y
732 $ hg -R tobundle commit -m'y'
732 $ hg -R tobundle commit -m'y'
733 $ hg -R tobundle bundle tobundle.hg
733 $ hg -R tobundle bundle tobundle.hg
734 searching for changes
734 searching for changes
735 2 changesets found
735 2 changesets found
736 $ hg unbundle tobundle.hg
736 $ hg unbundle tobundle.hg
737 adding changesets
737 adding changesets
738 adding manifests
738 adding manifests
739 adding file changes
739 adding file changes
740 added 2 changesets with 2 changes to 2 files (+1 heads)
740 added 2 changesets with 2 changes to 2 files (+1 heads)
741 new changesets 125c9a1d6df6:9ba5f110a0b3 (2 drafts)
741 new changesets 125c9a1d6df6:9ba5f110a0b3 (2 drafts)
742 (run 'hg heads' to see heads, 'hg merge' to merge)
742 (run 'hg heads' to see heads, 'hg merge' to merge)
743
743
744 update to active bookmark if it's not the parent
744 update to active bookmark if it's not the parent
745
745
746 (it is known issue that fsmonitor can't handle nested repositories. In
746 (it is known issue that fsmonitor can't handle nested repositories. In
747 this test scenario, cloned-bookmark-default and tobundle exist in the
747 this test scenario, cloned-bookmark-default and tobundle exist in the
748 working directory of current repository)
748 working directory of current repository)
749
749
750 $ hg summary
750 $ hg summary
751 parent: 2:db815d6d32e6
751 parent: 2:db815d6d32e6
752 2
752 2
753 branch: default
753 branch: default
754 bookmarks: *Z Y x y
754 bookmarks: *Z Y x y
755 commit: 1 added, 1 unknown (new branch head) (no-fsmonitor !)
755 commit: 1 added, 1 unknown (new branch head) (no-fsmonitor !)
756 commit: 1 added, * unknown (new branch head) (glob) (fsmonitor !)
756 commit: 1 added, * unknown (new branch head) (glob) (fsmonitor !)
757 update: 2 new changesets (update)
757 update: 2 new changesets (update)
758 phases: 5 draft
758 phases: 5 draft
759 $ hg update
759 $ hg update
760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
761 updating bookmark Z
761 updating bookmark Z
762 $ hg bookmarks
762 $ hg bookmarks
763 X2 1:925d80f479bb
763 X2 1:925d80f479bb
764 Y 2:db815d6d32e6
764 Y 2:db815d6d32e6
765 * Z 3:125c9a1d6df6
765 * Z 3:125c9a1d6df6
766 x y 2:db815d6d32e6
766 x y 2:db815d6d32e6
767
767
768 pull --update works the same as pull && update
768 pull --update works the same as pull && update
769
769
770 $ hg bookmark -r3 Y
770 $ hg bookmark -r3 Y
771 moving bookmark 'Y' forward from db815d6d32e6
771 moving bookmark 'Y' forward from db815d6d32e6
772 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
772 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
773 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
773 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
774
774
775 (manual version)
775 (manual version)
776
776
777 $ hg -R ../cloned-bookmarks-manual-update update Y
777 $ hg -R ../cloned-bookmarks-manual-update update Y
778 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
778 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
779 (activating bookmark Y)
779 (activating bookmark Y)
780 $ hg -R ../cloned-bookmarks-manual-update pull .
780 $ hg -R ../cloned-bookmarks-manual-update pull .
781 pulling from .
781 pulling from .
782 searching for changes
782 searching for changes
783 adding changesets
783 adding changesets
784 adding manifests
784 adding manifests
785 adding file changes
785 adding file changes
786 updating bookmark Y
786 updating bookmark Y
787 updating bookmark Z
787 updating bookmark Z
788 added 2 changesets with 2 changes to 2 files (+1 heads)
788 added 2 changesets with 2 changes to 2 files (+1 heads)
789 new changesets 125c9a1d6df6:9ba5f110a0b3
789 new changesets 125c9a1d6df6:9ba5f110a0b3
790 (run 'hg heads' to see heads, 'hg merge' to merge)
790 (run 'hg heads' to see heads, 'hg merge' to merge)
791
791
792 (# tests strange but with --date crashing when bookmark have to move)
792 (# tests strange but with --date crashing when bookmark have to move)
793
793
794 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
794 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
795 abort: revision matching date not found
795 abort: revision matching date not found
796 [10]
796 [10]
797 $ hg -R ../cloned-bookmarks-manual-update update
797 $ hg -R ../cloned-bookmarks-manual-update update
798 updating to active bookmark Y
798 updating to active bookmark Y
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
800
800
801 (all in one version)
801 (all in one version)
802
802
803 $ hg -R ../cloned-bookmarks-update update Y
803 $ hg -R ../cloned-bookmarks-update update Y
804 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
804 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
805 (activating bookmark Y)
805 (activating bookmark Y)
806 $ hg -R ../cloned-bookmarks-update pull --update .
806 $ hg -R ../cloned-bookmarks-update pull --update .
807 pulling from .
807 pulling from .
808 searching for changes
808 searching for changes
809 adding changesets
809 adding changesets
810 adding manifests
810 adding manifests
811 adding file changes
811 adding file changes
812 updating bookmark Y
812 updating bookmark Y
813 updating bookmark Z
813 updating bookmark Z
814 added 2 changesets with 2 changes to 2 files (+1 heads)
814 added 2 changesets with 2 changes to 2 files (+1 heads)
815 new changesets 125c9a1d6df6:9ba5f110a0b3
815 new changesets 125c9a1d6df6:9ba5f110a0b3
816 updating to active bookmark Y
816 updating to active bookmark Y
817 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
817 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
818
818
819 We warn about divergent during bare update to the active bookmark
819 We warn about divergent during bare update to the active bookmark
820
820
821 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
821 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
822 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
823 (activating bookmark Y)
823 (activating bookmark Y)
824 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
824 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
825 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
825 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
826 X2 1:925d80f479bb
826 X2 1:925d80f479bb
827 * Y 2:db815d6d32e6
827 * Y 2:db815d6d32e6
828 Y@1 1:925d80f479bb
828 Y@1 1:925d80f479bb
829 Z 2:db815d6d32e6
829 Z 2:db815d6d32e6
830 x y 2:db815d6d32e6
830 x y 2:db815d6d32e6
831 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
831 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
832 pulling from $TESTTMP/repo
832 pulling from $TESTTMP/repo
833 searching for changes
833 searching for changes
834 adding changesets
834 adding changesets
835 adding manifests
835 adding manifests
836 adding file changes
836 adding file changes
837 updating bookmark Y
837 updating bookmark Y
838 updating bookmark Z
838 updating bookmark Z
839 added 2 changesets with 2 changes to 2 files (+1 heads)
839 added 2 changesets with 2 changes to 2 files (+1 heads)
840 new changesets 125c9a1d6df6:9ba5f110a0b3
840 new changesets 125c9a1d6df6:9ba5f110a0b3
841 (run 'hg heads' to see heads, 'hg merge' to merge)
841 (run 'hg heads' to see heads, 'hg merge' to merge)
842 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
842 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
843 updating to active bookmark Y
843 updating to active bookmark Y
844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 1 other divergent bookmarks for "Y"
845 1 other divergent bookmarks for "Y"
846
846
847 test wrongly formated bookmark
847 test wrongly formated bookmark
848
848
849 $ echo '' >> .hg/bookmarks
849 $ echo '' >> .hg/bookmarks
850 $ hg bookmarks
850 $ hg bookmarks
851 X2 1:925d80f479bb
851 X2 1:925d80f479bb
852 Y 3:125c9a1d6df6
852 Y 3:125c9a1d6df6
853 * Z 3:125c9a1d6df6
853 * Z 3:125c9a1d6df6
854 x y 2:db815d6d32e6
854 x y 2:db815d6d32e6
855 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
855 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
856 $ hg bookmarks
856 $ hg bookmarks
857 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
857 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
858 X2 1:925d80f479bb
858 X2 1:925d80f479bb
859 Y 3:125c9a1d6df6
859 Y 3:125c9a1d6df6
860 * Z 3:125c9a1d6df6
860 * Z 3:125c9a1d6df6
861 x y 2:db815d6d32e6
861 x y 2:db815d6d32e6
862
862
863 test missing revisions
863 test missing revisions
864
864
865 $ echo "925d80f479b925d80f479bc925d80f479bccabab z" > .hg/bookmarks
865 $ echo "925d80f479b925d80f479bc925d80f479bccabab z" > .hg/bookmarks
866 $ hg book
866 $ hg book
867 no bookmarks set
867 no bookmarks set
868
868
869 test stripping a non-checked-out but bookmarked revision
869 test stripping a non-checked-out but bookmarked revision
870
870
871 $ hg log --graph
871 $ hg log --graph
872 o changeset: 4:9ba5f110a0b3
872 o changeset: 4:9ba5f110a0b3
873 | branch: test
873 | branch: test
874 | tag: tip
874 | tag: tip
875 | parent: 2:db815d6d32e6
875 | parent: 2:db815d6d32e6
876 | user: test
876 | user: test
877 | date: Thu Jan 01 00:00:00 1970 +0000
877 | date: Thu Jan 01 00:00:00 1970 +0000
878 | summary: y
878 | summary: y
879 |
879 |
880 | @ changeset: 3:125c9a1d6df6
880 | @ changeset: 3:125c9a1d6df6
881 |/ user: test
881 |/ user: test
882 | date: Thu Jan 01 00:00:00 1970 +0000
882 | date: Thu Jan 01 00:00:00 1970 +0000
883 | summary: x
883 | summary: x
884 |
884 |
885 o changeset: 2:db815d6d32e6
885 o changeset: 2:db815d6d32e6
886 | parent: 0:f7b1eb17ad24
886 | parent: 0:f7b1eb17ad24
887 | user: test
887 | user: test
888 | date: Thu Jan 01 00:00:00 1970 +0000
888 | date: Thu Jan 01 00:00:00 1970 +0000
889 | summary: 2
889 | summary: 2
890 |
890 |
891 | o changeset: 1:925d80f479bb
891 | o changeset: 1:925d80f479bb
892 |/ user: test
892 |/ user: test
893 | date: Thu Jan 01 00:00:00 1970 +0000
893 | date: Thu Jan 01 00:00:00 1970 +0000
894 | summary: 1
894 | summary: 1
895 |
895 |
896 o changeset: 0:f7b1eb17ad24
896 o changeset: 0:f7b1eb17ad24
897 user: test
897 user: test
898 date: Thu Jan 01 00:00:00 1970 +0000
898 date: Thu Jan 01 00:00:00 1970 +0000
899 summary: 0
899 summary: 0
900
900
901 $ hg book should-end-on-two
901 $ hg book should-end-on-two
902 $ hg co --clean 4
902 $ hg co --clean 4
903 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
903 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
904 (leaving bookmark should-end-on-two)
904 (leaving bookmark should-end-on-two)
905 $ hg book four
905 $ hg book four
906 $ hg --config extensions.mq= strip 3
906 $ hg --config extensions.mq= strip 3
907 saved backup bundle to * (glob)
907 saved backup bundle to * (glob)
908 should-end-on-two should end up pointing to revision 2, as that's the
908 should-end-on-two should end up pointing to revision 2, as that's the
909 tipmost surviving ancestor of the stripped revision.
909 tipmost surviving ancestor of the stripped revision.
910 $ hg log --graph
910 $ hg log --graph
911 @ changeset: 3:9ba5f110a0b3
911 @ changeset: 3:9ba5f110a0b3
912 | branch: test
912 | branch: test
913 | bookmark: four
913 | bookmark: four
914 | tag: tip
914 | tag: tip
915 | user: test
915 | user: test
916 | date: Thu Jan 01 00:00:00 1970 +0000
916 | date: Thu Jan 01 00:00:00 1970 +0000
917 | summary: y
917 | summary: y
918 |
918 |
919 o changeset: 2:db815d6d32e6
919 o changeset: 2:db815d6d32e6
920 | bookmark: should-end-on-two
920 | bookmark: should-end-on-two
921 | parent: 0:f7b1eb17ad24
921 | parent: 0:f7b1eb17ad24
922 | user: test
922 | user: test
923 | date: Thu Jan 01 00:00:00 1970 +0000
923 | date: Thu Jan 01 00:00:00 1970 +0000
924 | summary: 2
924 | summary: 2
925 |
925 |
926 | o changeset: 1:925d80f479bb
926 | o changeset: 1:925d80f479bb
927 |/ user: test
927 |/ user: test
928 | date: Thu Jan 01 00:00:00 1970 +0000
928 | date: Thu Jan 01 00:00:00 1970 +0000
929 | summary: 1
929 | summary: 1
930 |
930 |
931 o changeset: 0:f7b1eb17ad24
931 o changeset: 0:f7b1eb17ad24
932 user: test
932 user: test
933 date: Thu Jan 01 00:00:00 1970 +0000
933 date: Thu Jan 01 00:00:00 1970 +0000
934 summary: 0
934 summary: 0
935
935
936
936
937 no-op update doesn't deactivate bookmarks
937 no-op update doesn't deactivate bookmarks
938
938
939 (it is known issue that fsmonitor can't handle nested repositories. In
939 (it is known issue that fsmonitor can't handle nested repositories. In
940 this test scenario, cloned-bookmark-default and tobundle exist in the
940 this test scenario, cloned-bookmark-default and tobundle exist in the
941 working directory of current repository)
941 working directory of current repository)
942
942
943 $ hg bookmarks
943 $ hg bookmarks
944 * four 3:9ba5f110a0b3
944 * four 3:9ba5f110a0b3
945 should-end-on-two 2:db815d6d32e6
945 should-end-on-two 2:db815d6d32e6
946 $ hg up four
946 $ hg up four
947 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
947 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
948 $ hg up
948 $ hg up
949 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
949 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
950 $ hg sum
950 $ hg sum
951 parent: 3:9ba5f110a0b3 tip
951 parent: 3:9ba5f110a0b3 tip
952 y
952 y
953 branch: test
953 branch: test
954 bookmarks: *four
954 bookmarks: *four
955 commit: 2 unknown (clean) (no-fsmonitor !)
955 commit: 2 unknown (clean) (no-fsmonitor !)
956 commit: * unknown (clean) (glob) (fsmonitor !)
956 commit: * unknown (clean) (glob) (fsmonitor !)
957 update: (current)
957 update: (current)
958 phases: 4 draft
958 phases: 4 draft
959
959
960 test clearing divergent bookmarks of linear ancestors
960 test clearing divergent bookmarks of linear ancestors
961
961
962 $ hg bookmark Z -r 0
962 $ hg bookmark Z -r 0
963 $ hg bookmark Z@1 -r 1
963 $ hg bookmark Z@1 -r 1
964 $ hg bookmark Z@2 -r 2
964 $ hg bookmark Z@2 -r 2
965 $ hg bookmark Z@3 -r 3
965 $ hg bookmark Z@3 -r 3
966 $ hg book
966 $ hg book
967 Z 0:f7b1eb17ad24
967 Z 0:f7b1eb17ad24
968 Z@1 1:925d80f479bb
968 Z@1 1:925d80f479bb
969 Z@2 2:db815d6d32e6
969 Z@2 2:db815d6d32e6
970 Z@3 3:9ba5f110a0b3
970 Z@3 3:9ba5f110a0b3
971 * four 3:9ba5f110a0b3
971 * four 3:9ba5f110a0b3
972 should-end-on-two 2:db815d6d32e6
972 should-end-on-two 2:db815d6d32e6
973 $ hg bookmark Z
973 $ hg bookmark Z
974 moving bookmark 'Z' forward from f7b1eb17ad24
974 moving bookmark 'Z' forward from f7b1eb17ad24
975 $ hg book
975 $ hg book
976 * Z 3:9ba5f110a0b3
976 * Z 3:9ba5f110a0b3
977 Z@1 1:925d80f479bb
977 Z@1 1:925d80f479bb
978 four 3:9ba5f110a0b3
978 four 3:9ba5f110a0b3
979 should-end-on-two 2:db815d6d32e6
979 should-end-on-two 2:db815d6d32e6
980
980
981 test clearing only a single divergent bookmark across branches
981 test clearing only a single divergent bookmark across branches
982
982
983 $ hg book foo -r 1
983 $ hg book foo -r 1
984 $ hg book foo@1 -r 0
984 $ hg book foo@1 -r 0
985 $ hg book foo@2 -r 2
985 $ hg book foo@2 -r 2
986 $ hg book foo@3 -r 3
986 $ hg book foo@3 -r 3
987 $ hg book foo -r foo@3
987 $ hg book foo -r foo@3
988 $ hg book
988 $ hg book
989 * Z 3:9ba5f110a0b3
989 * Z 3:9ba5f110a0b3
990 Z@1 1:925d80f479bb
990 Z@1 1:925d80f479bb
991 foo 3:9ba5f110a0b3
991 foo 3:9ba5f110a0b3
992 foo@1 0:f7b1eb17ad24
992 foo@1 0:f7b1eb17ad24
993 foo@2 2:db815d6d32e6
993 foo@2 2:db815d6d32e6
994 four 3:9ba5f110a0b3
994 four 3:9ba5f110a0b3
995 should-end-on-two 2:db815d6d32e6
995 should-end-on-two 2:db815d6d32e6
996
996
997 pull --update works the same as pull && update (case #2)
997 pull --update works the same as pull && update (case #2)
998
998
999 It is assumed that "hg pull" itself doesn't update current active
999 It is assumed that "hg pull" itself doesn't update current active
1000 bookmark ('Y' in tests below).
1000 bookmark ('Y' in tests below).
1001
1001
1002 $ hg pull -q ../cloned-bookmarks-update
1002 $ hg pull -q ../cloned-bookmarks-update
1003 divergent bookmark Z stored as Z@2
1003 divergent bookmark Z stored as Z@2
1004
1004
1005 (pulling revision on another named branch with --update updates
1005 (pulling revision on another named branch with --update updates
1006 neither the working directory nor current active bookmark: "no-op"
1006 neither the working directory nor current active bookmark: "no-op"
1007 case)
1007 case)
1008
1008
1009 $ echo yy >> y
1009 $ echo yy >> y
1010 $ hg commit -m yy
1010 $ hg commit -m yy
1011
1011
1012 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1012 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1013 * Y 3:125c9a1d6df6
1013 * Y 3:125c9a1d6df6
1014 $ hg -R ../cloned-bookmarks-update pull . --update
1014 $ hg -R ../cloned-bookmarks-update pull . --update
1015 pulling from .
1015 pulling from .
1016 searching for changes
1016 searching for changes
1017 adding changesets
1017 adding changesets
1018 adding manifests
1018 adding manifests
1019 adding file changes
1019 adding file changes
1020 divergent bookmark Z stored as Z@default
1020 divergent bookmark Z stored as Z@default
1021 adding remote bookmark foo
1021 adding remote bookmark foo
1022 adding remote bookmark four
1022 adding remote bookmark four
1023 adding remote bookmark should-end-on-two
1023 adding remote bookmark should-end-on-two
1024 added 1 changesets with 1 changes to 1 files
1024 added 1 changesets with 1 changes to 1 files
1025 new changesets 5fb12f0f2d51
1025 new changesets 5fb12f0f2d51
1026 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1026 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1027 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1027 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1028 3:125c9a1d6df6
1028 3:125c9a1d6df6
1029 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1029 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1030 * Y 3:125c9a1d6df6
1030 * Y 3:125c9a1d6df6
1031
1031
1032 (pulling revision on current named/topological branch with --update
1032 (pulling revision on current named/topological branch with --update
1033 updates the working directory and current active bookmark)
1033 updates the working directory and current active bookmark)
1034
1034
1035 $ hg update -C -q 125c9a1d6df6
1035 $ hg update -C -q 125c9a1d6df6
1036 $ echo xx >> x
1036 $ echo xx >> x
1037 $ hg commit -m xx
1037 $ hg commit -m xx
1038
1038
1039 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1039 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1040 * Y 3:125c9a1d6df6
1040 * Y 3:125c9a1d6df6
1041 $ hg -R ../cloned-bookmarks-update pull . --update
1041 $ hg -R ../cloned-bookmarks-update pull . --update
1042 pulling from .
1042 pulling from .
1043 searching for changes
1043 searching for changes
1044 adding changesets
1044 adding changesets
1045 adding manifests
1045 adding manifests
1046 adding file changes
1046 adding file changes
1047 divergent bookmark Z stored as Z@default
1047 divergent bookmark Z stored as Z@default
1048 added 1 changesets with 1 changes to 1 files
1048 added 1 changesets with 1 changes to 1 files
1049 new changesets 81dcce76aa0b
1049 new changesets 81dcce76aa0b
1050 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1050 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1051 updating bookmark Y
1051 updating bookmark Y
1052 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1052 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1053 6:81dcce76aa0b
1053 6:81dcce76aa0b
1054 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1054 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1055 * Y 6:81dcce76aa0b
1055 * Y 6:81dcce76aa0b
1056
1056
1057 $ cd ..
1057 $ cd ..
1058
1058
1059 ensure changelog is written before bookmarks
1059 ensure changelog is written before bookmarks
1060 $ hg init orderrepo
1060 $ hg init orderrepo
1061 $ cd orderrepo
1061 $ cd orderrepo
1062 $ touch a
1062 $ touch a
1063 $ hg commit -Aqm one
1063 $ hg commit -Aqm one
1064 $ hg book mybook
1064 $ hg book mybook
1065 $ echo a > a
1065 $ echo a > a
1066
1066
1067 $ cat > $TESTTMP/pausefinalize.py <<EOF
1067 $ cat > $TESTTMP/pausefinalize.py <<EOF
1068 > from __future__ import absolute_import
1068 > from __future__ import absolute_import
1069 > import os
1069 > import os
1070 > import time
1070 > import time
1071 > from mercurial import extensions, localrepo
1071 > from mercurial import extensions, localrepo
1072 > def transaction(orig, self, desc, report=None):
1072 > def transaction(orig, self, desc, report=None):
1073 > tr = orig(self, desc, report)
1073 > tr = orig(self, desc, report)
1074 > def sleep(*args, **kwargs):
1074 > def sleep(*args, **kwargs):
1075 > retry = 20
1075 > retry = 20
1076 > while retry > 0 and not os.path.exists(b"$TESTTMP/unpause"):
1076 > while retry > 0 and not os.path.exists(b"$TESTTMP/unpause"):
1077 > retry -= 1
1077 > retry -= 1
1078 > time.sleep(0.5)
1078 > time.sleep(0.5)
1079 > if os.path.exists(b"$TESTTMP/unpause"):
1079 > if os.path.exists(b"$TESTTMP/unpause"):
1080 > os.remove(b"$TESTTMP/unpause")
1080 > os.remove(b"$TESTTMP/unpause")
1081 > # It is important that this finalizer start with 'a', so it runs before
1081 > # It is important that this finalizer start with 'a', so it runs before
1082 > # the changelog finalizer appends to the changelog.
1082 > # the changelog finalizer appends to the changelog.
1083 > tr.addfinalize(b'a-sleep', sleep)
1083 > tr.addfinalize(b'a-sleep', sleep)
1084 > return tr
1084 > return tr
1085 >
1085 >
1086 > def extsetup(ui):
1086 > def extsetup(ui):
1087 > # This extension inserts an artifical pause during the transaction
1087 > # This extension inserts an artifical pause during the transaction
1088 > # finalizer, so we can run commands mid-transaction-close.
1088 > # finalizer, so we can run commands mid-transaction-close.
1089 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
1089 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
1090 > transaction)
1090 > transaction)
1091 > EOF
1091 > EOF
1092 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
1092 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
1093 $ sleep 2
1093 $ sleep 2
1094 $ hg log -r .
1094 $ hg log -r .
1095 changeset: 0:867bc5792c8c
1095 changeset: 0:867bc5792c8c
1096 bookmark: mybook
1096 bookmark: mybook
1097 tag: tip
1097 tag: tip
1098 user: test
1098 user: test
1099 date: Thu Jan 01 00:00:00 1970 +0000
1099 date: Thu Jan 01 00:00:00 1970 +0000
1100 summary: one
1100 summary: one
1101
1101
1102 $ hg bookmarks
1102 $ hg bookmarks
1103 * mybook 0:867bc5792c8c
1103 * mybook 0:867bc5792c8c
1104 $ touch $TESTTMP/unpause
1104 $ touch $TESTTMP/unpause
1105
1105
1106 $ cd ..
1106 $ cd ..
1107
1107
1108 check whether HG_PENDING makes pending changes only in related
1108 check whether HG_PENDING makes pending changes only in related
1109 repositories visible to an external hook.
1109 repositories visible to an external hook.
1110
1110
1111 (emulate a transaction running concurrently by copied
1111 (emulate a transaction running concurrently by copied
1112 .hg/bookmarks.pending in subsequent test)
1112 .hg/bookmarks.pending in subsequent test)
1113
1113
1114 $ cat > $TESTTMP/savepending.sh <<EOF
1114 $ cat > $TESTTMP/savepending.sh <<EOF
1115 > cp .hg/bookmarks.pending .hg/bookmarks.pending.saved
1115 > cp .hg/bookmarks.pending .hg/bookmarks.pending.saved
1116 > exit 1 # to avoid adding new bookmark for subsequent tests
1116 > exit 1 # to avoid adding new bookmark for subsequent tests
1117 > EOF
1117 > EOF
1118
1118
1119 $ hg init unrelated
1119 $ hg init unrelated
1120 $ cd unrelated
1120 $ cd unrelated
1121 $ echo a > a
1121 $ echo a > a
1122 $ hg add a
1122 $ hg add a
1123 $ hg commit -m '#0'
1123 $ hg commit -m '#0'
1124 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" bookmarks INVISIBLE
1124 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" bookmarks INVISIBLE
1125 transaction abort!
1125 transaction abort!
1126 rollback completed
1126 rollback completed
1127 abort: pretxnclose hook exited with status 1
1127 abort: pretxnclose hook exited with status 1
1128 [255]
1128 [255]
1129 $ cp .hg/bookmarks.pending.saved .hg/bookmarks.pending
1129 $ cp .hg/bookmarks.pending.saved .hg/bookmarks.pending
1130
1130
1131 (check visible bookmarks while transaction running in repo)
1131 (check visible bookmarks while transaction running in repo)
1132
1132
1133 $ cat > $TESTTMP/checkpending.sh <<EOF
1133 $ cat > $TESTTMP/checkpending.sh <<EOF
1134 > echo "@repo"
1134 > echo "@repo"
1135 > hg -R "$TESTTMP/repo" bookmarks
1135 > hg -R "$TESTTMP/repo" bookmarks
1136 > echo "@unrelated"
1136 > echo "@unrelated"
1137 > hg -R "$TESTTMP/unrelated" bookmarks
1137 > hg -R "$TESTTMP/unrelated" bookmarks
1138 > exit 1 # to avoid adding new bookmark for subsequent tests
1138 > exit 1 # to avoid adding new bookmark for subsequent tests
1139 > EOF
1139 > EOF
1140
1140
1141 $ cd ../repo
1141 $ cd ../repo
1142 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" bookmarks NEW
1142 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" bookmarks NEW
1143 @repo
1143 @repo
1144 * NEW 6:81dcce76aa0b
1144 * NEW 6:81dcce76aa0b
1145 X2 1:925d80f479bb
1145 X2 1:925d80f479bb
1146 Y 4:125c9a1d6df6
1146 Y 4:125c9a1d6df6
1147 Z 5:5fb12f0f2d51
1147 Z 5:5fb12f0f2d51
1148 Z@1 1:925d80f479bb
1148 Z@1 1:925d80f479bb
1149 Z@2 4:125c9a1d6df6
1149 Z@2 4:125c9a1d6df6
1150 foo 3:9ba5f110a0b3
1150 foo 3:9ba5f110a0b3
1151 foo@1 0:f7b1eb17ad24
1151 foo@1 0:f7b1eb17ad24
1152 foo@2 2:db815d6d32e6
1152 foo@2 2:db815d6d32e6
1153 four 3:9ba5f110a0b3
1153 four 3:9ba5f110a0b3
1154 should-end-on-two 2:db815d6d32e6
1154 should-end-on-two 2:db815d6d32e6
1155 x y 2:db815d6d32e6
1155 x y 2:db815d6d32e6
1156 @unrelated
1156 @unrelated
1157 no bookmarks set
1157 no bookmarks set
1158 transaction abort!
1158 transaction abort!
1159 rollback completed
1159 rollback completed
1160 abort: pretxnclose hook exited with status 1
1160 abort: pretxnclose hook exited with status 1
1161 [255]
1161 [255]
1162
1162
1163 Check pretxnclose-bookmark can abort a transaction
1163 Check pretxnclose-bookmark can abort a transaction
1164 --------------------------------------------------
1164 --------------------------------------------------
1165
1165
1166 add hooks:
1166 add hooks:
1167
1167
1168 * to prevent NEW bookmark on a non-public changeset
1168 * to prevent NEW bookmark on a non-public changeset
1169 * to prevent non-forward move of NEW bookmark
1169 * to prevent non-forward move of NEW bookmark
1170
1170
1171 $ cat << EOF >> .hg/hgrc
1171 $ cat << EOF >> .hg/hgrc
1172 > [hooks]
1172 > [hooks]
1173 > pretxnclose-bookmark.force-public = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"\$HG_NODE\" -T '{phase}' | grep public > /dev/null)"
1173 > pretxnclose-bookmark.force-public = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"\$HG_NODE\" -T '{phase}' | grep public > /dev/null)"
1174 > pretxnclose-bookmark.force-forward = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"max(\$HG_OLDNODE::\$HG_NODE)\" -T 'MATCH' | grep MATCH > /dev/null)"
1174 > pretxnclose-bookmark.force-forward = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"max(\$HG_OLDNODE::\$HG_NODE)\" -T 'MATCH' | grep MATCH > /dev/null)"
1175 > EOF
1175 > EOF
1176
1176
1177 $ hg log -G -T phases
1177 $ hg log -G -T phases
1178 @ changeset: 6:81dcce76aa0b
1178 @ changeset: 6:81dcce76aa0b
1179 | tag: tip
1179 | tag: tip
1180 | phase: draft
1180 | phase: draft
1181 | parent: 4:125c9a1d6df6
1181 | parent: 4:125c9a1d6df6
1182 | user: test
1182 | user: test
1183 | date: Thu Jan 01 00:00:00 1970 +0000
1183 | date: Thu Jan 01 00:00:00 1970 +0000
1184 | summary: xx
1184 | summary: xx
1185 |
1185 |
1186 | o changeset: 5:5fb12f0f2d51
1186 | o changeset: 5:5fb12f0f2d51
1187 | | branch: test
1187 | | branch: test
1188 | | bookmark: Z
1188 | | bookmark: Z
1189 | | phase: draft
1189 | | phase: draft
1190 | | parent: 3:9ba5f110a0b3
1190 | | parent: 3:9ba5f110a0b3
1191 | | user: test
1191 | | user: test
1192 | | date: Thu Jan 01 00:00:00 1970 +0000
1192 | | date: Thu Jan 01 00:00:00 1970 +0000
1193 | | summary: yy
1193 | | summary: yy
1194 | |
1194 | |
1195 o | changeset: 4:125c9a1d6df6
1195 o | changeset: 4:125c9a1d6df6
1196 | | bookmark: Y
1196 | | bookmark: Y
1197 | | bookmark: Z@2
1197 | | bookmark: Z@2
1198 | | phase: public
1198 | | phase: public
1199 | | parent: 2:db815d6d32e6
1199 | | parent: 2:db815d6d32e6
1200 | | user: test
1200 | | user: test
1201 | | date: Thu Jan 01 00:00:00 1970 +0000
1201 | | date: Thu Jan 01 00:00:00 1970 +0000
1202 | | summary: x
1202 | | summary: x
1203 | |
1203 | |
1204 | o changeset: 3:9ba5f110a0b3
1204 | o changeset: 3:9ba5f110a0b3
1205 |/ branch: test
1205 |/ branch: test
1206 | bookmark: foo
1206 | bookmark: foo
1207 | bookmark: four
1207 | bookmark: four
1208 | phase: public
1208 | phase: public
1209 | user: test
1209 | user: test
1210 | date: Thu Jan 01 00:00:00 1970 +0000
1210 | date: Thu Jan 01 00:00:00 1970 +0000
1211 | summary: y
1211 | summary: y
1212 |
1212 |
1213 o changeset: 2:db815d6d32e6
1213 o changeset: 2:db815d6d32e6
1214 | bookmark: foo@2
1214 | bookmark: foo@2
1215 | bookmark: should-end-on-two
1215 | bookmark: should-end-on-two
1216 | bookmark: x y
1216 | bookmark: x y
1217 | phase: public
1217 | phase: public
1218 | parent: 0:f7b1eb17ad24
1218 | parent: 0:f7b1eb17ad24
1219 | user: test
1219 | user: test
1220 | date: Thu Jan 01 00:00:00 1970 +0000
1220 | date: Thu Jan 01 00:00:00 1970 +0000
1221 | summary: 2
1221 | summary: 2
1222 |
1222 |
1223 | o changeset: 1:925d80f479bb
1223 | o changeset: 1:925d80f479bb
1224 |/ bookmark: X2
1224 |/ bookmark: X2
1225 | bookmark: Z@1
1225 | bookmark: Z@1
1226 | phase: public
1226 | phase: public
1227 | user: test
1227 | user: test
1228 | date: Thu Jan 01 00:00:00 1970 +0000
1228 | date: Thu Jan 01 00:00:00 1970 +0000
1229 | summary: 1
1229 | summary: 1
1230 |
1230 |
1231 o changeset: 0:f7b1eb17ad24
1231 o changeset: 0:f7b1eb17ad24
1232 bookmark: foo@1
1232 bookmark: foo@1
1233 phase: public
1233 phase: public
1234 user: test
1234 user: test
1235 date: Thu Jan 01 00:00:00 1970 +0000
1235 date: Thu Jan 01 00:00:00 1970 +0000
1236 summary: 0
1236 summary: 0
1237
1237
1238
1238
1239 attempt to create on a default changeset
1239 attempt to create on a default changeset
1240
1240
1241 $ hg bookmark -r 81dcce76aa0b NEW
1241 $ hg bookmark -r 81dcce76aa0b NEW
1242 transaction abort!
1242 transaction abort!
1243 rollback completed
1243 rollback completed
1244 abort: pretxnclose-bookmark.force-public hook exited with status 1
1244 abort: pretxnclose-bookmark.force-public hook exited with status 1
1245 [255]
1245 [255]
1246
1246
1247 create on a public changeset
1247 create on a public changeset
1248
1248
1249 $ hg bookmark -r 9ba5f110a0b3 NEW
1249 $ hg bookmark -r 9ba5f110a0b3 NEW
1250
1250
1251 move to the other branch
1251 move to the other branch
1252
1252
1253 $ hg bookmark -f -r 125c9a1d6df6 NEW
1253 $ hg bookmark -f -r 125c9a1d6df6 NEW
1254 transaction abort!
1254 transaction abort!
1255 rollback completed
1255 rollback completed
1256 abort: pretxnclose-bookmark.force-forward hook exited with status 1
1256 abort: pretxnclose-bookmark.force-forward hook exited with status 1
1257 [255]
1257 [255]
@@ -1,1498 +1,1498 b''
1 $ cat > fakeremoteuser.py << EOF
1 $ cat > fakeremoteuser.py << EOF
2 > import os
2 > import os
3 > from mercurial.hgweb import hgweb_mod
3 > from mercurial.hgweb import hgweb_mod
4 > from mercurial import wireprotov1server
4 > from mercurial import wireprotov1server
5 > class testenvhgweb(hgweb_mod.hgweb):
5 > class testenvhgweb(hgweb_mod.hgweb):
6 > def __call__(self, env, respond):
6 > def __call__(self, env, respond):
7 > # Allow REMOTE_USER to define authenticated user.
7 > # Allow REMOTE_USER to define authenticated user.
8 > if r'REMOTE_USER' in os.environ:
8 > if r'REMOTE_USER' in os.environ:
9 > env[r'REMOTE_USER'] = os.environ[r'REMOTE_USER']
9 > env[r'REMOTE_USER'] = os.environ[r'REMOTE_USER']
10 > # Allow REQUEST_METHOD to override HTTP method
10 > # Allow REQUEST_METHOD to override HTTP method
11 > if r'REQUEST_METHOD' in os.environ:
11 > if r'REQUEST_METHOD' in os.environ:
12 > env[r'REQUEST_METHOD'] = os.environ[r'REQUEST_METHOD']
12 > env[r'REQUEST_METHOD'] = os.environ[r'REQUEST_METHOD']
13 > return super(testenvhgweb, self).__call__(env, respond)
13 > return super(testenvhgweb, self).__call__(env, respond)
14 > hgweb_mod.hgweb = testenvhgweb
14 > hgweb_mod.hgweb = testenvhgweb
15 >
15 >
16 > @wireprotov1server.wireprotocommand(b'customreadnoperm')
16 > @wireprotov1server.wireprotocommand(b'customreadnoperm')
17 > def customread(repo, proto):
17 > def customread(repo, proto):
18 > return b'read-only command no defined permissions\n'
18 > return b'read-only command no defined permissions\n'
19 > @wireprotov1server.wireprotocommand(b'customwritenoperm')
19 > @wireprotov1server.wireprotocommand(b'customwritenoperm')
20 > def customwritenoperm(repo, proto):
20 > def customwritenoperm(repo, proto):
21 > return b'write command no defined permissions\n'
21 > return b'write command no defined permissions\n'
22 > @wireprotov1server.wireprotocommand(b'customreadwithperm', permission=b'pull')
22 > @wireprotov1server.wireprotocommand(b'customreadwithperm', permission=b'pull')
23 > def customreadwithperm(repo, proto):
23 > def customreadwithperm(repo, proto):
24 > return b'read-only command w/ defined permissions\n'
24 > return b'read-only command w/ defined permissions\n'
25 > @wireprotov1server.wireprotocommand(b'customwritewithperm', permission=b'push')
25 > @wireprotov1server.wireprotocommand(b'customwritewithperm', permission=b'push')
26 > def customwritewithperm(repo, proto):
26 > def customwritewithperm(repo, proto):
27 > return b'write command w/ defined permissions\n'
27 > return b'write command w/ defined permissions\n'
28 > EOF
28 > EOF
29
29
30 $ cat >> $HGRCPATH << EOF
30 $ cat >> $HGRCPATH << EOF
31 > [extensions]
31 > [extensions]
32 > fakeremoteuser = $TESTTMP/fakeremoteuser.py
32 > fakeremoteuser = $TESTTMP/fakeremoteuser.py
33 > strip =
33 > strip =
34 > EOF
34 > EOF
35
35
36 $ hg init test
36 $ hg init test
37 $ cd test
37 $ cd test
38 $ echo a > a
38 $ echo a > a
39 $ hg ci -Ama
39 $ hg ci -Ama
40 adding a
40 adding a
41 $ cd ..
41 $ cd ..
42 $ hg clone test test2
42 $ hg clone test test2
43 updating to branch default
43 updating to branch default
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ cd test2
45 $ cd test2
46 $ echo a >> a
46 $ echo a >> a
47 $ hg ci -mb
47 $ hg ci -mb
48 $ hg book bm -r 0
48 $ hg book bm -r 0
49 $ cd ../test
49 $ cd ../test
50
50
51 web.deny_read=* prevents access to wire protocol for all users
51 web.deny_read=* prevents access to wire protocol for all users
52
52
53 $ cat > .hg/hgrc <<EOF
53 $ cat > .hg/hgrc <<EOF
54 > [web]
54 > [web]
55 > deny_read = *
55 > deny_read = *
56 > EOF
56 > EOF
57
57
58 $ hg serve -p $HGPORT -d --pid-file hg.pid
58 $ hg serve -p $HGPORT -d --pid-file hg.pid
59 $ cat hg.pid > $DAEMON_PIDS
59 $ cat hg.pid > $DAEMON_PIDS
60
60
61 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
61 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
62 401 read not authorized
62 401 read not authorized
63
63
64 0
64 0
65 read not authorized
65 read not authorized
66 [1]
66 [1]
67
67
68 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out'
68 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out'
69 401 read not authorized
69 401 read not authorized
70
70
71 0
71 0
72 read not authorized
72 read not authorized
73 [1]
73 [1]
74
74
75 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
75 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
76 401 read not authorized
76 401 read not authorized
77
77
78 0
78 0
79 read not authorized
79 read not authorized
80 [1]
80 [1]
81
81
82 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
82 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
83 401 read not authorized
83 401 read not authorized
84
84
85 0
85 0
86 read not authorized
86 read not authorized
87 [1]
87 [1]
88
88
89 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
89 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
90 401 read not authorized
90 401 read not authorized
91
91
92 0
92 0
93 read not authorized
93 read not authorized
94 [1]
94 [1]
95
95
96 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
96 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
97 401 read not authorized
97 401 read not authorized
98
98
99 0
99 0
100 read not authorized
100 read not authorized
101 [1]
101 [1]
102
102
103 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
103 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
104 401 read not authorized
104 401 read not authorized
105
105
106 0
106 0
107 read not authorized
107 read not authorized
108 [1]
108 [1]
109
109
110 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
110 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
111 401 read not authorized
111 401 read not authorized
112
112
113 0
113 0
114 read not authorized
114 read not authorized
115 [1]
115 [1]
116
116
117 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
117 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
118 pulling from http://localhost:$HGPORT/
118 pulling from http://localhost:$HGPORT/
119 abort: authorization failed
119 abort: authorization failed
120 [255]
120 [255]
121
121
122 $ killdaemons.py
122 $ killdaemons.py
123
123
124 web.deny_read=* with REMOTE_USER set still locks out clients
124 web.deny_read=* with REMOTE_USER set still locks out clients
125
125
126 $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
126 $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
127 $ cat hg.pid > $DAEMON_PIDS
127 $ cat hg.pid > $DAEMON_PIDS
128
128
129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
130 401 read not authorized
130 401 read not authorized
131
131
132 0
132 0
133 read not authorized
133 read not authorized
134 [1]
134 [1]
135
135
136 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out'
136 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out'
137 401 read not authorized
137 401 read not authorized
138
138
139 0
139 0
140 read not authorized
140 read not authorized
141 [1]
141 [1]
142
142
143 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
143 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
144 401 read not authorized
144 401 read not authorized
145
145
146 0
146 0
147 read not authorized
147 read not authorized
148 [1]
148 [1]
149
149
150 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
150 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
151 401 read not authorized
151 401 read not authorized
152
152
153 0
153 0
154 read not authorized
154 read not authorized
155 [1]
155 [1]
156
156
157 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
157 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
158 401 read not authorized
158 401 read not authorized
159
159
160 0
160 0
161 read not authorized
161 read not authorized
162 [1]
162 [1]
163
163
164 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
164 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
165 401 read not authorized
165 401 read not authorized
166
166
167 0
167 0
168 read not authorized
168 read not authorized
169 [1]
169 [1]
170
170
171 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
171 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
172 401 read not authorized
172 401 read not authorized
173
173
174 0
174 0
175 read not authorized
175 read not authorized
176 [1]
176 [1]
177
177
178 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
178 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
179 pulling from http://localhost:$HGPORT/
179 pulling from http://localhost:$HGPORT/
180 abort: authorization failed
180 abort: authorization failed
181 [255]
181 [255]
182
182
183 $ killdaemons.py
183 $ killdaemons.py
184
184
185 web.deny_read=<user> denies access to unauthenticated user
185 web.deny_read=<user> denies access to unauthenticated user
186
186
187 $ cat > .hg/hgrc <<EOF
187 $ cat > .hg/hgrc <<EOF
188 > [web]
188 > [web]
189 > deny_read = baduser1,baduser2
189 > deny_read = baduser1,baduser2
190 > EOF
190 > EOF
191
191
192 $ hg serve -p $HGPORT -d --pid-file hg.pid
192 $ hg serve -p $HGPORT -d --pid-file hg.pid
193 $ cat hg.pid > $DAEMON_PIDS
193 $ cat hg.pid > $DAEMON_PIDS
194
194
195 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
195 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
196 401 read not authorized
196 401 read not authorized
197
197
198 0
198 0
199 read not authorized
199 read not authorized
200 [1]
200 [1]
201
201
202 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
202 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
203 401 read not authorized
203 401 read not authorized
204
204
205 0
205 0
206 read not authorized
206 read not authorized
207 [1]
207 [1]
208
208
209 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
209 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
210 401 read not authorized
210 401 read not authorized
211
211
212 0
212 0
213 read not authorized
213 read not authorized
214 [1]
214 [1]
215
215
216 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
216 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
217 401 read not authorized
217 401 read not authorized
218
218
219 0
219 0
220 read not authorized
220 read not authorized
221 [1]
221 [1]
222
222
223 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
223 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
224 401 read not authorized
224 401 read not authorized
225
225
226 0
226 0
227 read not authorized
227 read not authorized
228 [1]
228 [1]
229
229
230 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
230 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
231 401 read not authorized
231 401 read not authorized
232
232
233 0
233 0
234 read not authorized
234 read not authorized
235 [1]
235 [1]
236
236
237 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
237 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
238 pulling from http://localhost:$HGPORT/
238 pulling from http://localhost:$HGPORT/
239 abort: authorization failed
239 abort: authorization failed
240 [255]
240 [255]
241
241
242 $ killdaemons.py
242 $ killdaemons.py
243
243
244 web.deny_read=<user> denies access to users in deny list
244 web.deny_read=<user> denies access to users in deny list
245
245
246 $ REMOTE_USER=baduser2 hg serve -p $HGPORT -d --pid-file hg.pid
246 $ REMOTE_USER=baduser2 hg serve -p $HGPORT -d --pid-file hg.pid
247 $ cat hg.pid > $DAEMON_PIDS
247 $ cat hg.pid > $DAEMON_PIDS
248
248
249 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
249 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
250 401 read not authorized
250 401 read not authorized
251
251
252 0
252 0
253 read not authorized
253 read not authorized
254 [1]
254 [1]
255
255
256 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
256 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
257 401 read not authorized
257 401 read not authorized
258
258
259 0
259 0
260 read not authorized
260 read not authorized
261 [1]
261 [1]
262
262
263 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
263 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
264 401 read not authorized
264 401 read not authorized
265
265
266 0
266 0
267 read not authorized
267 read not authorized
268 [1]
268 [1]
269
269
270 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
270 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
271 401 read not authorized
271 401 read not authorized
272
272
273 0
273 0
274 read not authorized
274 read not authorized
275 [1]
275 [1]
276
276
277 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
277 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
278 401 read not authorized
278 401 read not authorized
279
279
280 0
280 0
281 read not authorized
281 read not authorized
282 [1]
282 [1]
283
283
284 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
284 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
285 401 read not authorized
285 401 read not authorized
286
286
287 0
287 0
288 read not authorized
288 read not authorized
289 [1]
289 [1]
290
290
291 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
291 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
292 pulling from http://localhost:$HGPORT/
292 pulling from http://localhost:$HGPORT/
293 abort: authorization failed
293 abort: authorization failed
294 [255]
294 [255]
295
295
296 $ killdaemons.py
296 $ killdaemons.py
297
297
298 web.deny_read=<user> allows access to authenticated users not in list
298 web.deny_read=<user> allows access to authenticated users not in list
299
299
300 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
300 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
301 $ cat hg.pid > $DAEMON_PIDS
301 $ cat hg.pid > $DAEMON_PIDS
302
302
303 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
303 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
304 200 Script output follows
304 200 Script output follows
305
305
306 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
306 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
307 publishing True (no-eol)
307 publishing True (no-eol)
308
308
309 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
309 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
310 200 Script output follows
310 200 Script output follows
311
311
312 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
312 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
313 publishing True (no-eol)
313 publishing True (no-eol)
314
314
315 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
315 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
316 405 push requires POST request
316 405 push requires POST request
317
317
318 0
318 0
319 push requires POST request
319 push requires POST request
320 [1]
320 [1]
321
321
322 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
322 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
323 200 Script output follows
323 200 Script output follows
324
324
325 read-only command w/ defined permissions
325 read-only command w/ defined permissions
326
326
327 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
327 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
328 405 push requires POST request
328 405 push requires POST request
329
329
330 0
330 0
331 push requires POST request
331 push requires POST request
332 [1]
332 [1]
333
333
334 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
334 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
335 405 push requires POST request
335 405 push requires POST request
336
336
337 0
337 0
338 push requires POST request
338 push requires POST request
339 [1]
339 [1]
340
340
341 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
341 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
342 pulling from http://localhost:$HGPORT/
342 pulling from http://localhost:$HGPORT/
343 searching for changes
343 searching for changes
344 no changes found
344 no changes found
345
345
346 $ killdaemons.py
346 $ killdaemons.py
347
347
348 web.allow_read=* allows reads for unauthenticated users
348 web.allow_read=* allows reads for unauthenticated users
349
349
350 $ cat > .hg/hgrc <<EOF
350 $ cat > .hg/hgrc <<EOF
351 > [web]
351 > [web]
352 > allow_read = *
352 > allow_read = *
353 > EOF
353 > EOF
354
354
355 $ hg serve -p $HGPORT -d --pid-file hg.pid
355 $ hg serve -p $HGPORT -d --pid-file hg.pid
356 $ cat hg.pid > $DAEMON_PIDS
356 $ cat hg.pid > $DAEMON_PIDS
357
357
358 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
358 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
359 200 Script output follows
359 200 Script output follows
360
360
361 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
361 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
362 publishing True (no-eol)
362 publishing True (no-eol)
363
363
364 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
364 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
365 200 Script output follows
365 200 Script output follows
366
366
367 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
367 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
368 publishing True (no-eol)
368 publishing True (no-eol)
369
369
370 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
370 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
371 405 push requires POST request
371 405 push requires POST request
372
372
373 0
373 0
374 push requires POST request
374 push requires POST request
375 [1]
375 [1]
376
376
377 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
377 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
378 200 Script output follows
378 200 Script output follows
379
379
380 read-only command w/ defined permissions
380 read-only command w/ defined permissions
381
381
382 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
382 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
383 405 push requires POST request
383 405 push requires POST request
384
384
385 0
385 0
386 push requires POST request
386 push requires POST request
387 [1]
387 [1]
388
388
389 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
389 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
390 405 push requires POST request
390 405 push requires POST request
391
391
392 0
392 0
393 push requires POST request
393 push requires POST request
394 [1]
394 [1]
395
395
396 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
396 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
397 pulling from http://localhost:$HGPORT/
397 pulling from http://localhost:$HGPORT/
398 searching for changes
398 searching for changes
399 no changes found
399 no changes found
400
400
401 $ killdaemons.py
401 $ killdaemons.py
402
402
403 web.allow_read=* allows read for authenticated user
403 web.allow_read=* allows read for authenticated user
404
404
405 $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
405 $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
406 $ cat hg.pid > $DAEMON_PIDS
406 $ cat hg.pid > $DAEMON_PIDS
407
407
408 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
408 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
409 200 Script output follows
409 200 Script output follows
410
410
411 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
411 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
412 publishing True (no-eol)
412 publishing True (no-eol)
413
413
414 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
414 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
415 200 Script output follows
415 200 Script output follows
416
416
417 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
417 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
418 publishing True (no-eol)
418 publishing True (no-eol)
419
419
420 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
420 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
421 405 push requires POST request
421 405 push requires POST request
422
422
423 0
423 0
424 push requires POST request
424 push requires POST request
425 [1]
425 [1]
426
426
427 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
427 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
428 200 Script output follows
428 200 Script output follows
429
429
430 read-only command w/ defined permissions
430 read-only command w/ defined permissions
431
431
432 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
432 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
433 405 push requires POST request
433 405 push requires POST request
434
434
435 0
435 0
436 push requires POST request
436 push requires POST request
437 [1]
437 [1]
438
438
439 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
439 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
440 405 push requires POST request
440 405 push requires POST request
441
441
442 0
442 0
443 push requires POST request
443 push requires POST request
444 [1]
444 [1]
445
445
446 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
446 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
447 pulling from http://localhost:$HGPORT/
447 pulling from http://localhost:$HGPORT/
448 searching for changes
448 searching for changes
449 no changes found
449 no changes found
450
450
451 $ killdaemons.py
451 $ killdaemons.py
452
452
453 web.allow_read=<user> does not allow unauthenticated users to read
453 web.allow_read=<user> does not allow unauthenticated users to read
454
454
455 $ cat > .hg/hgrc <<EOF
455 $ cat > .hg/hgrc <<EOF
456 > [web]
456 > [web]
457 > allow_read = gooduser
457 > allow_read = gooduser
458 > EOF
458 > EOF
459
459
460 $ hg serve -p $HGPORT -d --pid-file hg.pid
460 $ hg serve -p $HGPORT -d --pid-file hg.pid
461 $ cat hg.pid > $DAEMON_PIDS
461 $ cat hg.pid > $DAEMON_PIDS
462
462
463 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
463 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
464 401 read not authorized
464 401 read not authorized
465
465
466 0
466 0
467 read not authorized
467 read not authorized
468 [1]
468 [1]
469
469
470 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
470 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
471 401 read not authorized
471 401 read not authorized
472
472
473 0
473 0
474 read not authorized
474 read not authorized
475 [1]
475 [1]
476
476
477 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
477 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
478 401 read not authorized
478 401 read not authorized
479
479
480 0
480 0
481 read not authorized
481 read not authorized
482 [1]
482 [1]
483
483
484 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
484 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
485 401 read not authorized
485 401 read not authorized
486
486
487 0
487 0
488 read not authorized
488 read not authorized
489 [1]
489 [1]
490
490
491 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
491 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
492 401 read not authorized
492 401 read not authorized
493
493
494 0
494 0
495 read not authorized
495 read not authorized
496 [1]
496 [1]
497
497
498 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
498 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
499 401 read not authorized
499 401 read not authorized
500
500
501 0
501 0
502 read not authorized
502 read not authorized
503 [1]
503 [1]
504
504
505 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
505 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
506 pulling from http://localhost:$HGPORT/
506 pulling from http://localhost:$HGPORT/
507 abort: authorization failed
507 abort: authorization failed
508 [255]
508 [255]
509
509
510 $ killdaemons.py
510 $ killdaemons.py
511
511
512 web.allow_read=<user> does not allow user not in list to read
512 web.allow_read=<user> does not allow user not in list to read
513
513
514 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
514 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
515 $ cat hg.pid > $DAEMON_PIDS
515 $ cat hg.pid > $DAEMON_PIDS
516
516
517 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
517 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
518 401 read not authorized
518 401 read not authorized
519
519
520 0
520 0
521 read not authorized
521 read not authorized
522 [1]
522 [1]
523
523
524 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
524 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
525 401 read not authorized
525 401 read not authorized
526
526
527 0
527 0
528 read not authorized
528 read not authorized
529 [1]
529 [1]
530
530
531 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
531 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
532 401 read not authorized
532 401 read not authorized
533
533
534 0
534 0
535 read not authorized
535 read not authorized
536 [1]
536 [1]
537
537
538 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
538 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
539 401 read not authorized
539 401 read not authorized
540
540
541 0
541 0
542 read not authorized
542 read not authorized
543 [1]
543 [1]
544
544
545 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
545 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
546 401 read not authorized
546 401 read not authorized
547
547
548 0
548 0
549 read not authorized
549 read not authorized
550 [1]
550 [1]
551
551
552 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
552 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
553 401 read not authorized
553 401 read not authorized
554
554
555 0
555 0
556 read not authorized
556 read not authorized
557 [1]
557 [1]
558
558
559 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
559 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
560 pulling from http://localhost:$HGPORT/
560 pulling from http://localhost:$HGPORT/
561 abort: authorization failed
561 abort: authorization failed
562 [255]
562 [255]
563
563
564 $ killdaemons.py
564 $ killdaemons.py
565
565
566 web.allow_read=<user> allows read from user in list
566 web.allow_read=<user> allows read from user in list
567
567
568 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
568 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
569 $ cat hg.pid > $DAEMON_PIDS
569 $ cat hg.pid > $DAEMON_PIDS
570
570
571 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
571 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
572 200 Script output follows
572 200 Script output follows
573
573
574 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
574 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
575 publishing True (no-eol)
575 publishing True (no-eol)
576
576
577 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
577 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
578 200 Script output follows
578 200 Script output follows
579
579
580 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
580 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
581 publishing True (no-eol)
581 publishing True (no-eol)
582
582
583 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
583 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
584 405 push requires POST request
584 405 push requires POST request
585
585
586 0
586 0
587 push requires POST request
587 push requires POST request
588 [1]
588 [1]
589
589
590 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
590 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
591 200 Script output follows
591 200 Script output follows
592
592
593 read-only command w/ defined permissions
593 read-only command w/ defined permissions
594
594
595 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
595 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
596 405 push requires POST request
596 405 push requires POST request
597
597
598 0
598 0
599 push requires POST request
599 push requires POST request
600 [1]
600 [1]
601
601
602 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
602 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
603 405 push requires POST request
603 405 push requires POST request
604
604
605 0
605 0
606 push requires POST request
606 push requires POST request
607 [1]
607 [1]
608
608
609 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
609 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
610 pulling from http://localhost:$HGPORT/
610 pulling from http://localhost:$HGPORT/
611 searching for changes
611 searching for changes
612 no changes found
612 no changes found
613
613
614 $ killdaemons.py
614 $ killdaemons.py
615
615
616 web.deny_read takes precedence over web.allow_read
616 web.deny_read takes precedence over web.allow_read
617
617
618 $ cat > .hg/hgrc <<EOF
618 $ cat > .hg/hgrc <<EOF
619 > [web]
619 > [web]
620 > allow_read = baduser
620 > allow_read = baduser
621 > deny_read = baduser
621 > deny_read = baduser
622 > EOF
622 > EOF
623
623
624 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
624 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
625 $ cat hg.pid > $DAEMON_PIDS
625 $ cat hg.pid > $DAEMON_PIDS
626
626
627 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
627 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
628 401 read not authorized
628 401 read not authorized
629
629
630 0
630 0
631 read not authorized
631 read not authorized
632 [1]
632 [1]
633
633
634 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
634 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
635 401 read not authorized
635 401 read not authorized
636
636
637 0
637 0
638 read not authorized
638 read not authorized
639 [1]
639 [1]
640
640
641 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
641 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
642 401 read not authorized
642 401 read not authorized
643
643
644 0
644 0
645 read not authorized
645 read not authorized
646 [1]
646 [1]
647
647
648 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
648 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
649 401 read not authorized
649 401 read not authorized
650
650
651 0
651 0
652 read not authorized
652 read not authorized
653 [1]
653 [1]
654
654
655 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
655 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
656 401 read not authorized
656 401 read not authorized
657
657
658 0
658 0
659 read not authorized
659 read not authorized
660 [1]
660 [1]
661
661
662 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
662 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
663 401 read not authorized
663 401 read not authorized
664
664
665 0
665 0
666 read not authorized
666 read not authorized
667 [1]
667 [1]
668
668
669 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
669 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
670 pulling from http://localhost:$HGPORT/
670 pulling from http://localhost:$HGPORT/
671 abort: authorization failed
671 abort: authorization failed
672 [255]
672 [255]
673
673
674 $ killdaemons.py
674 $ killdaemons.py
675
675
676 web.allow-pull=false denies read access to repo
676 web.allow-pull=false denies read access to repo
677
677
678 $ cat > .hg/hgrc <<EOF
678 $ cat > .hg/hgrc <<EOF
679 > [web]
679 > [web]
680 > allow-pull = false
680 > allow-pull = false
681 > EOF
681 > EOF
682
682
683 $ hg serve -p $HGPORT -d --pid-file hg.pid
683 $ hg serve -p $HGPORT -d --pid-file hg.pid
684 $ cat hg.pid > $DAEMON_PIDS
684 $ cat hg.pid > $DAEMON_PIDS
685
685
686 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
686 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
687 401 pull not authorized
687 401 pull not authorized
688
688
689 0
689 0
690 pull not authorized
690 pull not authorized
691 [1]
691 [1]
692
692
693 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
693 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
694 401 pull not authorized
694 401 pull not authorized
695
695
696 0
696 0
697 pull not authorized
697 pull not authorized
698 [1]
698 [1]
699
699
700 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
700 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
701 401 pull not authorized
701 401 pull not authorized
702
702
703 0
703 0
704 pull not authorized
704 pull not authorized
705 [1]
705 [1]
706
706
707 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
707 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
708 405 push requires POST request
708 405 push requires POST request
709
709
710 0
710 0
711 push requires POST request
711 push requires POST request
712 [1]
712 [1]
713
713
714 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
714 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
715 401 pull not authorized
715 401 pull not authorized
716
716
717 0
717 0
718 pull not authorized
718 pull not authorized
719 [1]
719 [1]
720
720
721 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
721 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
722 405 push requires POST request
722 405 push requires POST request
723
723
724 0
724 0
725 push requires POST request
725 push requires POST request
726 [1]
726 [1]
727
727
728 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
728 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
729 405 push requires POST request
729 405 push requires POST request
730
730
731 0
731 0
732 push requires POST request
732 push requires POST request
733 [1]
733 [1]
734
734
735 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
735 $ hg --cwd ../test2 pull http://localhost:$HGPORT/
736 pulling from http://localhost:$HGPORT/
736 pulling from http://localhost:$HGPORT/
737 abort: authorization failed
737 abort: authorization failed
738 [255]
738 [255]
739
739
740 $ killdaemons.py
740 $ killdaemons.py
741
741
742 Attempting a write command with HTTP GET fails
742 Attempting a write command with HTTP GET fails
743
743
744 $ cat > .hg/hgrc <<EOF
744 $ cat > .hg/hgrc <<EOF
745 > EOF
745 > EOF
746
746
747 $ REQUEST_METHOD=GET hg serve -p $HGPORT -d --pid-file hg.pid
747 $ REQUEST_METHOD=GET hg serve -p $HGPORT -d --pid-file hg.pid
748 $ cat hg.pid > $DAEMON_PIDS
748 $ cat hg.pid > $DAEMON_PIDS
749
749
750 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
750 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
751 405 push requires POST request
751 405 push requires POST request
752
752
753 0
753 0
754 push requires POST request
754 push requires POST request
755 [1]
755 [1]
756
756
757 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
757 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
758 405 push requires POST request
758 405 push requires POST request
759
759
760 0
760 0
761 push requires POST request
761 push requires POST request
762 [1]
762 [1]
763
763
764 $ hg bookmarks
764 $ hg bookmarks
765 no bookmarks set
765 no bookmarks set
766 $ hg bookmark -d bm
766 $ hg bookmark -d bm
767 abort: bookmark 'bm' does not exist
767 abort: bookmark 'bm' does not exist
768 [255]
768 [10]
769
769
770 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
770 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
771 405 push requires POST request
771 405 push requires POST request
772
772
773 0
773 0
774 push requires POST request
774 push requires POST request
775 [1]
775 [1]
776
776
777 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
777 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
778 405 push requires POST request
778 405 push requires POST request
779
779
780 0
780 0
781 push requires POST request
781 push requires POST request
782 [1]
782 [1]
783
783
784 $ killdaemons.py
784 $ killdaemons.py
785
785
786 Attempting a write command with an unknown HTTP verb fails
786 Attempting a write command with an unknown HTTP verb fails
787
787
788 $ REQUEST_METHOD=someverb hg serve -p $HGPORT -d --pid-file hg.pid
788 $ REQUEST_METHOD=someverb hg serve -p $HGPORT -d --pid-file hg.pid
789 $ cat hg.pid > $DAEMON_PIDS
789 $ cat hg.pid > $DAEMON_PIDS
790
790
791 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
791 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
792 405 push requires POST request
792 405 push requires POST request
793
793
794 0
794 0
795 push requires POST request
795 push requires POST request
796 [1]
796 [1]
797
797
798 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
798 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
799 405 push requires POST request
799 405 push requires POST request
800
800
801 0
801 0
802 push requires POST request
802 push requires POST request
803 [1]
803 [1]
804
804
805 $ hg bookmarks
805 $ hg bookmarks
806 no bookmarks set
806 no bookmarks set
807 $ hg bookmark -d bm
807 $ hg bookmark -d bm
808 abort: bookmark 'bm' does not exist
808 abort: bookmark 'bm' does not exist
809 [255]
809 [10]
810
810
811 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
811 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
812 405 push requires POST request
812 405 push requires POST request
813
813
814 0
814 0
815 push requires POST request
815 push requires POST request
816 [1]
816 [1]
817
817
818 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
818 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
819 405 push requires POST request
819 405 push requires POST request
820
820
821 0
821 0
822 push requires POST request
822 push requires POST request
823 [1]
823 [1]
824
824
825 $ killdaemons.py
825 $ killdaemons.py
826
826
827 Pushing on a plaintext channel is disabled by default
827 Pushing on a plaintext channel is disabled by default
828
828
829 $ cat > .hg/hgrc <<EOF
829 $ cat > .hg/hgrc <<EOF
830 > EOF
830 > EOF
831
831
832 $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
832 $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
833 $ cat hg.pid > $DAEMON_PIDS
833 $ cat hg.pid > $DAEMON_PIDS
834
834
835 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
835 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
836 403 ssl required
836 403 ssl required
837
837
838 0
838 0
839 ssl required
839 ssl required
840 [1]
840 [1]
841
841
842 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
842 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
843 403 ssl required
843 403 ssl required
844
844
845 0
845 0
846 ssl required
846 ssl required
847 [1]
847 [1]
848
848
849 $ hg bookmarks
849 $ hg bookmarks
850 no bookmarks set
850 no bookmarks set
851
851
852 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
852 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
853 403 ssl required
853 403 ssl required
854
854
855 0
855 0
856 ssl required
856 ssl required
857 [1]
857 [1]
858
858
859 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
859 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
860 403 ssl required
860 403 ssl required
861
861
862 0
862 0
863 ssl required
863 ssl required
864 [1]
864 [1]
865
865
866 Reset server to remove REQUEST_METHOD hack to test hg client
866 Reset server to remove REQUEST_METHOD hack to test hg client
867
867
868 $ killdaemons.py
868 $ killdaemons.py
869 $ hg serve -p $HGPORT -d --pid-file hg.pid
869 $ hg serve -p $HGPORT -d --pid-file hg.pid
870 $ cat hg.pid > $DAEMON_PIDS
870 $ cat hg.pid > $DAEMON_PIDS
871
871
872 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
872 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
873 pushing to http://localhost:$HGPORT/
873 pushing to http://localhost:$HGPORT/
874 searching for changes
874 searching for changes
875 no changes found
875 no changes found
876 abort: HTTP Error 403: ssl required
876 abort: HTTP Error 403: ssl required
877 [100]
877 [100]
878
878
879 $ hg --cwd ../test2 push http://localhost:$HGPORT/
879 $ hg --cwd ../test2 push http://localhost:$HGPORT/
880 pushing to http://localhost:$HGPORT/
880 pushing to http://localhost:$HGPORT/
881 searching for changes
881 searching for changes
882 abort: HTTP Error 403: ssl required
882 abort: HTTP Error 403: ssl required
883 [100]
883 [100]
884
884
885 $ killdaemons.py
885 $ killdaemons.py
886
886
887 web.deny_push=* denies pushing to unauthenticated users
887 web.deny_push=* denies pushing to unauthenticated users
888
888
889 $ cat > .hg/hgrc <<EOF
889 $ cat > .hg/hgrc <<EOF
890 > [web]
890 > [web]
891 > push_ssl = false
891 > push_ssl = false
892 > deny_push = *
892 > deny_push = *
893 > EOF
893 > EOF
894
894
895 $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
895 $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
896 $ cat hg.pid > $DAEMON_PIDS
896 $ cat hg.pid > $DAEMON_PIDS
897
897
898 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
898 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
899 401 push not authorized
899 401 push not authorized
900
900
901 0
901 0
902 push not authorized
902 push not authorized
903 [1]
903 [1]
904
904
905 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
905 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
906 401 push not authorized
906 401 push not authorized
907
907
908 0
908 0
909 push not authorized
909 push not authorized
910 [1]
910 [1]
911
911
912 $ hg bookmarks
912 $ hg bookmarks
913 no bookmarks set
913 no bookmarks set
914
914
915 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
915 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
916 401 push not authorized
916 401 push not authorized
917
917
918 0
918 0
919 push not authorized
919 push not authorized
920 [1]
920 [1]
921
921
922 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
922 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
923 401 push not authorized
923 401 push not authorized
924
924
925 0
925 0
926 push not authorized
926 push not authorized
927 [1]
927 [1]
928
928
929 Reset server to remove REQUEST_METHOD hack to test hg client
929 Reset server to remove REQUEST_METHOD hack to test hg client
930
930
931 $ killdaemons.py
931 $ killdaemons.py
932 $ hg serve -p $HGPORT -d --pid-file hg.pid
932 $ hg serve -p $HGPORT -d --pid-file hg.pid
933 $ cat hg.pid > $DAEMON_PIDS
933 $ cat hg.pid > $DAEMON_PIDS
934
934
935 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
935 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
936 pushing to http://localhost:$HGPORT/
936 pushing to http://localhost:$HGPORT/
937 searching for changes
937 searching for changes
938 no changes found
938 no changes found
939 abort: authorization failed
939 abort: authorization failed
940 [255]
940 [255]
941
941
942 $ hg --cwd ../test2 push http://localhost:$HGPORT/
942 $ hg --cwd ../test2 push http://localhost:$HGPORT/
943 pushing to http://localhost:$HGPORT/
943 pushing to http://localhost:$HGPORT/
944 searching for changes
944 searching for changes
945 abort: authorization failed
945 abort: authorization failed
946 [255]
946 [255]
947
947
948 $ killdaemons.py
948 $ killdaemons.py
949
949
950 web.deny_push=* denies pushing to authenticated users
950 web.deny_push=* denies pushing to authenticated users
951
951
952 $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
952 $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
953 $ cat hg.pid > $DAEMON_PIDS
953 $ cat hg.pid > $DAEMON_PIDS
954
954
955 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
955 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
956 401 push not authorized
956 401 push not authorized
957
957
958 0
958 0
959 push not authorized
959 push not authorized
960 [1]
960 [1]
961
961
962 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
962 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
963 401 push not authorized
963 401 push not authorized
964
964
965 0
965 0
966 push not authorized
966 push not authorized
967 [1]
967 [1]
968
968
969 $ hg bookmarks
969 $ hg bookmarks
970 no bookmarks set
970 no bookmarks set
971
971
972 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
972 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
973 401 push not authorized
973 401 push not authorized
974
974
975 0
975 0
976 push not authorized
976 push not authorized
977 [1]
977 [1]
978
978
979 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
979 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
980 401 push not authorized
980 401 push not authorized
981
981
982 0
982 0
983 push not authorized
983 push not authorized
984 [1]
984 [1]
985
985
986 Reset server to remove REQUEST_METHOD hack to test hg client
986 Reset server to remove REQUEST_METHOD hack to test hg client
987
987
988 $ killdaemons.py
988 $ killdaemons.py
989 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
989 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
990 $ cat hg.pid > $DAEMON_PIDS
990 $ cat hg.pid > $DAEMON_PIDS
991
991
992 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
992 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
993 pushing to http://localhost:$HGPORT/
993 pushing to http://localhost:$HGPORT/
994 searching for changes
994 searching for changes
995 no changes found
995 no changes found
996 abort: authorization failed
996 abort: authorization failed
997 [255]
997 [255]
998
998
999 $ hg --cwd ../test2 push http://localhost:$HGPORT/
999 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1000 pushing to http://localhost:$HGPORT/
1000 pushing to http://localhost:$HGPORT/
1001 searching for changes
1001 searching for changes
1002 abort: authorization failed
1002 abort: authorization failed
1003 [255]
1003 [255]
1004
1004
1005 $ killdaemons.py
1005 $ killdaemons.py
1006
1006
1007 web.deny_push=<user> denies pushing to user in list
1007 web.deny_push=<user> denies pushing to user in list
1008
1008
1009 $ cat > .hg/hgrc <<EOF
1009 $ cat > .hg/hgrc <<EOF
1010 > [web]
1010 > [web]
1011 > push_ssl = false
1011 > push_ssl = false
1012 > deny_push = baduser
1012 > deny_push = baduser
1013 > EOF
1013 > EOF
1014
1014
1015 $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1015 $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1016 $ cat hg.pid > $DAEMON_PIDS
1016 $ cat hg.pid > $DAEMON_PIDS
1017
1017
1018 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1018 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1019 401 push not authorized
1019 401 push not authorized
1020
1020
1021 0
1021 0
1022 push not authorized
1022 push not authorized
1023 [1]
1023 [1]
1024
1024
1025 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1025 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1026 401 push not authorized
1026 401 push not authorized
1027
1027
1028 0
1028 0
1029 push not authorized
1029 push not authorized
1030 [1]
1030 [1]
1031
1031
1032 $ hg bookmarks
1032 $ hg bookmarks
1033 no bookmarks set
1033 no bookmarks set
1034
1034
1035 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1035 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1036 401 push not authorized
1036 401 push not authorized
1037
1037
1038 0
1038 0
1039 push not authorized
1039 push not authorized
1040 [1]
1040 [1]
1041
1041
1042 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1042 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1043 401 push not authorized
1043 401 push not authorized
1044
1044
1045 0
1045 0
1046 push not authorized
1046 push not authorized
1047 [1]
1047 [1]
1048
1048
1049 Reset server to remove REQUEST_METHOD hack to test hg client
1049 Reset server to remove REQUEST_METHOD hack to test hg client
1050
1050
1051 $ killdaemons.py
1051 $ killdaemons.py
1052 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
1052 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
1053 $ cat hg.pid > $DAEMON_PIDS
1053 $ cat hg.pid > $DAEMON_PIDS
1054
1054
1055 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1055 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1056 pushing to http://localhost:$HGPORT/
1056 pushing to http://localhost:$HGPORT/
1057 searching for changes
1057 searching for changes
1058 no changes found
1058 no changes found
1059 abort: authorization failed
1059 abort: authorization failed
1060 [255]
1060 [255]
1061
1061
1062 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1062 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1063 pushing to http://localhost:$HGPORT/
1063 pushing to http://localhost:$HGPORT/
1064 searching for changes
1064 searching for changes
1065 abort: authorization failed
1065 abort: authorization failed
1066 [255]
1066 [255]
1067
1067
1068 $ killdaemons.py
1068 $ killdaemons.py
1069
1069
1070 web.deny_push=<user> denies pushing to user not in list because allow-push isn't set
1070 web.deny_push=<user> denies pushing to user not in list because allow-push isn't set
1071
1071
1072 $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1072 $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1073 $ cat hg.pid > $DAEMON_PIDS
1073 $ cat hg.pid > $DAEMON_PIDS
1074
1074
1075 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1075 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1076 401 push not authorized
1076 401 push not authorized
1077
1077
1078 0
1078 0
1079 push not authorized
1079 push not authorized
1080 [1]
1080 [1]
1081
1081
1082 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1082 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1083 401 push not authorized
1083 401 push not authorized
1084
1084
1085 0
1085 0
1086 push not authorized
1086 push not authorized
1087 [1]
1087 [1]
1088
1088
1089 $ hg bookmarks
1089 $ hg bookmarks
1090 no bookmarks set
1090 no bookmarks set
1091
1091
1092 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1092 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1093 401 push not authorized
1093 401 push not authorized
1094
1094
1095 0
1095 0
1096 push not authorized
1096 push not authorized
1097 [1]
1097 [1]
1098
1098
1099 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1099 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1100 401 push not authorized
1100 401 push not authorized
1101
1101
1102 0
1102 0
1103 push not authorized
1103 push not authorized
1104 [1]
1104 [1]
1105
1105
1106 Reset server to remove REQUEST_METHOD hack to test hg client
1106 Reset server to remove REQUEST_METHOD hack to test hg client
1107
1107
1108 $ killdaemons.py
1108 $ killdaemons.py
1109 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
1109 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
1110 $ cat hg.pid > $DAEMON_PIDS
1110 $ cat hg.pid > $DAEMON_PIDS
1111
1111
1112 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1112 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1113 pushing to http://localhost:$HGPORT/
1113 pushing to http://localhost:$HGPORT/
1114 searching for changes
1114 searching for changes
1115 no changes found
1115 no changes found
1116 abort: authorization failed
1116 abort: authorization failed
1117 [255]
1117 [255]
1118
1118
1119 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1119 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1120 pushing to http://localhost:$HGPORT/
1120 pushing to http://localhost:$HGPORT/
1121 searching for changes
1121 searching for changes
1122 abort: authorization failed
1122 abort: authorization failed
1123 [255]
1123 [255]
1124
1124
1125 $ killdaemons.py
1125 $ killdaemons.py
1126
1126
1127 web.allow-push=* allows pushes from unauthenticated users
1127 web.allow-push=* allows pushes from unauthenticated users
1128
1128
1129 $ cat > .hg/hgrc <<EOF
1129 $ cat > .hg/hgrc <<EOF
1130 > [web]
1130 > [web]
1131 > push_ssl = false
1131 > push_ssl = false
1132 > allow-push = *
1132 > allow-push = *
1133 > EOF
1133 > EOF
1134
1134
1135 $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1135 $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1136 $ cat hg.pid > $DAEMON_PIDS
1136 $ cat hg.pid > $DAEMON_PIDS
1137
1137
1138 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1138 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1139 200 Script output follows
1139 200 Script output follows
1140
1140
1141 1
1141 1
1142
1142
1143 $ hg bookmarks
1143 $ hg bookmarks
1144 bm 0:cb9a9f314b8b
1144 bm 0:cb9a9f314b8b
1145 $ hg book -d bm
1145 $ hg book -d bm
1146
1146
1147 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1147 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1148 200 Script output follows
1148 200 Script output follows
1149
1149
1150 write command no defined permissions
1150 write command no defined permissions
1151
1151
1152 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1152 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1153 200 Script output follows
1153 200 Script output follows
1154
1154
1155 write command w/ defined permissions
1155 write command w/ defined permissions
1156
1156
1157 Reset server to remove REQUEST_METHOD hack to test hg client
1157 Reset server to remove REQUEST_METHOD hack to test hg client
1158
1158
1159 $ killdaemons.py
1159 $ killdaemons.py
1160 $ hg serve -p $HGPORT -d --pid-file hg.pid
1160 $ hg serve -p $HGPORT -d --pid-file hg.pid
1161 $ cat hg.pid > $DAEMON_PIDS
1161 $ cat hg.pid > $DAEMON_PIDS
1162
1162
1163 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1163 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1164 pushing to http://localhost:$HGPORT/
1164 pushing to http://localhost:$HGPORT/
1165 searching for changes
1165 searching for changes
1166 no changes found
1166 no changes found
1167 exporting bookmark bm
1167 exporting bookmark bm
1168 [1]
1168 [1]
1169
1169
1170 $ hg book -d bm
1170 $ hg book -d bm
1171
1171
1172 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1172 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1173 pushing to http://localhost:$HGPORT/
1173 pushing to http://localhost:$HGPORT/
1174 searching for changes
1174 searching for changes
1175 remote: adding changesets
1175 remote: adding changesets
1176 remote: adding manifests
1176 remote: adding manifests
1177 remote: adding file changes
1177 remote: adding file changes
1178 remote: added 1 changesets with 1 changes to 1 files
1178 remote: added 1 changesets with 1 changes to 1 files
1179
1179
1180 $ hg strip -r 1:
1180 $ hg strip -r 1:
1181 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
1181 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
1182
1182
1183 $ killdaemons.py
1183 $ killdaemons.py
1184
1184
1185 web.allow-push=* allows pushes from authenticated users
1185 web.allow-push=* allows pushes from authenticated users
1186
1186
1187 $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1187 $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1188 $ cat hg.pid > $DAEMON_PIDS
1188 $ cat hg.pid > $DAEMON_PIDS
1189
1189
1190 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1190 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1191 200 Script output follows
1191 200 Script output follows
1192
1192
1193 1
1193 1
1194
1194
1195 $ hg bookmarks
1195 $ hg bookmarks
1196 bm 0:cb9a9f314b8b
1196 bm 0:cb9a9f314b8b
1197 $ hg book -d bm
1197 $ hg book -d bm
1198
1198
1199 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1199 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1200 200 Script output follows
1200 200 Script output follows
1201
1201
1202 write command no defined permissions
1202 write command no defined permissions
1203
1203
1204 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1204 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1205 200 Script output follows
1205 200 Script output follows
1206
1206
1207 write command w/ defined permissions
1207 write command w/ defined permissions
1208
1208
1209 Reset server to remove REQUEST_METHOD hack to test hg client
1209 Reset server to remove REQUEST_METHOD hack to test hg client
1210
1210
1211 $ killdaemons.py
1211 $ killdaemons.py
1212 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1212 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1213 $ cat hg.pid > $DAEMON_PIDS
1213 $ cat hg.pid > $DAEMON_PIDS
1214
1214
1215 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1215 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1216 pushing to http://localhost:$HGPORT/
1216 pushing to http://localhost:$HGPORT/
1217 searching for changes
1217 searching for changes
1218 no changes found
1218 no changes found
1219 exporting bookmark bm
1219 exporting bookmark bm
1220 [1]
1220 [1]
1221
1221
1222 $ hg book -d bm
1222 $ hg book -d bm
1223
1223
1224 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1224 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1225 pushing to http://localhost:$HGPORT/
1225 pushing to http://localhost:$HGPORT/
1226 searching for changes
1226 searching for changes
1227 remote: adding changesets
1227 remote: adding changesets
1228 remote: adding manifests
1228 remote: adding manifests
1229 remote: adding file changes
1229 remote: adding file changes
1230 remote: added 1 changesets with 1 changes to 1 files
1230 remote: added 1 changesets with 1 changes to 1 files
1231
1231
1232 $ hg strip -r 1:
1232 $ hg strip -r 1:
1233 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
1233 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
1234
1234
1235 $ killdaemons.py
1235 $ killdaemons.py
1236
1236
1237 web.allow-push=<user> denies push to user not in list
1237 web.allow-push=<user> denies push to user not in list
1238
1238
1239 $ cat > .hg/hgrc <<EOF
1239 $ cat > .hg/hgrc <<EOF
1240 > [web]
1240 > [web]
1241 > push_ssl = false
1241 > push_ssl = false
1242 > allow-push = gooduser
1242 > allow-push = gooduser
1243 > EOF
1243 > EOF
1244
1244
1245 $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1245 $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1246 $ cat hg.pid > $DAEMON_PIDS
1246 $ cat hg.pid > $DAEMON_PIDS
1247
1247
1248 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1248 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1249 401 push not authorized
1249 401 push not authorized
1250
1250
1251 0
1251 0
1252 push not authorized
1252 push not authorized
1253 [1]
1253 [1]
1254
1254
1255 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1255 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1256 401 push not authorized
1256 401 push not authorized
1257
1257
1258 0
1258 0
1259 push not authorized
1259 push not authorized
1260 [1]
1260 [1]
1261
1261
1262 $ hg bookmarks
1262 $ hg bookmarks
1263 no bookmarks set
1263 no bookmarks set
1264
1264
1265 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1265 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1266 401 push not authorized
1266 401 push not authorized
1267
1267
1268 0
1268 0
1269 push not authorized
1269 push not authorized
1270 [1]
1270 [1]
1271
1271
1272 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1272 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1273 401 push not authorized
1273 401 push not authorized
1274
1274
1275 0
1275 0
1276 push not authorized
1276 push not authorized
1277 [1]
1277 [1]
1278
1278
1279 Reset server to remove REQUEST_METHOD hack to test hg client
1279 Reset server to remove REQUEST_METHOD hack to test hg client
1280
1280
1281 $ killdaemons.py
1281 $ killdaemons.py
1282 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
1282 $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
1283 $ cat hg.pid > $DAEMON_PIDS
1283 $ cat hg.pid > $DAEMON_PIDS
1284
1284
1285 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1285 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1286 pushing to http://localhost:$HGPORT/
1286 pushing to http://localhost:$HGPORT/
1287 searching for changes
1287 searching for changes
1288 no changes found
1288 no changes found
1289 abort: authorization failed
1289 abort: authorization failed
1290 [255]
1290 [255]
1291
1291
1292 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1292 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1293 pushing to http://localhost:$HGPORT/
1293 pushing to http://localhost:$HGPORT/
1294 searching for changes
1294 searching for changes
1295 abort: authorization failed
1295 abort: authorization failed
1296 [255]
1296 [255]
1297
1297
1298 $ killdaemons.py
1298 $ killdaemons.py
1299
1299
1300 web.allow-push=<user> allows push from user in list
1300 web.allow-push=<user> allows push from user in list
1301
1301
1302 $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1302 $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1303 $ cat hg.pid > $DAEMON_PIDS
1303 $ cat hg.pid > $DAEMON_PIDS
1304
1304
1305 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1305 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1306 200 Script output follows
1306 200 Script output follows
1307
1307
1308 1
1308 1
1309
1309
1310 $ hg bookmarks
1310 $ hg bookmarks
1311 bm 0:cb9a9f314b8b
1311 bm 0:cb9a9f314b8b
1312 $ hg book -d bm
1312 $ hg book -d bm
1313
1313
1314 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1314 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1315 200 Script output follows
1315 200 Script output follows
1316
1316
1317 1
1317 1
1318
1318
1319 $ hg bookmarks
1319 $ hg bookmarks
1320 bm 0:cb9a9f314b8b
1320 bm 0:cb9a9f314b8b
1321 $ hg book -d bm
1321 $ hg book -d bm
1322
1322
1323 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1323 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1324 200 Script output follows
1324 200 Script output follows
1325
1325
1326 write command no defined permissions
1326 write command no defined permissions
1327
1327
1328 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1328 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1329 200 Script output follows
1329 200 Script output follows
1330
1330
1331 write command w/ defined permissions
1331 write command w/ defined permissions
1332
1332
1333 Reset server to remove REQUEST_METHOD hack to test hg client
1333 Reset server to remove REQUEST_METHOD hack to test hg client
1334
1334
1335 $ killdaemons.py
1335 $ killdaemons.py
1336 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
1336 $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
1337 $ cat hg.pid > $DAEMON_PIDS
1337 $ cat hg.pid > $DAEMON_PIDS
1338
1338
1339 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1339 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1340 pushing to http://localhost:$HGPORT/
1340 pushing to http://localhost:$HGPORT/
1341 searching for changes
1341 searching for changes
1342 no changes found
1342 no changes found
1343 exporting bookmark bm
1343 exporting bookmark bm
1344 [1]
1344 [1]
1345
1345
1346 $ hg book -d bm
1346 $ hg book -d bm
1347
1347
1348 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1348 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1349 pushing to http://localhost:$HGPORT/
1349 pushing to http://localhost:$HGPORT/
1350 searching for changes
1350 searching for changes
1351 remote: adding changesets
1351 remote: adding changesets
1352 remote: adding manifests
1352 remote: adding manifests
1353 remote: adding file changes
1353 remote: adding file changes
1354 remote: added 1 changesets with 1 changes to 1 files
1354 remote: added 1 changesets with 1 changes to 1 files
1355
1355
1356 $ hg strip -r 1:
1356 $ hg strip -r 1:
1357 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
1357 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
1358
1358
1359 $ killdaemons.py
1359 $ killdaemons.py
1360
1360
1361 web.deny_push takes precedence over web.allow_push
1361 web.deny_push takes precedence over web.allow_push
1362
1362
1363 $ cat > .hg/hgrc <<EOF
1363 $ cat > .hg/hgrc <<EOF
1364 > [web]
1364 > [web]
1365 > push_ssl = false
1365 > push_ssl = false
1366 > allow-push = someuser
1366 > allow-push = someuser
1367 > deny_push = someuser
1367 > deny_push = someuser
1368 > EOF
1368 > EOF
1369
1369
1370 $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1370 $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
1371 $ cat hg.pid > $DAEMON_PIDS
1371 $ cat hg.pid > $DAEMON_PIDS
1372
1372
1373 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1373 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1374 401 push not authorized
1374 401 push not authorized
1375
1375
1376 0
1376 0
1377 push not authorized
1377 push not authorized
1378 [1]
1378 [1]
1379
1379
1380 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1380 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1381 401 push not authorized
1381 401 push not authorized
1382
1382
1383 0
1383 0
1384 push not authorized
1384 push not authorized
1385 [1]
1385 [1]
1386
1386
1387 $ hg bookmarks
1387 $ hg bookmarks
1388 no bookmarks set
1388 no bookmarks set
1389
1389
1390 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1390 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1391 401 push not authorized
1391 401 push not authorized
1392
1392
1393 0
1393 0
1394 push not authorized
1394 push not authorized
1395 [1]
1395 [1]
1396
1396
1397 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1397 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1398 401 push not authorized
1398 401 push not authorized
1399
1399
1400 0
1400 0
1401 push not authorized
1401 push not authorized
1402 [1]
1402 [1]
1403
1403
1404 Reset server to remove REQUEST_METHOD hack to test hg client
1404 Reset server to remove REQUEST_METHOD hack to test hg client
1405
1405
1406 $ killdaemons.py
1406 $ killdaemons.py
1407 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1407 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1408 $ cat hg.pid > $DAEMON_PIDS
1408 $ cat hg.pid > $DAEMON_PIDS
1409
1409
1410 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1410 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1411 pushing to http://localhost:$HGPORT/
1411 pushing to http://localhost:$HGPORT/
1412 searching for changes
1412 searching for changes
1413 no changes found
1413 no changes found
1414 abort: authorization failed
1414 abort: authorization failed
1415 [255]
1415 [255]
1416
1416
1417 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1417 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1418 pushing to http://localhost:$HGPORT/
1418 pushing to http://localhost:$HGPORT/
1419 searching for changes
1419 searching for changes
1420 abort: authorization failed
1420 abort: authorization failed
1421 [255]
1421 [255]
1422
1422
1423 $ killdaemons.py
1423 $ killdaemons.py
1424
1424
1425 web.allow-push has no effect if web.deny_read is set
1425 web.allow-push has no effect if web.deny_read is set
1426
1426
1427 $ cat > .hg/hgrc <<EOF
1427 $ cat > .hg/hgrc <<EOF
1428 > [web]
1428 > [web]
1429 > push_ssl = false
1429 > push_ssl = false
1430 > allow-push = *
1430 > allow-push = *
1431 > deny_read = *
1431 > deny_read = *
1432 > EOF
1432 > EOF
1433
1433
1434 $ REQUEST_METHOD=POST REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1434 $ REQUEST_METHOD=POST REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1435 $ cat hg.pid > $DAEMON_PIDS
1435 $ cat hg.pid > $DAEMON_PIDS
1436
1436
1437 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1437 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1438 401 read not authorized
1438 401 read not authorized
1439
1439
1440 0
1440 0
1441 read not authorized
1441 read not authorized
1442 [1]
1442 [1]
1443
1443
1444 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1444 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
1445 401 read not authorized
1445 401 read not authorized
1446
1446
1447 0
1447 0
1448 read not authorized
1448 read not authorized
1449 [1]
1449 [1]
1450
1450
1451 $ hg bookmarks
1451 $ hg bookmarks
1452 no bookmarks set
1452 no bookmarks set
1453
1453
1454 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
1454 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
1455 401 read not authorized
1455 401 read not authorized
1456
1456
1457 0
1457 0
1458 read not authorized
1458 read not authorized
1459 [1]
1459 [1]
1460
1460
1461 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
1461 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
1462 401 read not authorized
1462 401 read not authorized
1463
1463
1464 0
1464 0
1465 read not authorized
1465 read not authorized
1466 [1]
1466 [1]
1467
1467
1468 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1468 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
1469 401 read not authorized
1469 401 read not authorized
1470
1470
1471 0
1471 0
1472 read not authorized
1472 read not authorized
1473 [1]
1473 [1]
1474
1474
1475 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1475 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
1476 401 read not authorized
1476 401 read not authorized
1477
1477
1478 0
1478 0
1479 read not authorized
1479 read not authorized
1480 [1]
1480 [1]
1481
1481
1482 Reset server to remove REQUEST_METHOD hack to test hg client
1482 Reset server to remove REQUEST_METHOD hack to test hg client
1483
1483
1484 $ killdaemons.py
1484 $ killdaemons.py
1485 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1485 $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
1486 $ cat hg.pid > $DAEMON_PIDS
1486 $ cat hg.pid > $DAEMON_PIDS
1487
1487
1488 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1488 $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
1489 pushing to http://localhost:$HGPORT/
1489 pushing to http://localhost:$HGPORT/
1490 abort: authorization failed
1490 abort: authorization failed
1491 [255]
1491 [255]
1492
1492
1493 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1493 $ hg --cwd ../test2 push http://localhost:$HGPORT/
1494 pushing to http://localhost:$HGPORT/
1494 pushing to http://localhost:$HGPORT/
1495 abort: authorization failed
1495 abort: authorization failed
1496 [255]
1496 [255]
1497
1497
1498 $ killdaemons.py
1498 $ killdaemons.py
General Comments 0
You need to be logged in to leave comments. Login now