mercurial/localrepo.py
changeset 9149 abb7d4d43a5f
parent 9148 b7837f0ed9fe
child 9150 09a1ee498756
equal deleted inserted replaced
9148:b7837f0ed9fe 9149:abb7d4d43a5f
    11 import changelog, dirstate, filelog, manifest, context
    11 import changelog, dirstate, filelog, manifest, context
    12 import lock, transaction, store, encoding
    12 import lock, transaction, store, encoding
    13 import util, extensions, hook, error
    13 import util, extensions, hook, error
    14 import match as match_
    14 import match as match_
    15 import merge as merge_
    15 import merge as merge_
       
    16 import tags as tags_
    16 from lock import release
    17 from lock import release
    17 import weakref, stat, errno, os, time, inspect
    18 import weakref, stat, errno, os, time, inspect
    18 propertycache = util.propertycache
    19 propertycache = util.propertycache
    19 
    20 
    20 class localrepository(repo.repository):
    21 class localrepository(repo.repository):
   256         # mq and bookmarks add tags, but do not set the tagtype at all.
   257         # mq and bookmarks add tags, but do not set the tagtype at all.
   257         # Should each extension invent its own tag type?  Should there
   258         # Should each extension invent its own tag type?  Should there
   258         # be one tagtype for all such "virtual" tags?  Or is the status
   259         # be one tagtype for all such "virtual" tags?  Or is the status
   259         # quo fine?
   260         # quo fine?
   260 
   261 
   261         def readtags(lines, fn):
       
   262             '''Read tag definitions from a file (or any source of
       
   263             lines).  Return a mapping from tag name to (node, hist):
       
   264             node is the node id from the last line read for that name,
       
   265             and hist is the list of node ids previously associated with
       
   266             it (in file order).  All node ids are binary, not hex.'''
       
   267 
       
   268             filetags = {}               # map tag name to (node, hist)
       
   269             count = 0
       
   270 
       
   271             def warn(msg):
       
   272                 self.ui.warn(_("%s, line %s: %s\n") % (fn, count, msg))
       
   273 
       
   274             for line in lines:
       
   275                 count += 1
       
   276                 if not line:
       
   277                     continue
       
   278                 try:
       
   279                     (nodehex, name) = line.split(" ", 1)
       
   280                 except ValueError:
       
   281                     warn(_("cannot parse entry"))
       
   282                     continue
       
   283                 name = encoding.tolocal(name.strip()) # stored in UTF-8
       
   284                 try:
       
   285                     nodebin = bin(nodehex)
       
   286                 except TypeError:
       
   287                     warn(_("node '%s' is not well formed") % nodehex)
       
   288                     continue
       
   289                 if nodebin not in self.changelog.nodemap:
       
   290                     # silently ignore as pull -r might cause this
       
   291                     continue
       
   292 
       
   293                 # update filetags
       
   294                 hist = []
       
   295                 if name in filetags:
       
   296                     n, hist = filetags[name]
       
   297                     hist.append(n)
       
   298                 filetags[name] = (nodebin, hist)
       
   299             return filetags
       
   300 
       
   301         alltags = {}                    # map tag name to (node, hist)
   262         alltags = {}                    # map tag name to (node, hist)
   302         tagtypes = {}
   263         tagtypes = {}
   303 
   264 
   304         def updatetags(filetags, tagtype):
   265         tags_.findglobaltags(self.ui, self, alltags, tagtypes)
   305             '''Incorporate the tag info read from one file into the two
   266         tags_.readlocaltags(self.ui, self, alltags, tagtypes)
   306             dictionaries, alltags and tagtypes, that contain all tag
       
   307             info (global across all heads plus local).'''
       
   308 
       
   309             for name, nodehist in filetags.iteritems():
       
   310                 if name not in alltags:
       
   311                     alltags[name] = nodehist
       
   312                     tagtypes[name] = tagtype
       
   313                     continue
       
   314 
       
   315                 # we prefer alltags[name] if:
       
   316                 #  it supercedes us OR
       
   317                 #  mutual supercedes and it has a higher rank
       
   318                 # otherwise we win because we're tip-most
       
   319                 anode, ahist = nodehist
       
   320                 bnode, bhist = alltags[name]
       
   321                 if (bnode != anode and anode in bhist and
       
   322                     (bnode not in ahist or len(bhist) > len(ahist))):
       
   323                     anode = bnode
       
   324                 ahist.extend([n for n in bhist if n not in ahist])
       
   325                 alltags[name] = anode, ahist
       
   326                 tagtypes[name] = tagtype
       
   327 
       
   328         seen = set()
       
   329         fctx = None
       
   330         ctxs = []                       # list of filectx
       
   331         for node in self.heads():
       
   332             try:
       
   333                 fnode = self[node].filenode('.hgtags')
       
   334             except error.LookupError:
       
   335                 continue
       
   336             if fnode not in seen:
       
   337                 seen.add(fnode)
       
   338                 if not fctx:
       
   339                     fctx = self.filectx('.hgtags', fileid=fnode)
       
   340                 else:
       
   341                     fctx = fctx.filectx(fnode)
       
   342                 ctxs.append(fctx)
       
   343 
       
   344         # read the tags file from each head, ending with the tip
       
   345         for fctx in reversed(ctxs):
       
   346             filetags = readtags(fctx.data().splitlines(), fctx)
       
   347             updatetags(filetags, "global")
       
   348 
       
   349         try:
       
   350             data = encoding.fromlocal(self.opener("localtags").read())
       
   351             # localtags are stored in the local character set
       
   352             # while the internal tag table is stored in UTF-8
       
   353             filetags = readtags(data.splitlines(), "localtags")
       
   354             updatetags(filetags, "local")
       
   355         except IOError:
       
   356             pass
       
   357 
   267 
   358         tags = {}
   268         tags = {}
   359         for (name, (node, hist)) in alltags.iteritems():
   269         for (name, (node, hist)) in alltags.iteritems():
   360             if node != nullid:
   270             if node != nullid:
   361                 tags[name] = node
   271                 tags[name] = node