Show More
@@ -125,6 +125,10 b' def extsetup(ui):' | |||||
125 |
|
125 | |||
126 | def _hassharedbookmarks(repo): |
|
126 | def _hassharedbookmarks(repo): | |
127 | """Returns whether this repo has shared bookmarks""" |
|
127 | """Returns whether this repo has shared bookmarks""" | |
|
128 | if bookmarks.bookmarksinstore(repo): | |||
|
129 | # Kind of a lie, but it means that we skip our custom reads and writes | |||
|
130 | # from/to the source repo. | |||
|
131 | return False | |||
128 | try: |
|
132 | try: | |
129 | shared = repo.vfs.read('shared').splitlines() |
|
133 | shared = repo.vfs.read('shared').splitlines() | |
130 | except IOError as inst: |
|
134 | except IOError as inst: |
@@ -33,6 +33,14 b' from . import (' | |||||
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 | |||
@@ -40,7 +48,7 b' def _getbkfile(repo):' | |||||
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 |
|
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): | |
@@ -91,8 +99,11 b' class bmstore(object):' | |||||
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 |
|
|
102 | bookmarkspath = '.hg/bookmarks' | |
95 |
|
|
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 | |
@@ -192,8 +203,9 b' class bmstore(object):' | |||||
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= |
|
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): | |
@@ -203,9 +215,14 b' class bmstore(object):' | |||||
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): | |
@@ -428,7 +445,11 b' def listbookmarks(repo):' | |||||
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: |
@@ -676,6 +676,9 b" coreconfigitem('extdata', '.*'," | |||||
676 | default=None, |
|
676 | default=None, | |
677 | generic=True, |
|
677 | generic=True, | |
678 | ) |
|
678 | ) | |
|
679 | coreconfigitem('format', 'bookmarks-in-store', | |||
|
680 | default=False, | |||
|
681 | ) | |||
679 | coreconfigitem('format', 'chunkcachesize', |
|
682 | coreconfigitem('format', 'chunkcachesize', | |
680 | default=None, |
|
683 | default=None, | |
681 | ) |
|
684 | ) |
@@ -879,6 +879,15 b' https://www.mercurial-scm.org/wiki/Missi' | |||||
879 |
|
879 | |||
880 | On some system, Mercurial installation may lack `zstd` supports. Default is `zlib`. |
|
880 | On some system, Mercurial installation may lack `zstd` supports. Default is `zlib`. | |
881 |
|
881 | |||
|
882 | ``bookmarks-in-store`` | |||
|
883 | Store bookmarks in .hg/store/. This means that bookmarks are shared when | |||
|
884 | using `hg share` regardless of the `-B` option. | |||
|
885 | ||||
|
886 | Repositories with this on-disk format require Mercurial version 5.1. | |||
|
887 | ||||
|
888 | Disabled by default. | |||
|
889 | ||||
|
890 | ||||
882 | ``graph`` |
|
891 | ``graph`` | |
883 | --------- |
|
892 | --------- | |
884 |
|
893 |
@@ -122,6 +122,25 b' class storecache(_basefilecache):' | |||||
122 | def join(self, obj, fname): |
|
122 | def join(self, obj, fname): | |
123 | return obj.sjoin(fname) |
|
123 | return obj.sjoin(fname) | |
124 |
|
124 | |||
|
125 | class mixedrepostorecache(_basefilecache): | |||
|
126 | """filecache for a mix files in .hg/store and outside""" | |||
|
127 | def __init__(self, *pathsandlocations): | |||
|
128 | # scmutil.filecache only uses the path for passing back into our | |||
|
129 | # join(), so we can safely pass a list of paths and locations | |||
|
130 | super(mixedrepostorecache, self).__init__(*pathsandlocations) | |||
|
131 | for path, location in pathsandlocations: | |||
|
132 | _cachedfiles.update(pathsandlocations) | |||
|
133 | ||||
|
134 | def join(self, obj, fnameandlocation): | |||
|
135 | fname, location = fnameandlocation | |||
|
136 | if location == '': | |||
|
137 | return obj.vfs.join(fname) | |||
|
138 | else: | |||
|
139 | if location != 'store': | |||
|
140 | raise error.ProgrammingError('unexpected location: %s' % | |||
|
141 | location) | |||
|
142 | return obj.sjoin(fname) | |||
|
143 | ||||
125 | def isfilecached(repo, name): |
|
144 | def isfilecached(repo, name): | |
126 | """check if a repo has already cached "name" filecache-ed property |
|
145 | """check if a repo has already cached "name" filecache-ed property | |
127 |
|
146 | |||
@@ -891,6 +910,7 b' class localrepository(object):' | |||||
891 | 'treemanifest', |
|
910 | 'treemanifest', | |
892 | REVLOGV2_REQUIREMENT, |
|
911 | REVLOGV2_REQUIREMENT, | |
893 | SPARSEREVLOG_REQUIREMENT, |
|
912 | SPARSEREVLOG_REQUIREMENT, | |
|
913 | bookmarks.BOOKMARKS_IN_STORE_REQUIREMENT, | |||
894 | } |
|
914 | } | |
895 | _basesupported = supportedformats | { |
|
915 | _basesupported = supportedformats | { | |
896 | 'store', |
|
916 | 'store', | |
@@ -1205,7 +1225,8 b' class localrepository(object):' | |||||
1205 | cls = repoview.newtype(self.unfiltered().__class__) |
|
1225 | cls = repoview.newtype(self.unfiltered().__class__) | |
1206 | return cls(self, name, visibilityexceptions) |
|
1226 | return cls(self, name, visibilityexceptions) | |
1207 |
|
1227 | |||
1208 |
@ |
|
1228 | @mixedrepostorecache(('bookmarks', ''), ('bookmarks.current', ''), | |
|
1229 | ('bookmarks', 'store')) | |||
1209 | def _bookmarks(self): |
|
1230 | def _bookmarks(self): | |
1210 | return bookmarks.bmstore(self) |
|
1231 | return bookmarks.bmstore(self) | |
1211 |
|
1232 | |||
@@ -1962,7 +1983,7 b' class localrepository(object):' | |||||
1962 | (self.vfs, 'journal.dirstate'), |
|
1983 | (self.vfs, 'journal.dirstate'), | |
1963 | (self.vfs, 'journal.branch'), |
|
1984 | (self.vfs, 'journal.branch'), | |
1964 | (self.vfs, 'journal.desc'), |
|
1985 | (self.vfs, 'journal.desc'), | |
1965 |
(self |
|
1986 | (bookmarks.bookmarksvfs(self), 'journal.bookmarks'), | |
1966 | (self.svfs, 'journal.phaseroots')) |
|
1987 | (self.svfs, 'journal.phaseroots')) | |
1967 |
|
1988 | |||
1968 | def undofiles(self): |
|
1989 | def undofiles(self): | |
@@ -1977,8 +1998,9 b' class localrepository(object):' | |||||
1977 | encoding.fromlocal(self.dirstate.branch())) |
|
1998 | encoding.fromlocal(self.dirstate.branch())) | |
1978 | self.vfs.write("journal.desc", |
|
1999 | self.vfs.write("journal.desc", | |
1979 | "%d\n%s\n" % (len(self), desc)) |
|
2000 | "%d\n%s\n" % (len(self), desc)) | |
1980 | self.vfs.write("journal.bookmarks", |
|
2001 | bookmarksvfs = bookmarks.bookmarksvfs(self) | |
1981 | self.vfs.tryread("bookmarks")) |
|
2002 | bookmarksvfs.write("journal.bookmarks", | |
|
2003 | bookmarksvfs.tryread("bookmarks")) | |||
1982 | self.svfs.write("journal.phaseroots", |
|
2004 | self.svfs.write("journal.phaseroots", | |
1983 | self.svfs.tryread("phaseroots")) |
|
2005 | self.svfs.tryread("phaseroots")) | |
1984 |
|
2006 | |||
@@ -2048,8 +2070,9 b' class localrepository(object):' | |||||
2048 | vfsmap = {'plain': self.vfs, '': self.svfs} |
|
2070 | vfsmap = {'plain': self.vfs, '': self.svfs} | |
2049 | transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn, |
|
2071 | transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn, | |
2050 | checkambigfiles=_cachedfiles) |
|
2072 | checkambigfiles=_cachedfiles) | |
2051 | if self.vfs.exists('undo.bookmarks'): |
|
2073 | bookmarksvfs = bookmarks.bookmarksvfs(self) | |
2052 | self.vfs.rename('undo.bookmarks', 'bookmarks', checkambig=True) |
|
2074 | if bookmarksvfs.exists('undo.bookmarks'): | |
|
2075 | bookmarksvfs.rename('undo.bookmarks', 'bookmarks', checkambig=True) | |||
2053 | if self.svfs.exists('undo.phaseroots'): |
|
2076 | if self.svfs.exists('undo.phaseroots'): | |
2054 | self.svfs.rename('undo.phaseroots', 'phaseroots', checkambig=True) |
|
2077 | self.svfs.rename('undo.phaseroots', 'phaseroots', checkambig=True) | |
2055 | self.invalidate() |
|
2078 | self.invalidate() | |
@@ -3003,6 +3026,9 b' def newreporequirements(ui, createopts):' | |||||
3003 | if createopts.get('lfs'): |
|
3026 | if createopts.get('lfs'): | |
3004 | requirements.add('lfs') |
|
3027 | requirements.add('lfs') | |
3005 |
|
3028 | |||
|
3029 | if ui.configbool('format', 'bookmarks-in-store'): | |||
|
3030 | requirements.add(bookmarks.BOOKMARKS_IN_STORE_REQUIREMENT) | |||
|
3031 | ||||
3006 | return requirements |
|
3032 | return requirements | |
3007 |
|
3033 | |||
3008 | def filterknowncreateopts(ui, createopts): |
|
3034 | def filterknowncreateopts(ui, createopts): |
@@ -337,7 +337,7 b' def _calcmode(vfs):' | |||||
337 | mode = None |
|
337 | mode = None | |
338 | return mode |
|
338 | return mode | |
339 |
|
339 | |||
340 | _data = ('narrowspec data meta 00manifest.d 00manifest.i' |
|
340 | _data = ('bookmarks narrowspec data meta 00manifest.d 00manifest.i' | |
341 | ' 00changelog.d 00changelog.i phaseroots obsstore') |
|
341 | ' 00changelog.d 00changelog.i phaseroots obsstore') | |
342 |
|
342 | |||
343 | def isrevlog(f, kind, st): |
|
343 | def isrevlog(f, kind, st): | |
@@ -612,7 +612,7 b' class fncachestore(basicstore):' | |||||
612 | raise |
|
612 | raise | |
613 |
|
613 | |||
614 | def copylist(self): |
|
614 | def copylist(self): | |
615 | d = ('narrowspec data meta dh fncache phaseroots obsstore' |
|
615 | d = ('bookmarks narrowspec data meta dh fncache phaseroots obsstore' | |
616 | ' 00manifest.d 00manifest.i 00changelog.d 00changelog.i') |
|
616 | ' 00manifest.d 00manifest.i 00changelog.d 00changelog.i') | |
617 | return (['requires', '00changelog.i'] + |
|
617 | return (['requires', '00changelog.i'] + | |
618 | ['store/' + f for f in d.split()]) |
|
618 | ['store/' + f for f in d.split()]) |
@@ -1513,6 +1513,8 b' Separate sections from subsections' | |||||
1513 |
|
1513 | |||
1514 | "revlog-compression" |
|
1514 | "revlog-compression" | |
1515 |
|
1515 | |||
|
1516 | "bookmarks-in-store" | |||
|
1517 | ||||
1516 | "profiling" |
|
1518 | "profiling" | |
1517 | ----------- |
|
1519 | ----------- | |
1518 |
|
1520 |
@@ -1,6 +1,13 b'' | |||||
|
1 | #testcases vfs svfs | |||
|
2 | ||||
1 | $ echo "[extensions]" >> $HGRCPATH |
|
3 | $ echo "[extensions]" >> $HGRCPATH | |
2 | $ echo "share = " >> $HGRCPATH |
|
4 | $ echo "share = " >> $HGRCPATH | |
3 |
|
5 | |||
|
6 | #if svfs | |||
|
7 | $ echo "[format]" >> $HGRCPATH | |||
|
8 | $ echo "bookmarks-in-store = yes " >> $HGRCPATH | |||
|
9 | #endif | |||
|
10 | ||||
4 | prepare repo1 |
|
11 | prepare repo1 | |
5 |
|
12 | |||
6 | $ hg init repo1 |
|
13 | $ hg init repo1 | |
@@ -33,17 +40,21 b' test sharing bookmarks' | |||||
33 | $ cd ../repo2 |
|
40 | $ cd ../repo2 | |
34 | $ hg book bm2 |
|
41 | $ hg book bm2 | |
35 | $ hg bookmarks |
|
42 | $ hg bookmarks | |
|
43 | bm1 2:c2e0ac586386 (svfs !) | |||
36 | * bm2 2:c2e0ac586386 |
|
44 | * bm2 2:c2e0ac586386 | |
37 | $ cd ../repo3 |
|
45 | $ cd ../repo3 | |
38 | $ hg bookmarks |
|
46 | $ hg bookmarks | |
39 | bm1 2:c2e0ac586386 |
|
47 | bm1 2:c2e0ac586386 | |
|
48 | bm2 2:c2e0ac586386 (svfs !) | |||
40 | $ hg book bm3 |
|
49 | $ hg book bm3 | |
41 | $ hg bookmarks |
|
50 | $ hg bookmarks | |
42 | bm1 2:c2e0ac586386 |
|
51 | bm1 2:c2e0ac586386 | |
|
52 | bm2 2:c2e0ac586386 (svfs !) | |||
43 | * bm3 2:c2e0ac586386 |
|
53 | * bm3 2:c2e0ac586386 | |
44 | $ cd ../repo1 |
|
54 | $ cd ../repo1 | |
45 | $ hg bookmarks |
|
55 | $ hg bookmarks | |
46 | * bm1 2:c2e0ac586386 |
|
56 | * bm1 2:c2e0ac586386 | |
|
57 | bm2 2:c2e0ac586386 (svfs !) | |||
47 | bm3 2:c2e0ac586386 |
|
58 | bm3 2:c2e0ac586386 | |
48 |
|
59 | |||
49 | check whether HG_PENDING makes pending changes only in relatd |
|
60 | check whether HG_PENDING makes pending changes only in relatd | |
@@ -70,14 +81,18 b' Therefore, this test scenario ignores ch' | |||||
70 | $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX |
|
81 | $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX | |
71 | @repo1 |
|
82 | @repo1 | |
72 | bm1 2:c2e0ac586386 |
|
83 | bm1 2:c2e0ac586386 | |
|
84 | bm2 2:c2e0ac586386 (svfs !) | |||
73 | bm3 2:c2e0ac586386 |
|
85 | bm3 2:c2e0ac586386 | |
74 | * bmX 2:c2e0ac586386 |
|
86 | * bmX 2:c2e0ac586386 | |
75 | @repo2 |
|
87 | @repo2 | |
|
88 | bm1 2:c2e0ac586386 (svfs !) | |||
76 | * bm2 2:c2e0ac586386 |
|
89 | * bm2 2:c2e0ac586386 | |
|
90 | bm3 2:c2e0ac586386 (svfs !) | |||
77 | @repo3 |
|
91 | @repo3 | |
78 | bm1 2:c2e0ac586386 |
|
92 | bm1 2:c2e0ac586386 | |
|
93 | bm2 2:c2e0ac586386 (svfs !) | |||
79 | * bm3 2:c2e0ac586386 |
|
94 | * bm3 2:c2e0ac586386 | |
80 | bmX 2:c2e0ac586386 |
|
95 | bmX 2:c2e0ac586386 (vfs !) | |
81 | transaction abort! |
|
96 | transaction abort! | |
82 | rollback completed |
|
97 | rollback completed | |
83 | abort: pretxnclose hook exited with status 1 |
|
98 | abort: pretxnclose hook exited with status 1 | |
@@ -92,11 +107,15 b' src), because (1) HG_PENDING refers only' | |||||
92 | $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX |
|
107 | $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX | |
93 | @repo1 |
|
108 | @repo1 | |
94 | * bm1 2:c2e0ac586386 |
|
109 | * bm1 2:c2e0ac586386 | |
|
110 | bm2 2:c2e0ac586386 (svfs !) | |||
95 | bm3 2:c2e0ac586386 |
|
111 | bm3 2:c2e0ac586386 | |
96 | @repo2 |
|
112 | @repo2 | |
|
113 | bm1 2:c2e0ac586386 (svfs !) | |||
97 | * bm2 2:c2e0ac586386 |
|
114 | * bm2 2:c2e0ac586386 | |
|
115 | bm3 2:c2e0ac586386 (svfs !) | |||
98 | @repo3 |
|
116 | @repo3 | |
99 | bm1 2:c2e0ac586386 |
|
117 | bm1 2:c2e0ac586386 | |
|
118 | bm2 2:c2e0ac586386 (svfs !) | |||
100 | bm3 2:c2e0ac586386 |
|
119 | bm3 2:c2e0ac586386 | |
101 | * bmX 2:c2e0ac586386 |
|
120 | * bmX 2:c2e0ac586386 | |
102 | transaction abort! |
|
121 | transaction abort! | |
@@ -105,6 +124,11 b' src), because (1) HG_PENDING refers only' | |||||
105 | [255] |
|
124 | [255] | |
106 | $ hg book bm3 |
|
125 | $ hg book bm3 | |
107 |
|
126 | |||
|
127 | clean up bm2 since it's uninteresting (not shared in the vfs case and | |||
|
128 | same as bm3 in the svfs case) | |||
|
129 | $ cd ../repo2 | |||
|
130 | $ hg book -d bm2 | |||
|
131 | ||||
108 | $ cd ../repo1 |
|
132 | $ cd ../repo1 | |
109 |
|
133 | |||
110 | test that commits work |
|
134 | test that commits work |
General Comments 0
You need to be logged in to leave comments.
Login now