mercurial/revset.py
changeset 11383 de544774ebea
parent 11349 cf8a9154a362
child 11385 e5a2134c083b
equal deleted inserted replaced
11382:2f09b13e914d 11383:de544774ebea
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 import re
     8 import re
     9 import parser, util, error, discovery
     9 import parser, util, error, discovery
    10 import match as _match
    10 import match as _match
       
    11 from i18n import _
    11 
    12 
    12 elements = {
    13 elements = {
    13     "(": (20, ("group", 1, ")"), ("func", 1, ")")),
    14     "(": (20, ("group", 1, ")"), ("func", 1, ")")),
    14     "-": (19, ("negate", 19), ("minus", 19)),
    15     "-": (19, ("negate", 19), ("minus", 19)),
    15     "::": (17, ("dagrangepre", 17), ("dagrange", 17),
    16     "::": (17, ("dagrangepre", 17), ("dagrange", 17),
    58                 if d == c:
    59                 if d == c:
    59                     yield ('string', program[s:pos].decode('string-escape'), s)
    60                     yield ('string', program[s:pos].decode('string-escape'), s)
    60                     break
    61                     break
    61                 pos += 1
    62                 pos += 1
    62             else:
    63             else:
    63                 raise error.ParseError("unterminated string", s)
    64                 raise error.ParseError(_("unterminated string"), s)
    64         elif c.isalnum() or c in '.': # gather up a symbol/keyword
    65         elif c.isalnum() or c in '.': # gather up a symbol/keyword
    65             s = pos
    66             s = pos
    66             pos += 1
    67             pos += 1
    67             while pos < l: # find end of symbol
    68             while pos < l: # find end of symbol
    68                 d = program[pos]
    69                 d = program[pos]
    77                 yield (sym, None, s)
    78                 yield (sym, None, s)
    78             else:
    79             else:
    79                 yield ('symbol', sym, s)
    80                 yield ('symbol', sym, s)
    80             pos -= 1
    81             pos -= 1
    81         else:
    82         else:
    82             raise error.ParseError("syntax error", pos)
    83             raise error.ParseError(_("syntax error"), pos)
    83         pos += 1
    84         pos += 1
    84     yield ('end', None, pos)
    85     yield ('end', None, pos)
    85 
    86 
    86 # helpers
    87 # helpers
    87 
    88 
   103         raise error.ParseError(err)
   104         raise error.ParseError(err)
   104     return l
   105     return l
   105 
   106 
   106 def getset(repo, subset, x):
   107 def getset(repo, subset, x):
   107     if not x:
   108     if not x:
   108         raise error.ParseError("missing argument")
   109         raise error.ParseError(_("missing argument"))
   109     return methods[x[0]](repo, subset, *x[1:])
   110     return methods[x[0]](repo, subset, *x[1:])
   110 
   111 
   111 # operator methods
   112 # operator methods
   112 
   113 
   113 def negate(repo, subset, x):
   114 def negate(repo, subset, x):
   114     return getset(repo, subset,
   115     return getset(repo, subset,
   115                   ('string', '-' + getstring(x, "can't negate that")))
   116                   ('string', '-' + getstring(x, _("can't negate that"))))
   116 
   117 
   117 def stringset(repo, subset, x):
   118 def stringset(repo, subset, x):
   118     x = repo[x].rev()
   119     x = repo[x].rev()
   119     if x == -1 and len(subset) == len(repo):
   120     if x == -1 and len(subset) == len(repo):
   120         return [-1]
   121         return [-1]
   122         return [x]
   123         return [x]
   123     return []
   124     return []
   124 
   125 
   125 def symbolset(repo, subset, x):
   126 def symbolset(repo, subset, x):
   126     if x in symbols:
   127     if x in symbols:
   127         raise error.ParseError("can't use %s here" % x)
   128         raise error.ParseError(_("can't use %s here") % x)
   128     return stringset(repo, subset, x)
   129     return stringset(repo, subset, x)
   129 
   130 
   130 def rangeset(repo, subset, x, y):
   131 def rangeset(repo, subset, x, y):
   131     m = getset(repo, subset, x)[0]
   132     m = getset(repo, subset, x)[0]
   132     n = getset(repo, subset, y)[-1]
   133     n = getset(repo, subset, y)[-1]
   145 def notset(repo, subset, x):
   146 def notset(repo, subset, x):
   146     s = set(getset(repo, subset, x))
   147     s = set(getset(repo, subset, x))
   147     return [r for r in subset if r not in s]
   148     return [r for r in subset if r not in s]
   148 
   149 
   149 def listset(repo, subset, a, b):
   150 def listset(repo, subset, a, b):
   150     raise error.ParseError("can't use a list in this context")
   151     raise error.ParseError(_("can't use a list in this context"))
   151 
   152 
   152 def func(repo, subset, a, b):
   153 def func(repo, subset, a, b):
   153     if a[0] == 'symbol' and a[1] in symbols:
   154     if a[0] == 'symbol' and a[1] in symbols:
   154         return symbols[a[1]](repo, subset, b)
   155         return symbols[a[1]](repo, subset, b)
   155     raise error.ParseError("not a function: %s" % a[1])
   156     raise error.ParseError(_("not a function: %s") % a[1])
   156 
   157 
   157 # functions
   158 # functions
   158 
   159 
   159 def p1(repo, subset, x):
   160 def p1(repo, subset, x):
   160     ps = set()
   161     ps = set()
   184         if m in subset:
   185         if m in subset:
   185             return [m]
   186             return [m]
   186     return []
   187     return []
   187 
   188 
   188 def limit(repo, subset, x):
   189 def limit(repo, subset, x):
   189     l = getargs(x, 2, 2, "limit wants two args")
   190     l = getargs(x, 2, 2, _("limit wants two arguments"))
   190     try:
   191     try:
   191         lim = int(getstring(l[1], "limit wants a number"))
   192         lim = int(getstring(l[1], _("limit wants a number")))
   192     except ValueError:
   193     except ValueError:
   193         raise error.ParseError("limit expects a number")
   194         raise error.ParseError(_("limit expects a number"))
   194     return getset(repo, subset, l[0])[:lim]
   195     return getset(repo, subset, l[0])[:lim]
   195 
   196 
   196 def children(repo, subset, x):
   197 def children(repo, subset, x):
   197     cs = set()
   198     cs = set()
   198     cl = repo.changelog
   199     cl = repo.changelog
   210         b.add(repo[r].branch())
   211         b.add(repo[r].branch())
   211     s = set(s)
   212     s = set(s)
   212     return [r for r in subset if r in s or repo[r].branch() in b]
   213     return [r for r in subset if r in s or repo[r].branch() in b]
   213 
   214 
   214 def ancestor(repo, subset, x):
   215 def ancestor(repo, subset, x):
   215     l = getargs(x, 2, 2, "ancestor wants two args")
   216     l = getargs(x, 2, 2, _("ancestor wants two arguments"))
   216     a = getset(repo, subset, l[0])
   217     a = getset(repo, subset, l[0])
   217     b = getset(repo, subset, l[1])
   218     b = getset(repo, subset, l[1])
   218     if len(a) > 1 or len(b) > 1:
   219     if len(a) > 1 or len(b) > 1:
   219         raise error.ParseError("ancestor args must be single revisions")
   220         raise error.ParseError(_("ancestor arguments must be single revisions"))
   220     return [repo[a[0]].ancestor(repo[b[0]]).rev()]
   221     return [repo[a[0]].ancestor(repo[b[0]]).rev()]
   221 
   222 
   222 def ancestors(repo, subset, x):
   223 def ancestors(repo, subset, x):
   223     args = getset(repo, range(len(repo)), x)
   224     args = getset(repo, range(len(repo)), x)
   224     s = set(repo.changelog.ancestors(*args)) | set(args)
   225     s = set(repo.changelog.ancestors(*args)) | set(args)
   228     args = getset(repo, range(len(repo)), x)
   229     args = getset(repo, range(len(repo)), x)
   229     s = set(repo.changelog.descendants(*args)) | set(args)
   230     s = set(repo.changelog.descendants(*args)) | set(args)
   230     return [r for r in subset if r in s]
   231     return [r for r in subset if r in s]
   231 
   232 
   232 def follow(repo, subset, x):
   233 def follow(repo, subset, x):
   233     getargs(x, 0, 0, "follow takes no arguments")
   234     getargs(x, 0, 0, _("follow takes no arguments"))
   234     p = repo['.'].rev()
   235     p = repo['.'].rev()
   235     s = set(repo.changelog.ancestors(p)) | set([p])
   236     s = set(repo.changelog.ancestors(p)) | set([p])
   236     return [r for r in subset if r in s]
   237     return [r for r in subset if r in s]
   237 
   238 
   238 def date(repo, subset, x):
   239 def date(repo, subset, x):
   239     ds = getstring(x, 'date wants a string')
   240     ds = getstring(x, _("date wants a string"))
   240     dm = util.matchdate(ds)
   241     dm = util.matchdate(ds)
   241     return [r for r in subset if dm(repo[r].date()[0])]
   242     return [r for r in subset if dm(repo[r].date()[0])]
   242 
   243 
   243 def keyword(repo, subset, x):
   244 def keyword(repo, subset, x):
   244     kw = getstring(x, "keyword wants a string").lower()
   245     kw = getstring(x, _("keyword wants a string")).lower()
   245     l = []
   246     l = []
   246     for r in subset:
   247     for r in subset:
   247         c = repo[r]
   248         c = repo[r]
   248         t = " ".join(c.files() + [c.user(), c.description()])
   249         t = " ".join(c.files() + [c.user(), c.description()])
   249         if kw in t.lower():
   250         if kw in t.lower():
   250             l.append(r)
   251             l.append(r)
   251     return l
   252     return l
   252 
   253 
   253 def grep(repo, subset, x):
   254 def grep(repo, subset, x):
   254     gr = re.compile(getstring(x, "grep wants a string"))
   255     gr = re.compile(getstring(x, _("grep wants a string")))
   255     l = []
   256     l = []
   256     for r in subset:
   257     for r in subset:
   257         c = repo[r]
   258         c = repo[r]
   258         for e in c.files() + [c.user(), c.description()]:
   259         for e in c.files() + [c.user(), c.description()]:
   259             if gr.search(e):
   260             if gr.search(e):
   260                 l.append(r)
   261                 l.append(r)
   261                 continue
   262                 continue
   262     return l
   263     return l
   263 
   264 
   264 def author(repo, subset, x):
   265 def author(repo, subset, x):
   265     n = getstring(x, "author wants a string").lower()
   266     n = getstring(x, _("author wants a string")).lower()
   266     return [r for r in subset if n in repo[r].user().lower()]
   267     return [r for r in subset if n in repo[r].user().lower()]
   267 
   268 
   268 def hasfile(repo, subset, x):
   269 def hasfile(repo, subset, x):
   269     pat = getstring(x, "file wants a pattern")
   270     pat = getstring(x, _("file wants a pattern"))
   270     m = _match.match(repo.root, repo.getcwd(), [pat])
   271     m = _match.match(repo.root, repo.getcwd(), [pat])
   271     s = []
   272     s = []
   272     for r in subset:
   273     for r in subset:
   273         for f in repo[r].files():
   274         for f in repo[r].files():
   274             if m(f):
   275             if m(f):
   275                 s.append(r)
   276                 s.append(r)
   276                 continue
   277                 continue
   277     return s
   278     return s
   278 
   279 
   279 def contains(repo, subset, x):
   280 def contains(repo, subset, x):
   280     pat = getstring(x, "file wants a pattern")
   281     pat = getstring(x, _("file wants a pattern"))
   281     m = _match.match(repo.root, repo.getcwd(), [pat])
   282     m = _match.match(repo.root, repo.getcwd(), [pat])
   282     s = []
   283     s = []
   283     if m.files() == [pat]:
   284     if m.files() == [pat]:
   284         for r in subset:
   285         for r in subset:
   285             if pat in repo[r]:
   286             if pat in repo[r]:
   319                     s.append(r)
   320                     s.append(r)
   320                     continue
   321                     continue
   321     return s
   322     return s
   322 
   323 
   323 def modifies(repo, subset, x):
   324 def modifies(repo, subset, x):
   324     pat = getstring(x, "modifies wants a pattern")
   325     pat = getstring(x, _("modifies wants a pattern"))
   325     return checkstatus(repo, subset, pat, 0)
   326     return checkstatus(repo, subset, pat, 0)
   326 
   327 
   327 def adds(repo, subset, x):
   328 def adds(repo, subset, x):
   328     pat = getstring(x, "adds wants a pattern")
   329     pat = getstring(x, _("adds wants a pattern"))
   329     return checkstatus(repo, subset, pat, 1)
   330     return checkstatus(repo, subset, pat, 1)
   330 
   331 
   331 def removes(repo, subset, x):
   332 def removes(repo, subset, x):
   332     pat = getstring(x, "removes wants a pattern")
   333     pat = getstring(x, _("removes wants a pattern"))
   333     return checkstatus(repo, subset, pat, 2)
   334     return checkstatus(repo, subset, pat, 2)
   334 
   335 
   335 def merge(repo, subset, x):
   336 def merge(repo, subset, x):
   336     getargs(x, 0, 0, "merge takes no arguments")
   337     getargs(x, 0, 0, _("merge takes no arguments"))
   337     cl = repo.changelog
   338     cl = repo.changelog
   338     return [r for r in subset if cl.parentrevs(r)[1] != -1]
   339     return [r for r in subset if cl.parentrevs(r)[1] != -1]
   339 
   340 
   340 def closed(repo, subset, x):
   341 def closed(repo, subset, x):
   341     getargs(x, 0, 0, "closed takes no arguments")
   342     getargs(x, 0, 0, _("closed takes no arguments"))
   342     return [r for r in subset if repo[r].extra().get('close')]
   343     return [r for r in subset if repo[r].extra().get('close')]
   343 
   344 
   344 def head(repo, subset, x):
   345 def head(repo, subset, x):
   345     getargs(x, 0, 0, "head takes no arguments")
   346     getargs(x, 0, 0, _("head takes no arguments"))
   346     hs = set()
   347     hs = set()
   347     for b, ls in repo.branchmap().iteritems():
   348     for b, ls in repo.branchmap().iteritems():
   348         hs.update(repo[h].rev() for h in ls)
   349         hs.update(repo[h].rev() for h in ls)
   349     return [r for r in subset if r in hs]
   350     return [r for r in subset if r in hs]
   350 
   351 
   352     l = getset(repo, subset, x)
   353     l = getset(repo, subset, x)
   353     l.reverse()
   354     l.reverse()
   354     return l
   355     return l
   355 
   356 
   356 def sort(repo, subset, x):
   357 def sort(repo, subset, x):
   357     l = getargs(x, 1, 2, "sort wants one or two arguments")
   358     l = getargs(x, 1, 2, _("sort wants one or two arguments"))
   358     keys = "rev"
   359     keys = "rev"
   359     if len(l) == 2:
   360     if len(l) == 2:
   360         keys = getstring(l[1], "sort spec must be a string")
   361         keys = getstring(l[1], _("sort spec must be a string"))
   361 
   362 
   362     s = l[0]
   363     s = l[0]
   363     keys = keys.split()
   364     keys = keys.split()
   364     l = []
   365     l = []
   365     def invert(s):
   366     def invert(s):
   387             elif k == 'date':
   388             elif k == 'date':
   388                 e.append(c.date()[0])
   389                 e.append(c.date()[0])
   389             elif k == '-date':
   390             elif k == '-date':
   390                 e.append(-c.date()[0])
   391                 e.append(-c.date()[0])
   391             else:
   392             else:
   392                 raise error.ParseError("unknown sort key %r" % k)
   393                 raise error.ParseError(_("unknown sort key %r") % k)
   393         e.append(r)
   394         e.append(r)
   394         l.append(e)
   395         l.append(e)
   395     l.sort()
   396     l.sort()
   396     return [e[-1] for e in l]
   397     return [e[-1] for e in l]
   397 
   398 
   398 def getall(repo, subset, x):
   399 def getall(repo, subset, x):
   399     getargs(x, 0, 0, "all takes no arguments")
   400     getargs(x, 0, 0, _("all takes no arguments"))
   400     return subset
   401     return subset
   401 
   402 
   402 def heads(repo, subset, x):
   403 def heads(repo, subset, x):
   403     s = getset(repo, subset, x)
   404     s = getset(repo, subset, x)
   404     ps = set(parents(repo, subset, x))
   405     ps = set(parents(repo, subset, x))
   409     cs = set(children(repo, subset, x))
   410     cs = set(children(repo, subset, x))
   410     return [r for r in s if r not in cs]
   411     return [r for r in s if r not in cs]
   411 
   412 
   412 def outgoing(repo, subset, x):
   413 def outgoing(repo, subset, x):
   413     import hg # avoid start-up nasties
   414     import hg # avoid start-up nasties
   414     l = getargs(x, 0, 1, "outgoing wants a repo path")
   415     l = getargs(x, 0, 1, _("outgoing wants a repository path"))
   415     dest = l[1:] or ''
   416     dest = l[1:] or ''
   416     dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
   417     dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
   417     dest, branches = hg.parseurl(dest)
   418     dest, branches = hg.parseurl(dest)
   418     other = hg.repository(hg.remoteui(repo, {}), dest)
   419     other = hg.repository(hg.remoteui(repo, {}), dest)
   419     repo.ui.pushbuffer()
   420     repo.ui.pushbuffer()
   423     o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, None)[0]])
   424     o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, None)[0]])
   424     print 'out', dest, o
   425     print 'out', dest, o
   425     return [r for r in subset if r in o]
   426     return [r for r in subset if r in o]
   426 
   427 
   427 def tagged(repo, subset, x):
   428 def tagged(repo, subset, x):
   428     getargs(x, 0, 0, "tagged takes no arguments")
   429     getargs(x, 0, 0, _("tagged takes no arguments"))
   429     cl = repo.changelog
   430     cl = repo.changelog
   430     s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
   431     s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
   431     return [r for r in subset if r in s]
   432     return [r for r in subset if r in s]
   432 
   433 
   433 symbols = {
   434 symbols = {
   521     elif op in 'range list':
   522     elif op in 'range list':
   522         wa, ta = optimize(x[1], small)
   523         wa, ta = optimize(x[1], small)
   523         wb, tb = optimize(x[2], small)
   524         wb, tb = optimize(x[2], small)
   524         return wa + wb, (op, ta, tb)
   525         return wa + wb, (op, ta, tb)
   525     elif op == 'func':
   526     elif op == 'func':
   526         f = getstring(x[1], "not a symbol")
   527         f = getstring(x[1], _("not a symbol"))
   527         wa, ta = optimize(x[2], small)
   528         wa, ta = optimize(x[2], small)
   528         if f in "grep date user author keyword branch file":
   529         if f in "grep date user author keyword branch file":
   529             w = 10 # slow
   530             w = 10 # slow
   530         elif f in "modifies adds removes outgoing":
   531         elif f in "modifies adds removes outgoing":
   531             w = 30 # slower
   532             w = 30 # slower