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 = 'bookmarks.active bookmarks.current' |
35 |
35 |
|
36 BOOKMARKS_IN_STORE_REQUIREMENT = 'bookmarksinstore' |
|
37 |
|
38 def bookmarksinstore(repo): |
|
39 return BOOKMARKS_IN_STORE_REQUIREMENT in repo.requirements |
|
40 |
|
41 def bookmarksvfs(repo): |
|
42 return repo.svfs if bookmarksinstore(repo) else repo.vfs |
|
43 |
36 def _getbkfile(repo): |
44 def _getbkfile(repo): |
37 """Hook so that extensions that mess with the store can hook bm storage. |
45 """Hook so that extensions that mess with the store can hook bm storage. |
38 |
46 |
39 For core, this just handles wether we should see pending |
47 For core, this just handles wether we should see pending |
40 bookmarks or the committed ones. Other extensions (like share) |
48 bookmarks or the committed ones. Other extensions (like share) |
41 may need to tweak this behavior further. |
49 may need to tweak this behavior further. |
42 """ |
50 """ |
43 fp, pending = txnutil.trypending(repo.root, repo.vfs, 'bookmarks') |
51 fp, pending = txnutil.trypending(repo.root, bookmarksvfs(repo), 'bookmarks') |
44 return fp |
52 return fp |
45 |
53 |
46 class bmstore(object): |
54 class bmstore(object): |
47 r"""Storage for bookmarks. |
55 r"""Storage for bookmarks. |
48 |
56 |
89 # TypeError: |
97 # TypeError: |
90 # - bin(...) |
98 # - bin(...) |
91 # ValueError: |
99 # ValueError: |
92 # - node in nm, for non-20-bytes entry |
100 # - node in nm, for non-20-bytes entry |
93 # - split(...), for string without ' ' |
101 # - split(...), for string without ' ' |
94 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') |
102 bookmarkspath = '.hg/bookmarks' |
95 % pycompat.bytestr(line)) |
103 if bookmarksinstore(repo): |
|
104 bookmarkspath = '.hg/store/bookmarks' |
|
105 repo.ui.warn(_('malformed line in %s: %r\n') |
|
106 % (bookmarkspath, pycompat.bytestr(line))) |
96 except IOError as inst: |
107 except IOError as inst: |
97 if inst.errno != errno.ENOENT: |
108 if inst.errno != errno.ENOENT: |
98 raise |
109 raise |
99 self._active = _readactive(repo, self) |
110 self._active = _readactive(repo, self) |
100 |
111 |
190 |
201 |
191 def _recordchange(self, tr): |
202 def _recordchange(self, tr): |
192 """record that bookmarks have been changed in a transaction |
203 """record that bookmarks have been changed in a transaction |
193 |
204 |
194 The transaction is then responsible for updating the file content.""" |
205 The transaction is then responsible for updating the file content.""" |
|
206 location = '' if bookmarksinstore(self._repo) else 'plain' |
195 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write, |
207 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write, |
196 location='plain') |
208 location=location) |
197 tr.hookargs['bookmark_moved'] = '1' |
209 tr.hookargs['bookmark_moved'] = '1' |
198 |
210 |
199 def _writerepo(self, repo): |
211 def _writerepo(self, repo): |
200 """Factored out for extensibility""" |
212 """Factored out for extensibility""" |
201 rbm = repo._bookmarks |
213 rbm = repo._bookmarks |
202 if rbm.active not in self._refmap: |
214 if rbm.active not in self._refmap: |
203 rbm.active = None |
215 rbm.active = None |
204 rbm._writeactive() |
216 rbm._writeactive() |
205 |
217 |
206 with repo.wlock(): |
218 if bookmarksinstore(repo): |
207 with repo.vfs('bookmarks', 'w', atomictemp=True, |
219 vfs = repo.svfs |
208 checkambig=True) as f: |
220 lock = repo.lock() |
|
221 else: |
|
222 vfs = repo.vfs |
|
223 lock = repo.wlock() |
|
224 with lock: |
|
225 with vfs('bookmarks', 'w', atomictemp=True, checkambig=True) as f: |
209 self._write(f) |
226 self._write(f) |
210 |
227 |
211 def _writeactive(self): |
228 def _writeactive(self): |
212 if self._aclean: |
229 if self._aclean: |
213 return |
230 return |
426 for book, node in listbinbookmarks(repo): |
443 for book, node in listbinbookmarks(repo): |
427 d[book] = hex(node) |
444 d[book] = hex(node) |
428 return d |
445 return d |
429 |
446 |
430 def pushbookmark(repo, key, old, new): |
447 def pushbookmark(repo, key, old, new): |
431 with repo.wlock(), repo.lock(), repo.transaction('bookmarks') as tr: |
448 if bookmarksinstore(repo): |
|
449 wlock = util.nullcontextmanager() |
|
450 else: |
|
451 wlock = repo.wlock() |
|
452 with wlock, repo.lock(), repo.transaction('bookmarks') as tr: |
432 marks = repo._bookmarks |
453 marks = repo._bookmarks |
433 existing = hex(marks.get(key, '')) |
454 existing = hex(marks.get(key, '')) |
434 if existing != old and existing != new: |
455 if existing != old and existing != new: |
435 return False |
456 return False |
436 if new == '': |
457 if new == '': |