##// END OF EJS Templates
tags: support 'instant' tag retrieval (issue548)...
Greg Ward -
r9152:4017291c default
parent child Browse files
Show More
@@ -265,11 +265,17 b' class localrepository(repo.repository):'
265 265 tags_.findglobaltags(self.ui, self, alltags, tagtypes)
266 266 tags_.readlocaltags(self.ui, self, alltags, tagtypes)
267 267
268 # Build the return dicts. Have to re-encode tag names because
269 # the tags module always uses UTF-8 (in order not to lose info
270 # writing to the cache), but the rest of Mercurial wants them in
271 # local encoding.
268 272 tags = {}
269 273 for (name, (node, hist)) in alltags.iteritems():
270 274 if node != nullid:
271 tags[name] = node
275 tags[encoding.tolocal(name)] = node
272 276 tags['tip'] = self.changelog.tip()
277 tagtypes = dict([(encoding.tolocal(name), value)
278 for (name, value) in tagtypes.iteritems()])
273 279 return (tags, tagtypes)
274 280
275 281 def tagtype(self, tagname):
@@ -59,7 +59,19 b' def findglobaltags1(ui, repo, alltags, t'
59 59
60 60 def findglobaltags2(ui, repo, alltags, tagtypes):
61 61 '''Same as findglobaltags1(), but with caching.'''
62 (heads, tagfnode, shouldwrite) = _readtagcache(ui, repo)
62 # This is so we can be lazy and assume alltags contains only global
63 # tags when we pass it to _writetagcache().
64 assert len(alltags) == len(tagtypes) == 0, \
65 "findglobaltags() should be called first"
66
67 (heads, tagfnode, cachetags, shouldwrite) = _readtagcache(ui, repo)
68 if cachetags is not None:
69 assert not shouldwrite
70 # XXX is this really 100% correct? are there oddball special
71 # cases where a global tag should outrank a local tag but won't,
72 # because cachetags does not contain rank info?
73 _updatetags(cachetags, 'global', alltags, tagtypes)
74 return
63 75
64 76 _debug(ui, "reading tags from %d head(s): %s\n"
65 77 % (len(heads), map(short, reversed(heads))))
@@ -82,7 +94,7 b' def findglobaltags2(ui, repo, alltags, t'
82 94
83 95 # and update the cache (if necessary)
84 96 if shouldwrite:
85 _writetagcache(ui, repo, heads, tagfnode)
97 _writetagcache(ui, repo, heads, tagfnode, alltags)
86 98
87 99 # Set this to findglobaltags1 to disable tag caching.
88 100 findglobaltags = findglobaltags2
@@ -90,16 +102,17 b' findglobaltags = findglobaltags2'
90 102 def readlocaltags(ui, repo, alltags, tagtypes):
91 103 '''Read local tags in repo. Update alltags and tagtypes.'''
92 104 try:
93 data = encoding.fromlocal(repo.opener("localtags").read())
94 # localtags are stored in the local character set
95 # while the internal tag table is stored in UTF-8
105 # localtags is in the local encoding; re-encode to UTF-8 on
106 # input for consistency with the rest of this module.
107 data = repo.opener("localtags").read()
96 108 filetags = _readtags(
97 ui, repo, data.splitlines(), "localtags")
109 ui, repo, data.splitlines(), "localtags",
110 recode=encoding.fromlocal)
98 111 _updatetags(filetags, "local", alltags, tagtypes)
99 112 except IOError:
100 113 pass
101 114
102 def _readtags(ui, repo, lines, fn):
115 def _readtags(ui, repo, lines, fn, recode=None):
103 116 '''Read tag definitions from a file (or any source of lines).
104 117 Return a mapping from tag name to (node, hist): node is the node id
105 118 from the last line read for that name, and hist is the list of node
@@ -121,7 +134,9 b' def _readtags(ui, repo, lines, fn):'
121 134 except ValueError:
122 135 warn(_("cannot parse entry"))
123 136 continue
124 name = encoding.tolocal(name.strip()) # stored in UTF-8
137 name = name.strip()
138 if recode:
139 name = recode(name)
125 140 try:
126 141 nodebin = bin(nodehex)
127 142 except TypeError:
@@ -173,11 +188,13 b' def _updatetags(filetags, tagtype, allta'
173 188 # the repo.
174 189
175 190 def _readtagcache(ui, repo):
176 '''Read the tag cache and return a tuple (heads, fnodes,
177 shouldwrite). heads is the list of all heads currently in the
178 repository (ordered from tip to oldest) and fnodes is a mapping from
179 head to .hgtags filenode. Caller is responsible for reading tag
180 info from each head.'''
191 '''Read the tag cache and return a tuple (heads, fnodes, cachetags,
192 shouldwrite). If the cache is completely up-to-date, cachetags is a
193 dict of the form returned by _readtags(); otherwise, it is None and
194 heads and fnodes are set. In that case, heads is the list of all
195 heads currently in the repository (ordered from tip to oldest) and
196 fnodes is a mapping from head to .hgtags filenode. If those two are
197 set, caller is responsible for reading tag info from each head.'''
181 198
182 199 try:
183 200 cachefile = repo.opener('tags.cache', 'r')
@@ -202,6 +219,8 b' def _readtagcache(ui, repo):'
202 219 cachefnode = {} # map headnode to filenode
203 220 if cachefile:
204 221 for line in cachefile:
222 if line == "\n":
223 break
205 224 line = line.rstrip().split()
206 225 cacherevs.append(int(line[0]))
207 226 headnode = bin(line[1])
@@ -210,8 +229,6 b' def _readtagcache(ui, repo):'
210 229 fnode = bin(line[2])
211 230 cachefnode[headnode] = fnode
212 231
213 cachefile.close()
214
215 232 tipnode = repo.changelog.tip()
216 233 tiprev = len(repo.changelog) - 1
217 234
@@ -221,14 +238,18 b' def _readtagcache(ui, repo):'
221 238 # have been destroyed by strip or rollback.)
222 239 if cacheheads and cacheheads[0] == tipnode and cacherevs[0] == tiprev:
223 240 _debug(ui, "tag cache: tip unchanged\n")
224 return (cacheheads, cachefnode, False)
241 tags = _readtags(ui, repo, cachefile, cachefile.name)
242 cachefile.close()
243 return (None, None, tags, False)
244 if cachefile:
245 cachefile.close() # ignore rest of file
225 246
226 247 repoheads = repo.heads()
227 248
228 249 # Case 2 (uncommon): empty repo; get out quickly and don't bother
229 250 # writing an empty cache.
230 251 if repoheads == [nullid]:
231 return ([], {}, False)
252 return ([], {}, {}, False)
232 253
233 254 # Case 3 (uncommon): cache file missing or empty.
234 255 if not cacheheads:
@@ -277,9 +298,9 b' def _readtagcache(ui, repo):'
277 298
278 299 # Caller has to iterate over all heads, but can use the filenodes in
279 300 # cachefnode to get to each .hgtags revision quickly.
280 return (repoheads, cachefnode, True)
301 return (repoheads, cachefnode, None, True)
281 302
282 def _writetagcache(ui, repo, heads, tagfnode):
303 def _writetagcache(ui, repo, heads, tagfnode, cachetags):
283 304
284 305 cachefile = repo.opener('tags.cache', 'w', atomictemp=True)
285 306 _debug(ui, 'writing cache file %s\n' % cachefile.name)
@@ -306,5 +327,13 b' def _writetagcache(ui, repo, heads, tagf'
306 327 else:
307 328 cachefile.write('%d %s\n' % (rev, hex(head)))
308 329
330 # Tag names in the cache are in UTF-8 -- which is the whole reason
331 # we keep them in UTF-8 throughout this module. If we converted
332 # them local encoding on input, we would lose info writing them to
333 # the cache.
334 cachefile.write('\n')
335 for (name, (node, hist)) in cachetags.iteritems():
336 cachefile.write("%s %s\n" % (hex(node), name))
337
309 338 cachefile.rename()
310 339 cachefile.close()
@@ -113,10 +113,12 b' patch queue now empty'
113 113 % qpush with dump of tag cache
114 114 .hg/tags.cache (pre qpush):
115 115 1
116
116 117 applying test.patch
117 118 now at: test.patch
118 119 .hg/tags.cache (post qpush):
119 120 2
121
120 122 % pop/push outside repo
121 123 popping test.patch
122 124 patch queue now empty
@@ -4,6 +4,10 b' cacheexists() {'
4 4 [ -f .hg/tags.cache ] && echo "tag cache exists" || echo "no tag cache"
5 5 }
6 6
7 # XXX need to test that the tag cache works when we strip an old head
8 # and add a new one rooted off non-tip: i.e. node and rev of tip are the
9 # same, but stuff has changed behind tip.
10
7 11 echo "% setup"
8 12 mkdir t
9 13 cd t
@@ -46,9 +46,6 b' created new head'
46 46 tip 8:c4be69a18c11
47 47 first 0:acb14030fe0a
48 48 changeset: 8:c4be69a18c11
49 .hgtags@75d9f02dfe28, line 2: cannot parse entry
50 .hgtags@75d9f02dfe28, line 4: node 'foo' is not well formed
51 .hgtags@c4be69a18c11, line 2: node 'x' is not well formed
52 49 tag: tip
53 50 parent: 3:ac5e980c4dc0
54 51 user: test
@@ -80,6 +77,8 b' bbd179dfa0a71671c253b3ae0aa1513b60d199fa'
80 77 4 0c192d7d5e6b78a714de54a2e9627952a877e25a 0c04f2a8af31de17fab7422878ee5a2dadbc943d
81 78 3 6fa450212aeb2a21ed616a54aea39a4a27894cd7 7d3b718c964ef37b89e550ebdafd5789e76ce1b0
82 79 2 7a94127795a33c10a370c93f731fd9fea0b79af6 0c04f2a8af31de17fab7422878ee5a2dadbc943d
80
81 78391a272241d70354aa14c874552cad6b51bb42 bar
83 82 % test tag removal
84 83 changeset: 5:5f6e8655b1c7
85 84 tag: tip
General Comments 0
You need to be logged in to leave comments. Login now