29 |
29 |
30 # label constants |
30 # label constants |
31 # until 3.5, bookmarks.current was the advertised name, not |
31 # until 3.5, bookmarks.current was the advertised name, not |
32 # bookmarks.active, so we must use both to avoid breaking old |
32 # bookmarks.active, so we must use both to avoid breaking old |
33 # custom styles |
33 # custom styles |
34 activebookmarklabel = 'bookmarks.active bookmarks.current' |
34 activebookmarklabel = b'bookmarks.active bookmarks.current' |
35 |
35 |
36 BOOKMARKS_IN_STORE_REQUIREMENT = 'bookmarksinstore' |
36 BOOKMARKS_IN_STORE_REQUIREMENT = b'bookmarksinstore' |
37 |
37 |
38 |
38 |
39 def bookmarksinstore(repo): |
39 def bookmarksinstore(repo): |
40 return BOOKMARKS_IN_STORE_REQUIREMENT in repo.requirements |
40 return BOOKMARKS_IN_STORE_REQUIREMENT in repo.requirements |
41 |
41 |
49 |
49 |
50 For core, this just handles wether we should see pending |
50 For core, this just handles wether we should see pending |
51 bookmarks or the committed ones. Other extensions (like share) |
51 bookmarks or the committed ones. Other extensions (like share) |
52 may need to tweak this behavior further. |
52 may need to tweak this behavior further. |
53 """ |
53 """ |
54 fp, pending = txnutil.trypending(repo.root, bookmarksvfs(repo), 'bookmarks') |
54 fp, pending = txnutil.trypending( |
|
55 repo.root, bookmarksvfs(repo), b'bookmarks' |
|
56 ) |
55 return fp |
57 return fp |
56 |
58 |
57 |
59 |
58 class bmstore(object): |
60 class bmstore(object): |
59 r"""Storage for bookmarks. |
61 r"""Storage for bookmarks. |
101 # TypeError: |
103 # TypeError: |
102 # - bin(...) |
104 # - bin(...) |
103 # ValueError: |
105 # ValueError: |
104 # - node in nm, for non-20-bytes entry |
106 # - node in nm, for non-20-bytes entry |
105 # - split(...), for string without ' ' |
107 # - split(...), for string without ' ' |
106 bookmarkspath = '.hg/bookmarks' |
108 bookmarkspath = b'.hg/bookmarks' |
107 if bookmarksinstore(repo): |
109 if bookmarksinstore(repo): |
108 bookmarkspath = '.hg/store/bookmarks' |
110 bookmarkspath = b'.hg/store/bookmarks' |
109 repo.ui.warn( |
111 repo.ui.warn( |
110 _('malformed line in %s: %r\n') |
112 _(b'malformed line in %s: %r\n') |
111 % (bookmarkspath, pycompat.bytestr(line)) |
113 % (bookmarkspath, pycompat.bytestr(line)) |
112 ) |
114 ) |
113 except IOError as inst: |
115 except IOError as inst: |
114 if inst.errno != errno.ENOENT: |
116 if inst.errno != errno.ENOENT: |
115 raise |
117 raise |
184 return self._nodemap.get(node, []) |
186 return self._nodemap.get(node, []) |
185 |
187 |
186 def applychanges(self, repo, tr, changes): |
188 def applychanges(self, repo, tr, changes): |
187 """Apply a list of changes to bookmarks |
189 """Apply a list of changes to bookmarks |
188 """ |
190 """ |
189 bmchanges = tr.changes.get('bookmarks') |
191 bmchanges = tr.changes.get(b'bookmarks') |
190 for name, node in changes: |
192 for name, node in changes: |
191 old = self._refmap.get(name) |
193 old = self._refmap.get(name) |
192 if node is None: |
194 if node is None: |
193 self._del(name) |
195 self._del(name) |
194 else: |
196 else: |
203 |
205 |
204 def _recordchange(self, tr): |
206 def _recordchange(self, tr): |
205 """record that bookmarks have been changed in a transaction |
207 """record that bookmarks have been changed in a transaction |
206 |
208 |
207 The transaction is then responsible for updating the file content.""" |
209 The transaction is then responsible for updating the file content.""" |
208 location = '' if bookmarksinstore(self._repo) else 'plain' |
210 location = b'' if bookmarksinstore(self._repo) else b'plain' |
209 tr.addfilegenerator( |
211 tr.addfilegenerator( |
210 'bookmarks', ('bookmarks',), self._write, location=location |
212 b'bookmarks', (b'bookmarks',), self._write, location=location |
211 ) |
213 ) |
212 tr.hookargs['bookmark_moved'] = '1' |
214 tr.hookargs[b'bookmark_moved'] = b'1' |
213 |
215 |
214 def _writerepo(self, repo): |
216 def _writerepo(self, repo): |
215 """Factored out for extensibility""" |
217 """Factored out for extensibility""" |
216 rbm = repo._bookmarks |
218 rbm = repo._bookmarks |
217 if rbm.active not in self._refmap: |
219 if rbm.active not in self._refmap: |
223 lock = repo.lock() |
225 lock = repo.lock() |
224 else: |
226 else: |
225 vfs = repo.vfs |
227 vfs = repo.vfs |
226 lock = repo.wlock() |
228 lock = repo.wlock() |
227 with lock: |
229 with lock: |
228 with vfs('bookmarks', 'w', atomictemp=True, checkambig=True) as f: |
230 with vfs(b'bookmarks', b'w', atomictemp=True, checkambig=True) as f: |
229 self._write(f) |
231 self._write(f) |
230 |
232 |
231 def _writeactive(self): |
233 def _writeactive(self): |
232 if self._aclean: |
234 if self._aclean: |
233 return |
235 return |
234 with self._repo.wlock(): |
236 with self._repo.wlock(): |
235 if self._active is not None: |
237 if self._active is not None: |
236 with self._repo.vfs( |
238 with self._repo.vfs( |
237 'bookmarks.current', 'w', atomictemp=True, checkambig=True |
239 b'bookmarks.current', b'w', atomictemp=True, checkambig=True |
238 ) as f: |
240 ) as f: |
239 f.write(encoding.fromlocal(self._active)) |
241 f.write(encoding.fromlocal(self._active)) |
240 else: |
242 else: |
241 self._repo.vfs.tryunlink('bookmarks.current') |
243 self._repo.vfs.tryunlink(b'bookmarks.current') |
242 self._aclean = True |
244 self._aclean = True |
243 |
245 |
244 def _write(self, fp): |
246 def _write(self, fp): |
245 for name, node in sorted(self._refmap.iteritems()): |
247 for name, node in sorted(self._refmap.iteritems()): |
246 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name))) |
248 fp.write(b"%s %s\n" % (hex(node), encoding.fromlocal(name))) |
247 self._clean = True |
249 self._clean = True |
248 self._repo.invalidatevolatilesets() |
250 self._repo.invalidatevolatilesets() |
249 |
251 |
250 def expandname(self, bname): |
252 def expandname(self, bname): |
251 if bname == '.': |
253 if bname == b'.': |
252 if self.active: |
254 if self.active: |
253 return self.active |
255 return self.active |
254 else: |
256 else: |
255 raise error.RepoLookupError(_("no active bookmark")) |
257 raise error.RepoLookupError(_(b"no active bookmark")) |
256 return bname |
258 return bname |
257 |
259 |
258 def checkconflict(self, mark, force=False, target=None): |
260 def checkconflict(self, mark, force=False, target=None): |
259 """check repo for a potential clash of mark with an existing bookmark, |
261 """check repo for a potential clash of mark with an existing bookmark, |
260 branch, or hash |
262 branch, or hash |
265 If force is supplied, then forcibly move the bookmark to a new commit |
267 If force is supplied, then forcibly move the bookmark to a new commit |
266 regardless if it is a move forward. |
268 regardless if it is a move forward. |
267 |
269 |
268 If divergent bookmark are to be deleted, they will be returned as list. |
270 If divergent bookmark are to be deleted, they will be returned as list. |
269 """ |
271 """ |
270 cur = self._repo['.'].node() |
272 cur = self._repo[b'.'].node() |
271 if mark in self._refmap and not force: |
273 if mark in self._refmap and not force: |
272 if target: |
274 if target: |
273 if self._refmap[mark] == target and target == cur: |
275 if self._refmap[mark] == target and target == cur: |
274 # re-activating a bookmark |
276 # re-activating a bookmark |
275 return [] |
277 return [] |
277 anc = self._repo.changelog.ancestors([rev]) |
279 anc = self._repo.changelog.ancestors([rev]) |
278 bmctx = self._repo[self[mark]] |
280 bmctx = self._repo[self[mark]] |
279 divs = [ |
281 divs = [ |
280 self._refmap[b] |
282 self._refmap[b] |
281 for b in self._refmap |
283 for b in self._refmap |
282 if b.split('@', 1)[0] == mark.split('@', 1)[0] |
284 if b.split(b'@', 1)[0] == mark.split(b'@', 1)[0] |
283 ] |
285 ] |
284 |
286 |
285 # allow resolving a single divergent bookmark even if moving |
287 # allow resolving a single divergent bookmark even if moving |
286 # the bookmark across branches when a revision is specified |
288 # the bookmark across branches when a revision is specified |
287 # that contains a divergent bookmark |
289 # that contains a divergent bookmark |
292 b for b in divs if self._repo[b].rev() in anc or b == target |
294 b for b in divs if self._repo[b].rev() in anc or b == target |
293 ] |
295 ] |
294 delbms = divergent2delete(self._repo, deletefrom, mark) |
296 delbms = divergent2delete(self._repo, deletefrom, mark) |
295 if validdest(self._repo, bmctx, self._repo[target]): |
297 if validdest(self._repo, bmctx, self._repo[target]): |
296 self._repo.ui.status( |
298 self._repo.ui.status( |
297 _("moving bookmark '%s' forward from %s\n") |
299 _(b"moving bookmark '%s' forward from %s\n") |
298 % (mark, short(bmctx.node())) |
300 % (mark, short(bmctx.node())) |
299 ) |
301 ) |
300 return delbms |
302 return delbms |
301 raise error.Abort( |
303 raise error.Abort( |
302 _("bookmark '%s' already exists " "(use -f to force)") % mark |
304 _(b"bookmark '%s' already exists " b"(use -f to force)") % mark |
303 ) |
305 ) |
304 if ( |
306 if ( |
305 mark in self._repo.branchmap() |
307 mark in self._repo.branchmap() |
306 or mark == self._repo.dirstate.branch() |
308 or mark == self._repo.dirstate.branch() |
307 ) and not force: |
309 ) and not force: |
308 raise error.Abort( |
310 raise error.Abort( |
309 _("a bookmark cannot have the name of an existing branch") |
311 _(b"a bookmark cannot have the name of an existing branch") |
310 ) |
312 ) |
311 if len(mark) > 3 and not force: |
313 if len(mark) > 3 and not force: |
312 try: |
314 try: |
313 shadowhash = scmutil.isrevsymbol(self._repo, mark) |
315 shadowhash = scmutil.isrevsymbol(self._repo, mark) |
314 except error.LookupError: # ambiguous identifier |
316 except error.LookupError: # ambiguous identifier |
315 shadowhash = False |
317 shadowhash = False |
316 if shadowhash: |
318 if shadowhash: |
317 self._repo.ui.warn( |
319 self._repo.ui.warn( |
318 _( |
320 _( |
319 "bookmark %s matches a changeset hash\n" |
321 b"bookmark %s matches a changeset hash\n" |
320 "(did you leave a -r out of an 'hg bookmark' " |
322 b"(did you leave a -r out of an 'hg bookmark' " |
321 "command?)\n" |
323 b"command?)\n" |
322 ) |
324 ) |
323 % mark |
325 % mark |
324 ) |
326 ) |
325 return [] |
327 return [] |
326 |
328 |
331 itself as we commit. This function returns the name of that bookmark. |
333 itself as we commit. This function returns the name of that bookmark. |
332 It is stored in .hg/bookmarks.current |
334 It is stored in .hg/bookmarks.current |
333 """ |
335 """ |
334 # No readline() in osutil.posixfile, reading everything is |
336 # No readline() in osutil.posixfile, reading everything is |
335 # cheap. |
337 # cheap. |
336 content = repo.vfs.tryread('bookmarks.current') |
338 content = repo.vfs.tryread(b'bookmarks.current') |
337 mark = encoding.tolocal((content.splitlines() or [''])[0]) |
339 mark = encoding.tolocal((content.splitlines() or [b''])[0]) |
338 if mark == '' or mark not in marks: |
340 if mark == b'' or mark not in marks: |
339 mark = None |
341 mark = None |
340 return mark |
342 return mark |
341 |
343 |
342 |
344 |
343 def activate(repo, mark): |
345 def activate(repo, mark): |
377 """find divergent versions of bm on nodes in deletefrom. |
379 """find divergent versions of bm on nodes in deletefrom. |
378 |
380 |
379 the list of bookmark to delete.""" |
381 the list of bookmark to delete.""" |
380 todelete = [] |
382 todelete = [] |
381 marks = repo._bookmarks |
383 marks = repo._bookmarks |
382 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]] |
384 divergent = [ |
|
385 b for b in marks if b.split(b'@', 1)[0] == bm.split(b'@', 1)[0] |
|
386 ] |
383 for mark in divergent: |
387 for mark in divergent: |
384 if mark == '@' or '@' not in mark: |
388 if mark == b'@' or b'@' not in mark: |
385 # can't be divergent by definition |
389 # can't be divergent by definition |
386 continue |
390 continue |
387 if mark and marks[mark] in deletefrom: |
391 if mark and marks[mark] in deletefrom: |
388 if mark != bm: |
392 if mark != bm: |
389 todelete.append(mark) |
393 todelete.append(mark) |
402 there were no divergent bookmarks, then this list will contain |
406 there were no divergent bookmarks, then this list will contain |
403 only one entry. |
407 only one entry. |
404 """ |
408 """ |
405 if not repo._activebookmark: |
409 if not repo._activebookmark: |
406 raise ValueError( |
410 raise ValueError( |
407 'headsforactive() only makes sense with an active bookmark' |
411 b'headsforactive() only makes sense with an active bookmark' |
408 ) |
412 ) |
409 name = repo._activebookmark.split('@', 1)[0] |
413 name = repo._activebookmark.split(b'@', 1)[0] |
410 heads = [] |
414 heads = [] |
411 for mark, n in repo._bookmarks.iteritems(): |
415 for mark, n in repo._bookmarks.iteritems(): |
412 if mark.split('@', 1)[0] == name: |
416 if mark.split(b'@', 1)[0] == name: |
413 heads.append(n) |
417 heads.append(n) |
414 return heads |
418 return heads |
415 |
419 |
416 |
420 |
417 def calculateupdate(ui, repo): |
421 def calculateupdate(ui, repo): |
418 '''Return a tuple (activemark, movemarkfrom) indicating the active bookmark |
422 '''Return a tuple (activemark, movemarkfrom) indicating the active bookmark |
419 and where to move the active bookmark from, if needed.''' |
423 and where to move the active bookmark from, if needed.''' |
420 checkout, movemarkfrom = None, None |
424 checkout, movemarkfrom = None, None |
421 activemark = repo._activebookmark |
425 activemark = repo._activebookmark |
422 if isactivewdirparent(repo): |
426 if isactivewdirparent(repo): |
423 movemarkfrom = repo['.'].node() |
427 movemarkfrom = repo[b'.'].node() |
424 elif activemark: |
428 elif activemark: |
425 ui.status(_("updating to active bookmark %s\n") % activemark) |
429 ui.status(_(b"updating to active bookmark %s\n") % activemark) |
426 checkout = activemark |
430 checkout = activemark |
427 return (checkout, movemarkfrom) |
431 return (checkout, movemarkfrom) |
428 |
432 |
429 |
433 |
430 def update(repo, parents, node): |
434 def update(repo, parents, node): |
438 if marks[active] in parents: |
442 if marks[active] in parents: |
439 new = repo[node] |
443 new = repo[node] |
440 divs = [ |
444 divs = [ |
441 repo[marks[b]] |
445 repo[marks[b]] |
442 for b in marks |
446 for b in marks |
443 if b.split('@', 1)[0] == active.split('@', 1)[0] |
447 if b.split(b'@', 1)[0] == active.split(b'@', 1)[0] |
444 ] |
448 ] |
445 anc = repo.changelog.ancestors([new.rev()]) |
449 anc = repo.changelog.ancestors([new.rev()]) |
446 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new] |
450 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new] |
447 if validdest(repo, repo[marks[active]], new): |
451 if validdest(repo, repo[marks[active]], new): |
448 bmchanges.append((active, new.node())) |
452 bmchanges.append((active, new.node())) |
449 |
453 |
450 for bm in divergent2delete(repo, deletefrom, active): |
454 for bm in divergent2delete(repo, deletefrom, active): |
451 bmchanges.append((bm, None)) |
455 bmchanges.append((bm, None)) |
452 |
456 |
453 if bmchanges: |
457 if bmchanges: |
454 with repo.lock(), repo.transaction('bookmark') as tr: |
458 with repo.lock(), repo.transaction(b'bookmark') as tr: |
455 marks.applychanges(repo, tr, bmchanges) |
459 marks.applychanges(repo, tr, bmchanges) |
456 return bool(bmchanges) |
460 return bool(bmchanges) |
457 |
461 |
458 |
462 |
459 def listbinbookmarks(repo): |
463 def listbinbookmarks(repo): |
478 def pushbookmark(repo, key, old, new): |
482 def pushbookmark(repo, key, old, new): |
479 if bookmarksinstore(repo): |
483 if bookmarksinstore(repo): |
480 wlock = util.nullcontextmanager() |
484 wlock = util.nullcontextmanager() |
481 else: |
485 else: |
482 wlock = repo.wlock() |
486 wlock = repo.wlock() |
483 with wlock, repo.lock(), repo.transaction('bookmarks') as tr: |
487 with wlock, repo.lock(), repo.transaction(b'bookmarks') as tr: |
484 marks = repo._bookmarks |
488 marks = repo._bookmarks |
485 existing = hex(marks.get(key, '')) |
489 existing = hex(marks.get(key, b'')) |
486 if existing != old and existing != new: |
490 if existing != old and existing != new: |
487 return False |
491 return False |
488 if new == '': |
492 if new == b'': |
489 changes = [(key, None)] |
493 changes = [(key, None)] |
490 else: |
494 else: |
491 if new not in repo: |
495 if new not in repo: |
492 return False |
496 return False |
493 changes = [(key, repo[new].node())] |
497 changes = [(key, repo[new].node())] |
578 bookmark name. |
582 bookmark name. |
579 |
583 |
580 This reuses already existing one with "@number" suffix, if it |
584 This reuses already existing one with "@number" suffix, if it |
581 refers ``remotenode``. |
585 refers ``remotenode``. |
582 ''' |
586 ''' |
583 if b == '@': |
587 if b == b'@': |
584 b = '' |
588 b = b'' |
585 # try to use an @pathalias suffix |
589 # try to use an @pathalias suffix |
586 # if an @pathalias already exists, we overwrite (update) it |
590 # if an @pathalias already exists, we overwrite (update) it |
587 if path.startswith("file:"): |
591 if path.startswith(b"file:"): |
588 path = util.url(path).path |
592 path = util.url(path).path |
589 for p, u in ui.configitems("paths"): |
593 for p, u in ui.configitems(b"paths"): |
590 if u.startswith("file:"): |
594 if u.startswith(b"file:"): |
591 u = util.url(u).path |
595 u = util.url(u).path |
592 if path == u: |
596 if path == u: |
593 return '%s@%s' % (b, p) |
597 return b'%s@%s' % (b, p) |
594 |
598 |
595 # assign a unique "@number" suffix newly |
599 # assign a unique "@number" suffix newly |
596 for x in range(1, 100): |
600 for x in range(1, 100): |
597 n = '%s@%d' % (b, x) |
601 n = b'%s@%d' % (b, x) |
598 if n not in localmarks or localmarks[n] == remotenode: |
602 if n not in localmarks or localmarks[n] == remotenode: |
599 return n |
603 return n |
600 |
604 |
601 return None |
605 return None |
602 |
606 |
628 for book, node in bookmarks: |
632 for book, node in bookmarks: |
629 if not node: # None or '' |
633 if not node: # None or '' |
630 node = wdirid |
634 node = wdirid |
631 binarydata.append(_binaryentry.pack(node, len(book))) |
635 binarydata.append(_binaryentry.pack(node, len(book))) |
632 binarydata.append(book) |
636 binarydata.append(book) |
633 return ''.join(binarydata) |
637 return b''.join(binarydata) |
634 |
638 |
635 |
639 |
636 def binarydecode(stream): |
640 def binarydecode(stream): |
637 """decode a binary stream into an '(bookmark, node)' iterable |
641 """decode a binary stream into an '(bookmark, node)' iterable |
638 |
642 |
650 books = [] |
654 books = [] |
651 while True: |
655 while True: |
652 entry = stream.read(entrysize) |
656 entry = stream.read(entrysize) |
653 if len(entry) < entrysize: |
657 if len(entry) < entrysize: |
654 if entry: |
658 if entry: |
655 raise error.Abort(_('bad bookmark stream')) |
659 raise error.Abort(_(b'bad bookmark stream')) |
656 break |
660 break |
657 node, length = _binaryentry.unpack(entry) |
661 node, length = _binaryentry.unpack(entry) |
658 bookmark = stream.read(length) |
662 bookmark = stream.read(length) |
659 if len(bookmark) < length: |
663 if len(bookmark) < length: |
660 if entry: |
664 if entry: |
661 raise error.Abort(_('bad bookmark stream')) |
665 raise error.Abort(_(b'bad bookmark stream')) |
662 if node == wdirid: |
666 if node == wdirid: |
663 node = None |
667 node = None |
664 books.append((bookmark, node)) |
668 books.append((bookmark, node)) |
665 return books |
669 return books |
666 |
670 |
667 |
671 |
668 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()): |
672 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()): |
669 ui.debug("checking for updated bookmarks\n") |
673 ui.debug(b"checking for updated bookmarks\n") |
670 localmarks = repo._bookmarks |
674 localmarks = repo._bookmarks |
671 ( |
675 ( |
672 addsrc, |
676 addsrc, |
673 adddst, |
677 adddst, |
674 advsrc, |
678 advsrc, |
679 same, |
683 same, |
680 ) = comparebookmarks(repo, remotemarks, localmarks) |
684 ) = comparebookmarks(repo, remotemarks, localmarks) |
681 |
685 |
682 status = ui.status |
686 status = ui.status |
683 warn = ui.warn |
687 warn = ui.warn |
684 if ui.configbool('ui', 'quietbookmarkmove'): |
688 if ui.configbool(b'ui', b'quietbookmarkmove'): |
685 status = warn = ui.debug |
689 status = warn = ui.debug |
686 |
690 |
687 explicit = set(explicit) |
691 explicit = set(explicit) |
688 changed = [] |
692 changed = [] |
689 for b, scid, dcid in addsrc: |
693 for b, scid, dcid in addsrc: |
690 if scid in repo: # add remote bookmarks for changes we already have |
694 if scid in repo: # add remote bookmarks for changes we already have |
691 changed.append( |
695 changed.append( |
692 (b, scid, status, _("adding remote bookmark %s\n") % b) |
696 (b, scid, status, _(b"adding remote bookmark %s\n") % b) |
693 ) |
697 ) |
694 elif b in explicit: |
698 elif b in explicit: |
695 explicit.remove(b) |
699 explicit.remove(b) |
696 ui.warn( |
700 ui.warn( |
697 _("remote bookmark %s points to locally missing %s\n") |
701 _(b"remote bookmark %s points to locally missing %s\n") |
698 % (b, hex(scid)[:12]) |
702 % (b, hex(scid)[:12]) |
699 ) |
703 ) |
700 |
704 |
701 for b, scid, dcid in advsrc: |
705 for b, scid, dcid in advsrc: |
702 changed.append((b, scid, status, _("updating bookmark %s\n") % b)) |
706 changed.append((b, scid, status, _(b"updating bookmark %s\n") % b)) |
703 # remove normal movement from explicit set |
707 # remove normal movement from explicit set |
704 explicit.difference_update(d[0] for d in changed) |
708 explicit.difference_update(d[0] for d in changed) |
705 |
709 |
706 for b, scid, dcid in diverge: |
710 for b, scid, dcid in diverge: |
707 if b in explicit: |
711 if b in explicit: |
708 explicit.discard(b) |
712 explicit.discard(b) |
709 changed.append((b, scid, status, _("importing bookmark %s\n") % b)) |
713 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b)) |
710 else: |
714 else: |
711 db = _diverge(ui, b, path, localmarks, scid) |
715 db = _diverge(ui, b, path, localmarks, scid) |
712 if db: |
716 if db: |
713 changed.append( |
717 changed.append( |
714 ( |
718 ( |
715 db, |
719 db, |
716 scid, |
720 scid, |
717 warn, |
721 warn, |
718 _("divergent bookmark %s stored as %s\n") % (b, db), |
722 _(b"divergent bookmark %s stored as %s\n") % (b, db), |
719 ) |
723 ) |
720 ) |
724 ) |
721 else: |
725 else: |
722 warn( |
726 warn( |
723 _( |
727 _( |
724 "warning: failed to assign numbered name " |
728 b"warning: failed to assign numbered name " |
725 "to divergent bookmark %s\n" |
729 b"to divergent bookmark %s\n" |
726 ) |
730 ) |
727 % b |
731 % b |
728 ) |
732 ) |
729 for b, scid, dcid in adddst + advdst: |
733 for b, scid, dcid in adddst + advdst: |
730 if b in explicit: |
734 if b in explicit: |
731 explicit.discard(b) |
735 explicit.discard(b) |
732 changed.append((b, scid, status, _("importing bookmark %s\n") % b)) |
736 changed.append((b, scid, status, _(b"importing bookmark %s\n") % b)) |
733 for b, scid, dcid in differ: |
737 for b, scid, dcid in differ: |
734 if b in explicit: |
738 if b in explicit: |
735 explicit.remove(b) |
739 explicit.remove(b) |
736 ui.warn( |
740 ui.warn( |
737 _("remote bookmark %s points to locally missing %s\n") |
741 _(b"remote bookmark %s points to locally missing %s\n") |
738 % (b, hex(scid)[:12]) |
742 % (b, hex(scid)[:12]) |
739 ) |
743 ) |
740 |
744 |
741 if changed: |
745 if changed: |
742 tr = trfunc() |
746 tr = trfunc() |
748 |
752 |
749 |
753 |
750 def incoming(ui, repo, peer): |
754 def incoming(ui, repo, peer): |
751 '''Show bookmarks incoming from other to repo |
755 '''Show bookmarks incoming from other to repo |
752 ''' |
756 ''' |
753 ui.status(_("searching for changed bookmarks\n")) |
757 ui.status(_(b"searching for changed bookmarks\n")) |
754 |
758 |
755 with peer.commandexecutor() as e: |
759 with peer.commandexecutor() as e: |
756 remotemarks = unhexlifybookmarks( |
760 remotemarks = unhexlifybookmarks( |
757 e.callcommand('listkeys', {'namespace': 'bookmarks',}).result() |
761 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result() |
758 ) |
762 ) |
759 |
763 |
760 r = comparebookmarks(repo, remotemarks, repo._bookmarks) |
764 r = comparebookmarks(repo, remotemarks, repo._bookmarks) |
761 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r |
765 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r |
762 |
766 |
766 else: |
770 else: |
767 getid = lambda id: id[:12] |
771 getid = lambda id: id[:12] |
768 if ui.verbose: |
772 if ui.verbose: |
769 |
773 |
770 def add(b, id, st): |
774 def add(b, id, st): |
771 incomings.append(" %-25s %s %s\n" % (b, getid(id), st)) |
775 incomings.append(b" %-25s %s %s\n" % (b, getid(id), st)) |
772 |
776 |
773 else: |
777 else: |
774 |
778 |
775 def add(b, id, st): |
779 def add(b, id, st): |
776 incomings.append(" %-25s %s\n" % (b, getid(id))) |
780 incomings.append(b" %-25s %s\n" % (b, getid(id))) |
777 |
781 |
778 for b, scid, dcid in addsrc: |
782 for b, scid, dcid in addsrc: |
779 # i18n: "added" refers to a bookmark |
783 # i18n: "added" refers to a bookmark |
780 add(b, hex(scid), _('added')) |
784 add(b, hex(scid), _(b'added')) |
781 for b, scid, dcid in advsrc: |
785 for b, scid, dcid in advsrc: |
782 # i18n: "advanced" refers to a bookmark |
786 # i18n: "advanced" refers to a bookmark |
783 add(b, hex(scid), _('advanced')) |
787 add(b, hex(scid), _(b'advanced')) |
784 for b, scid, dcid in diverge: |
788 for b, scid, dcid in diverge: |
785 # i18n: "diverged" refers to a bookmark |
789 # i18n: "diverged" refers to a bookmark |
786 add(b, hex(scid), _('diverged')) |
790 add(b, hex(scid), _(b'diverged')) |
787 for b, scid, dcid in differ: |
791 for b, scid, dcid in differ: |
788 # i18n: "changed" refers to a bookmark |
792 # i18n: "changed" refers to a bookmark |
789 add(b, hex(scid), _('changed')) |
793 add(b, hex(scid), _(b'changed')) |
790 |
794 |
791 if not incomings: |
795 if not incomings: |
792 ui.status(_("no changed bookmarks found\n")) |
796 ui.status(_(b"no changed bookmarks found\n")) |
793 return 1 |
797 return 1 |
794 |
798 |
795 for s in sorted(incomings): |
799 for s in sorted(incomings): |
796 ui.write(s) |
800 ui.write(s) |
797 |
801 |
799 |
803 |
800 |
804 |
801 def outgoing(ui, repo, other): |
805 def outgoing(ui, repo, other): |
802 '''Show bookmarks outgoing from repo to other |
806 '''Show bookmarks outgoing from repo to other |
803 ''' |
807 ''' |
804 ui.status(_("searching for changed bookmarks\n")) |
808 ui.status(_(b"searching for changed bookmarks\n")) |
805 |
809 |
806 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks')) |
810 remotemarks = unhexlifybookmarks(other.listkeys(b'bookmarks')) |
807 r = comparebookmarks(repo, repo._bookmarks, remotemarks) |
811 r = comparebookmarks(repo, repo._bookmarks, remotemarks) |
808 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r |
812 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r |
809 |
813 |
810 outgoings = [] |
814 outgoings = [] |
811 if ui.debugflag: |
815 if ui.debugflag: |
813 else: |
817 else: |
814 getid = lambda id: id[:12] |
818 getid = lambda id: id[:12] |
815 if ui.verbose: |
819 if ui.verbose: |
816 |
820 |
817 def add(b, id, st): |
821 def add(b, id, st): |
818 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st)) |
822 outgoings.append(b" %-25s %s %s\n" % (b, getid(id), st)) |
819 |
823 |
820 else: |
824 else: |
821 |
825 |
822 def add(b, id, st): |
826 def add(b, id, st): |
823 outgoings.append(" %-25s %s\n" % (b, getid(id))) |
827 outgoings.append(b" %-25s %s\n" % (b, getid(id))) |
824 |
828 |
825 for b, scid, dcid in addsrc: |
829 for b, scid, dcid in addsrc: |
826 # i18n: "added refers to a bookmark |
830 # i18n: "added refers to a bookmark |
827 add(b, hex(scid), _('added')) |
831 add(b, hex(scid), _(b'added')) |
828 for b, scid, dcid in adddst: |
832 for b, scid, dcid in adddst: |
829 # i18n: "deleted" refers to a bookmark |
833 # i18n: "deleted" refers to a bookmark |
830 add(b, ' ' * 40, _('deleted')) |
834 add(b, b' ' * 40, _(b'deleted')) |
831 for b, scid, dcid in advsrc: |
835 for b, scid, dcid in advsrc: |
832 # i18n: "advanced" refers to a bookmark |
836 # i18n: "advanced" refers to a bookmark |
833 add(b, hex(scid), _('advanced')) |
837 add(b, hex(scid), _(b'advanced')) |
834 for b, scid, dcid in diverge: |
838 for b, scid, dcid in diverge: |
835 # i18n: "diverged" refers to a bookmark |
839 # i18n: "diverged" refers to a bookmark |
836 add(b, hex(scid), _('diverged')) |
840 add(b, hex(scid), _(b'diverged')) |
837 for b, scid, dcid in differ: |
841 for b, scid, dcid in differ: |
838 # i18n: "changed" refers to a bookmark |
842 # i18n: "changed" refers to a bookmark |
839 add(b, hex(scid), _('changed')) |
843 add(b, hex(scid), _(b'changed')) |
840 |
844 |
841 if not outgoings: |
845 if not outgoings: |
842 ui.status(_("no changed bookmarks found\n")) |
846 ui.status(_(b"no changed bookmarks found\n")) |
843 return 1 |
847 return 1 |
844 |
848 |
845 for s in sorted(outgoings): |
849 for s in sorted(outgoings): |
846 ui.write(s) |
850 ui.write(s) |
847 |
851 |
853 |
857 |
854 This returns "(# of incoming, # of outgoing)" tuple. |
858 This returns "(# of incoming, # of outgoing)" tuple. |
855 ''' |
859 ''' |
856 with peer.commandexecutor() as e: |
860 with peer.commandexecutor() as e: |
857 remotemarks = unhexlifybookmarks( |
861 remotemarks = unhexlifybookmarks( |
858 e.callcommand('listkeys', {'namespace': 'bookmarks',}).result() |
862 e.callcommand(b'listkeys', {b'namespace': b'bookmarks',}).result() |
859 ) |
863 ) |
860 |
864 |
861 r = comparebookmarks(repo, remotemarks, repo._bookmarks) |
865 r = comparebookmarks(repo, remotemarks, repo._bookmarks) |
862 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r |
866 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r |
863 return (len(addsrc), len(adddst)) |
867 return (len(addsrc), len(adddst)) |
921 Raises an abort error if old is not in the bookmark store. |
925 Raises an abort error if old is not in the bookmark store. |
922 """ |
926 """ |
923 marks = repo._bookmarks |
927 marks = repo._bookmarks |
924 mark = checkformat(repo, new) |
928 mark = checkformat(repo, new) |
925 if old not in marks: |
929 if old not in marks: |
926 raise error.Abort(_("bookmark '%s' does not exist") % old) |
930 raise error.Abort(_(b"bookmark '%s' does not exist") % old) |
927 changes = [] |
931 changes = [] |
928 for bm in marks.checkconflict(mark, force): |
932 for bm in marks.checkconflict(mark, force): |
929 changes.append((bm, None)) |
933 changes.append((bm, None)) |
930 changes.extend([(mark, marks[old]), (old, None)]) |
934 changes.extend([(mark, marks[old]), (old, None)]) |
931 marks.applychanges(repo, tr, changes) |
935 marks.applychanges(repo, tr, changes) |
970 for bm in marks.checkconflict(mark, force, tgt): |
974 for bm in marks.checkconflict(mark, force, tgt): |
971 changes.append((bm, None)) |
975 changes.append((bm, None)) |
972 changes.append((mark, tgt)) |
976 changes.append((mark, tgt)) |
973 |
977 |
974 if hiddenrev: |
978 if hiddenrev: |
975 repo.ui.warn(_("bookmarking hidden changeset %s\n") % hiddenrev) |
979 repo.ui.warn(_(b"bookmarking hidden changeset %s\n") % hiddenrev) |
976 |
980 |
977 if ctx.obsolete(): |
981 if ctx.obsolete(): |
978 msg = obsutil._getfilteredreason(repo, "%s" % hiddenrev, ctx) |
982 msg = obsutil._getfilteredreason(repo, b"%s" % hiddenrev, ctx) |
979 repo.ui.warn("(%s)\n" % msg) |
983 repo.ui.warn(b"(%s)\n" % msg) |
980 |
984 |
981 marks.applychanges(repo, tr, changes) |
985 marks.applychanges(repo, tr, changes) |
982 if not inactive and cur == marks[newact] and not rev: |
986 if not inactive and cur == marks[newact] and not rev: |
983 activate(repo, newact) |
987 activate(repo, newact) |
984 elif cur != tgt and newact == repo._activebookmark: |
988 elif cur != tgt and newact == repo._activebookmark: |
991 Provides a way for extensions to control how bookmarks are printed (e.g. |
995 Provides a way for extensions to control how bookmarks are printed (e.g. |
992 prepend or postpend names) |
996 prepend or postpend names) |
993 """ |
997 """ |
994 hexfn = fm.hexfunc |
998 hexfn = fm.hexfunc |
995 if len(bmarks) == 0 and fm.isplain(): |
999 if len(bmarks) == 0 and fm.isplain(): |
996 ui.status(_("no bookmarks set\n")) |
1000 ui.status(_(b"no bookmarks set\n")) |
997 for bmark, (n, prefix, label) in sorted(bmarks.iteritems()): |
1001 for bmark, (n, prefix, label) in sorted(bmarks.iteritems()): |
998 fm.startitem() |
1002 fm.startitem() |
999 fm.context(repo=repo) |
1003 fm.context(repo=repo) |
1000 if not ui.quiet: |
1004 if not ui.quiet: |
1001 fm.plain(' %s ' % prefix, label=label) |
1005 fm.plain(b' %s ' % prefix, label=label) |
1002 fm.write('bookmark', '%s', bmark, label=label) |
1006 fm.write(b'bookmark', b'%s', bmark, label=label) |
1003 pad = " " * (25 - encoding.colwidth(bmark)) |
1007 pad = b" " * (25 - encoding.colwidth(bmark)) |
1004 fm.condwrite( |
1008 fm.condwrite( |
1005 not ui.quiet, |
1009 not ui.quiet, |
1006 'rev node', |
1010 b'rev node', |
1007 pad + ' %d:%s', |
1011 pad + b' %d:%s', |
1008 repo.changelog.rev(n), |
1012 repo.changelog.rev(n), |
1009 hexfn(n), |
1013 hexfn(n), |
1010 label=label, |
1014 label=label, |
1011 ) |
1015 ) |
1012 fm.data(active=(activebookmarklabel in label)) |
1016 fm.data(active=(activebookmarklabel in label)) |
1013 fm.plain('\n') |
1017 fm.plain(b'\n') |
1014 |
1018 |
1015 |
1019 |
1016 def printbookmarks(ui, repo, fm, names=None): |
1020 def printbookmarks(ui, repo, fm, names=None): |
1017 """print bookmarks by the given formatter |
1021 """print bookmarks by the given formatter |
1018 |
1022 |
1020 """ |
1024 """ |
1021 marks = repo._bookmarks |
1025 marks = repo._bookmarks |
1022 bmarks = {} |
1026 bmarks = {} |
1023 for bmark in names or marks: |
1027 for bmark in names or marks: |
1024 if bmark not in marks: |
1028 if bmark not in marks: |
1025 raise error.Abort(_("bookmark '%s' does not exist") % bmark) |
1029 raise error.Abort(_(b"bookmark '%s' does not exist") % bmark) |
1026 active = repo._activebookmark |
1030 active = repo._activebookmark |
1027 if bmark == active: |
1031 if bmark == active: |
1028 prefix, label = '*', activebookmarklabel |
1032 prefix, label = b'*', activebookmarklabel |
1029 else: |
1033 else: |
1030 prefix, label = ' ', '' |
1034 prefix, label = b' ', b'' |
1031 |
1035 |
1032 bmarks[bmark] = (marks[bmark], prefix, label) |
1036 bmarks[bmark] = (marks[bmark], prefix, label) |
1033 _printbookmarks(ui, repo, fm, bmarks) |
1037 _printbookmarks(ui, repo, fm, bmarks) |
1034 |
1038 |
1035 |
1039 |
1036 def preparehookargs(name, old, new): |
1040 def preparehookargs(name, old, new): |
1037 if new is None: |
1041 if new is None: |
1038 new = '' |
1042 new = b'' |
1039 if old is None: |
1043 if old is None: |
1040 old = '' |
1044 old = b'' |
1041 return {'bookmark': name, 'node': hex(new), 'oldnode': hex(old)} |
1045 return {b'bookmark': name, b'node': hex(new), b'oldnode': hex(old)} |