mercurial/revset.py
changeset 13915 8f81d6f4047f
parent 13914 27573f2ddfb9
child 13932 34f577007ffe
equal deleted inserted replaced
13914:27573f2ddfb9 13915:8f81d6f4047f
   172         return symbols[a[1]](repo, subset, b)
   172         return symbols[a[1]](repo, subset, b)
   173     raise error.ParseError(_("not a function: %s") % a[1])
   173     raise error.ParseError(_("not a function: %s") % a[1])
   174 
   174 
   175 # functions
   175 # functions
   176 
   176 
   177 def node(repo, subset, x):
   177 def adds(repo, subset, x):
   178     """``id(string)``
   178     """``adds(pattern)``
   179     Revision non-ambiguously specified by the given hex string prefix.
   179     Changesets that add a file matching pattern.
   180     """
   180     """
   181     # i18n: "id" is a keyword
   181     # i18n: "adds" is a keyword
   182     l = getargs(x, 1, 1, _("id requires one argument"))
   182     pat = getstring(x, _("adds requires a pattern"))
   183     # i18n: "id" is a keyword
   183     return checkstatus(repo, subset, pat, 1)
   184     n = getstring(l[0], _("id requires a string"))
       
   185     if len(n) == 40:
       
   186         rn = repo[n].rev()
       
   187     else:
       
   188         rn = repo.changelog.rev(repo.changelog._partialmatch(n))
       
   189     return [r for r in subset if r == rn]
       
   190 
       
   191 def rev(repo, subset, x):
       
   192     """``rev(number)``
       
   193     Revision with the given numeric identifier.
       
   194     """
       
   195     # i18n: "rev" is a keyword
       
   196     l = getargs(x, 1, 1, _("rev requires one argument"))
       
   197     try:
       
   198         # i18n: "rev" is a keyword
       
   199         l = int(getstring(l[0], _("rev requires a number")))
       
   200     except ValueError:
       
   201         # i18n: "rev" is a keyword
       
   202         raise error.ParseError(_("rev expects a number"))
       
   203     return [r for r in subset if r == l]
       
   204 
       
   205 def p1(repo, subset, x):
       
   206     """``p1([set])``
       
   207     First parent of changesets in set, or the working directory.
       
   208     """
       
   209     if x is None:
       
   210         p = repo[x].p1().rev()
       
   211         return [r for r in subset if r == p]
       
   212 
       
   213     ps = set()
       
   214     cl = repo.changelog
       
   215     for r in getset(repo, range(len(repo)), x):
       
   216         ps.add(cl.parentrevs(r)[0])
       
   217     return [r for r in subset if r in ps]
       
   218 
       
   219 def p2(repo, subset, x):
       
   220     """``p2([set])``
       
   221     Second parent of changesets in set, or the working directory.
       
   222     """
       
   223     if x is None:
       
   224         ps = repo[x].parents()
       
   225         try:
       
   226             p = ps[1].rev()
       
   227             return [r for r in subset if r == p]
       
   228         except IndexError:
       
   229             return []
       
   230 
       
   231     ps = set()
       
   232     cl = repo.changelog
       
   233     for r in getset(repo, range(len(repo)), x):
       
   234         ps.add(cl.parentrevs(r)[1])
       
   235     return [r for r in subset if r in ps]
       
   236 
       
   237 def parents(repo, subset, x):
       
   238     """``parents([set])``
       
   239     The set of all parents for all changesets in set, or the working directory.
       
   240     """
       
   241     if x is None:
       
   242         ps = tuple(p.rev() for p in repo[x].parents())
       
   243         return [r for r in subset if r in ps]
       
   244 
       
   245     ps = set()
       
   246     cl = repo.changelog
       
   247     for r in getset(repo, range(len(repo)), x):
       
   248         ps.update(cl.parentrevs(r))
       
   249     return [r for r in subset if r in ps]
       
   250 
       
   251 def maxrev(repo, subset, x):
       
   252     """``max(set)``
       
   253     Changeset with highest revision number in set.
       
   254     """
       
   255     s = getset(repo, subset, x)
       
   256     if s:
       
   257         m = max(s)
       
   258         if m in subset:
       
   259             return [m]
       
   260     return []
       
   261 
       
   262 def minrev(repo, subset, x):
       
   263     """``min(set)``
       
   264     Changeset with lowest revision number in set.
       
   265     """
       
   266     s = getset(repo, subset, x)
       
   267     if s:
       
   268         m = min(s)
       
   269         if m in subset:
       
   270             return [m]
       
   271     return []
       
   272 
       
   273 def limit(repo, subset, x):
       
   274     """``limit(set, n)``
       
   275     First n members of set.
       
   276     """
       
   277     # i18n: "limit" is a keyword
       
   278     l = getargs(x, 2, 2, _("limit requires two arguments"))
       
   279     try:
       
   280         # i18n: "limit" is a keyword
       
   281         lim = int(getstring(l[1], _("limit requires a number")))
       
   282     except ValueError:
       
   283         # i18n: "limit" is a keyword
       
   284         raise error.ParseError(_("limit expects a number"))
       
   285     return getset(repo, subset, l[0])[:lim]
       
   286 
       
   287 def children(repo, subset, x):
       
   288     """``children(set)``
       
   289     Child changesets of changesets in set.
       
   290     """
       
   291     cs = set()
       
   292     cl = repo.changelog
       
   293     s = set(getset(repo, range(len(repo)), x))
       
   294     for r in xrange(0, len(repo)):
       
   295         for p in cl.parentrevs(r):
       
   296             if p in s:
       
   297                 cs.add(r)
       
   298     return [r for r in subset if r in cs]
       
   299 
       
   300 def branch(repo, subset, x):
       
   301     """``branch(string or set)``
       
   302     All changesets belonging to the given branch or the branches of the given
       
   303     changesets.
       
   304     """
       
   305     try:
       
   306         b = getstring(x, '')
       
   307         if b in repo.branchmap():
       
   308             return [r for r in subset if repo[r].branch() == b]
       
   309     except error.ParseError:
       
   310         # not a string, but another revspec, e.g. tip()
       
   311         pass
       
   312 
       
   313     s = getset(repo, range(len(repo)), x)
       
   314     b = set()
       
   315     for r in s:
       
   316         b.add(repo[r].branch())
       
   317     s = set(s)
       
   318     return [r for r in subset if r in s or repo[r].branch() in b]
       
   319 
   184 
   320 def ancestor(repo, subset, x):
   185 def ancestor(repo, subset, x):
   321     """``ancestor(single, single)``
   186     """``ancestor(single, single)``
   322     Greatest common ancestor of the two changesets.
   187     Greatest common ancestor of the two changesets.
   323     """
   188     """
   341     if not args:
   206     if not args:
   342         return []
   207         return []
   343     s = set(repo.changelog.ancestors(*args)) | set(args)
   208     s = set(repo.changelog.ancestors(*args)) | set(args)
   344     return [r for r in subset if r in s]
   209     return [r for r in subset if r in s]
   345 
   210 
   346 def descendants(repo, subset, x):
       
   347     """``descendants(set)``
       
   348     Changesets which are descendants of changesets in set.
       
   349     """
       
   350     args = getset(repo, range(len(repo)), x)
       
   351     if not args:
       
   352         return []
       
   353     s = set(repo.changelog.descendants(*args)) | set(args)
       
   354     return [r for r in subset if r in s]
       
   355 
       
   356 def follow(repo, subset, x):
       
   357     """``follow()``
       
   358     An alias for ``::.`` (ancestors of the working copy's first parent).
       
   359     """
       
   360     # i18n: "follow" is a keyword
       
   361     getargs(x, 0, 0, _("follow takes no arguments"))
       
   362     p = repo['.'].rev()
       
   363     s = set(repo.changelog.ancestors(p)) | set([p])
       
   364     return [r for r in subset if r in s]
       
   365 
       
   366 def date(repo, subset, x):
       
   367     """``date(interval)``
       
   368     Changesets within the interval, see :hg:`help dates`.
       
   369     """
       
   370     # i18n: "date" is a keyword
       
   371     ds = getstring(x, _("date requires a string"))
       
   372     dm = util.matchdate(ds)
       
   373     return [r for r in subset if dm(repo[r].date()[0])]
       
   374 
       
   375 def keyword(repo, subset, x):
       
   376     """``keyword(string)``
       
   377     Search commit message, user name, and names of changed files for
       
   378     string.
       
   379     """
       
   380     # i18n: "keyword" is a keyword
       
   381     kw = getstring(x, _("keyword requires a string")).lower()
       
   382     l = []
       
   383     for r in subset:
       
   384         c = repo[r]
       
   385         t = " ".join(c.files() + [c.user(), c.description()])
       
   386         if kw in t.lower():
       
   387             l.append(r)
       
   388     return l
       
   389 
       
   390 def grep(repo, subset, x):
       
   391     """``grep(regex)``
       
   392     Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
       
   393     to ensure special escape characters are handled correctly.
       
   394     """
       
   395     try:
       
   396         # i18n: "grep" is a keyword
       
   397         gr = re.compile(getstring(x, _("grep requires a string")))
       
   398     except re.error, e:
       
   399         raise error.ParseError(_('invalid match pattern: %s') % e)
       
   400     l = []
       
   401     for r in subset:
       
   402         c = repo[r]
       
   403         for e in c.files() + [c.user(), c.description()]:
       
   404             if gr.search(e):
       
   405                 l.append(r)
       
   406                 break
       
   407     return l
       
   408 
       
   409 def author(repo, subset, x):
   211 def author(repo, subset, x):
   410     """``author(string)``
   212     """``author(string)``
   411     Alias for ``user(string)``.
   213     Alias for ``user(string)``.
   412     """
   214     """
   413     # i18n: "author" is a keyword
   215     # i18n: "author" is a keyword
   414     n = getstring(x, _("author requires a string")).lower()
   216     n = getstring(x, _("author requires a string")).lower()
   415     return [r for r in subset if n in repo[r].user().lower()]
   217     return [r for r in subset if n in repo[r].user().lower()]
   416 
   218 
   417 def user(repo, subset, x):
   219 def bisected(repo, subset, x):
   418     """``user(string)``
   220     """``bisected(string)``
   419     User name is string.
   221     Changesets marked in the specified bisect state (good, bad, skip).
   420     """
   222     """
   421     return author(repo, subset, x)
   223     state = getstring(x, _("bisect requires a string")).lower()
   422 
   224     if state not in ('good', 'bad', 'skip', 'unknown'):
   423 def hasfile(repo, subset, x):
   225         raise ParseError(_('invalid bisect state'))
   424     """``file(pattern)``
   226     marked = set(repo.changelog.rev(n) for n in hbisect.load_state(repo)[state])
   425     Changesets affecting files matched by pattern.
   227     return [r for r in subset if r in marked]
   426     """
   228 
   427     # i18n: "file" is a keyword
   229 def bookmark(repo, subset, x):
   428     pat = getstring(x, _("file requires a pattern"))
   230     """``bookmark([name])``
   429     m = matchmod.match(repo.root, repo.getcwd(), [pat])
   231     The named bookmark or all bookmarks.
   430     s = []
   232     """
   431     for r in subset:
   233     # i18n: "bookmark" is a keyword
   432         for f in repo[r].files():
   234     args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
   433             if m(f):
   235     if args:
   434                 s.append(r)
   236         bm = getstring(args[0],
   435                 break
   237                        # i18n: "bookmark" is a keyword
   436     return s
   238                        _('the argument to bookmark must be a string'))
   437 
   239         bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
   438 def contains(repo, subset, x):
   240         if not bmrev:
   439     """``contains(pattern)``
   241             raise util.Abort(_("bookmark '%s' does not exist") % bm)
   440     Revision contains pattern.
   242         bmrev = repo[bmrev].rev()
   441     """
   243         return [r for r in subset if r == bmrev]
   442     # i18n: "contains" is a keyword
   244     bms = set([repo[r].rev()
   443     pat = getstring(x, _("contains requires a pattern"))
   245                for r in bookmarksmod.listbookmarks(repo).values()])
   444     m = matchmod.match(repo.root, repo.getcwd(), [pat])
   246     return [r for r in subset if r in bms]
   445     s = []
   247 
   446     if m.files() == [pat]:
   248 def branch(repo, subset, x):
   447         for r in subset:
   249     """``branch(string or set)``
   448             if pat in repo[r]:
   250     All changesets belonging to the given branch or the branches of the given
   449                 s.append(r)
   251     changesets.
   450     else:
   252     """
   451         for r in subset:
   253     try:
   452             for f in repo[r].manifest():
   254         b = getstring(x, '')
   453                 if m(f):
   255         if b in repo.branchmap():
   454                     s.append(r)
   256             return [r for r in subset if repo[r].branch() == b]
   455                     break
   257     except error.ParseError:
   456     return s
   258         # not a string, but another revspec, e.g. tip()
       
   259         pass
       
   260 
       
   261     s = getset(repo, range(len(repo)), x)
       
   262     b = set()
       
   263     for r in s:
       
   264         b.add(repo[r].branch())
       
   265     s = set(s)
       
   266     return [r for r in subset if r in s or repo[r].branch() in b]
   457 
   267 
   458 def checkstatus(repo, subset, pat, field):
   268 def checkstatus(repo, subset, pat, field):
   459     m = matchmod.match(repo.root, repo.getcwd(), [pat])
   269     m = matchmod.match(repo.root, repo.getcwd(), [pat])
   460     s = []
   270     s = []
   461     fast = (m.files() == [pat])
   271     fast = (m.files() == [pat])
   479                 if m(f):
   289                 if m(f):
   480                     s.append(r)
   290                     s.append(r)
   481                     break
   291                     break
   482     return s
   292     return s
   483 
   293 
   484 def modifies(repo, subset, x):
   294 def children(repo, subset, x):
   485     """``modifies(pattern)``
   295     """``children(set)``
   486     Changesets modifying files matched by pattern.
   296     Child changesets of changesets in set.
   487     """
   297     """
   488     # i18n: "modifies" is a keyword
   298     cs = set()
   489     pat = getstring(x, _("modifies requires a pattern"))
       
   490     return checkstatus(repo, subset, pat, 0)
       
   491 
       
   492 def adds(repo, subset, x):
       
   493     """``adds(pattern)``
       
   494     Changesets that add a file matching pattern.
       
   495     """
       
   496     # i18n: "adds" is a keyword
       
   497     pat = getstring(x, _("adds requires a pattern"))
       
   498     return checkstatus(repo, subset, pat, 1)
       
   499 
       
   500 def removes(repo, subset, x):
       
   501     """``removes(pattern)``
       
   502     Changesets which remove files matching pattern.
       
   503     """
       
   504     # i18n: "removes" is a keyword
       
   505     pat = getstring(x, _("removes requires a pattern"))
       
   506     return checkstatus(repo, subset, pat, 2)
       
   507 
       
   508 def merge(repo, subset, x):
       
   509     """``merge()``
       
   510     Changeset is a merge changeset.
       
   511     """
       
   512     # i18n: "merge" is a keyword
       
   513     getargs(x, 0, 0, _("merge takes no arguments"))
       
   514     cl = repo.changelog
   299     cl = repo.changelog
   515     return [r for r in subset if cl.parentrevs(r)[1] != -1]
   300     s = set(getset(repo, range(len(repo)), x))
       
   301     for r in xrange(0, len(repo)):
       
   302         for p in cl.parentrevs(r):
       
   303             if p in s:
       
   304                 cs.add(r)
       
   305     return [r for r in subset if r in cs]
   516 
   306 
   517 def closed(repo, subset, x):
   307 def closed(repo, subset, x):
   518     """``closed()``
   308     """``closed()``
   519     Changeset is closed.
   309     Changeset is closed.
   520     """
   310     """
   521     # i18n: "closed" is a keyword
   311     # i18n: "closed" is a keyword
   522     getargs(x, 0, 0, _("closed takes no arguments"))
   312     getargs(x, 0, 0, _("closed takes no arguments"))
   523     return [r for r in subset if repo[r].extra().get('close')]
   313     return [r for r in subset if repo[r].extra().get('close')]
       
   314 
       
   315 def contains(repo, subset, x):
       
   316     """``contains(pattern)``
       
   317     Revision contains pattern.
       
   318     """
       
   319     # i18n: "contains" is a keyword
       
   320     pat = getstring(x, _("contains requires a pattern"))
       
   321     m = matchmod.match(repo.root, repo.getcwd(), [pat])
       
   322     s = []
       
   323     if m.files() == [pat]:
       
   324         for r in subset:
       
   325             if pat in repo[r]:
       
   326                 s.append(r)
       
   327     else:
       
   328         for r in subset:
       
   329             for f in repo[r].manifest():
       
   330                 if m(f):
       
   331                     s.append(r)
       
   332                     break
       
   333     return s
       
   334 
       
   335 def date(repo, subset, x):
       
   336     """``date(interval)``
       
   337     Changesets within the interval, see :hg:`help dates`.
       
   338     """
       
   339     # i18n: "date" is a keyword
       
   340     ds = getstring(x, _("date requires a string"))
       
   341     dm = util.matchdate(ds)
       
   342     return [r for r in subset if dm(repo[r].date()[0])]
       
   343 
       
   344 def descendants(repo, subset, x):
       
   345     """``descendants(set)``
       
   346     Changesets which are descendants of changesets in set.
       
   347     """
       
   348     args = getset(repo, range(len(repo)), x)
       
   349     if not args:
       
   350         return []
       
   351     s = set(repo.changelog.descendants(*args)) | set(args)
       
   352     return [r for r in subset if r in s]
       
   353 
       
   354 def follow(repo, subset, x):
       
   355     """``follow()``
       
   356     An alias for ``::.`` (ancestors of the working copy's first parent).
       
   357     """
       
   358     # i18n: "follow" is a keyword
       
   359     getargs(x, 0, 0, _("follow takes no arguments"))
       
   360     p = repo['.'].rev()
       
   361     s = set(repo.changelog.ancestors(p)) | set([p])
       
   362     return [r for r in subset if r in s]
       
   363 
       
   364 def getall(repo, subset, x):
       
   365     """``all()``
       
   366     All changesets, the same as ``0:tip``.
       
   367     """
       
   368     # i18n: "all" is a keyword
       
   369     getargs(x, 0, 0, _("all takes no arguments"))
       
   370     return subset
       
   371 
       
   372 def grep(repo, subset, x):
       
   373     """``grep(regex)``
       
   374     Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
       
   375     to ensure special escape characters are handled correctly.
       
   376     """
       
   377     try:
       
   378         # i18n: "grep" is a keyword
       
   379         gr = re.compile(getstring(x, _("grep requires a string")))
       
   380     except re.error, e:
       
   381         raise error.ParseError(_('invalid match pattern: %s') % e)
       
   382     l = []
       
   383     for r in subset:
       
   384         c = repo[r]
       
   385         for e in c.files() + [c.user(), c.description()]:
       
   386             if gr.search(e):
       
   387                 l.append(r)
       
   388                 break
       
   389     return l
       
   390 
       
   391 def hasfile(repo, subset, x):
       
   392     """``file(pattern)``
       
   393     Changesets affecting files matched by pattern.
       
   394     """
       
   395     # i18n: "file" is a keyword
       
   396     pat = getstring(x, _("file requires a pattern"))
       
   397     m = matchmod.match(repo.root, repo.getcwd(), [pat])
       
   398     s = []
       
   399     for r in subset:
       
   400         for f in repo[r].files():
       
   401             if m(f):
       
   402                 s.append(r)
       
   403                 break
       
   404     return s
   524 
   405 
   525 def head(repo, subset, x):
   406 def head(repo, subset, x):
   526     """``head()``
   407     """``head()``
   527     Changeset is a named branch head.
   408     Changeset is a named branch head.
   528     """
   409     """
   531     hs = set()
   412     hs = set()
   532     for b, ls in repo.branchmap().iteritems():
   413     for b, ls in repo.branchmap().iteritems():
   533         hs.update(repo[h].rev() for h in ls)
   414         hs.update(repo[h].rev() for h in ls)
   534     return [r for r in subset if r in hs]
   415     return [r for r in subset if r in hs]
   535 
   416 
   536 def reverse(repo, subset, x):
   417 def heads(repo, subset, x):
   537     """``reverse(set)``
   418     """``heads(set)``
   538     Reverse order of set.
   419     Members of set with no children in set.
   539     """
   420     """
   540     l = getset(repo, subset, x)
   421     s = getset(repo, subset, x)
   541     l.reverse()
   422     ps = set(parents(repo, subset, x))
       
   423     return [r for r in s if r not in ps]
       
   424 
       
   425 def keyword(repo, subset, x):
       
   426     """``keyword(string)``
       
   427     Search commit message, user name, and names of changed files for
       
   428     string.
       
   429     """
       
   430     # i18n: "keyword" is a keyword
       
   431     kw = getstring(x, _("keyword requires a string")).lower()
       
   432     l = []
       
   433     for r in subset:
       
   434         c = repo[r]
       
   435         t = " ".join(c.files() + [c.user(), c.description()])
       
   436         if kw in t.lower():
       
   437             l.append(r)
   542     return l
   438     return l
       
   439 
       
   440 def limit(repo, subset, x):
       
   441     """``limit(set, n)``
       
   442     First n members of set.
       
   443     """
       
   444     # i18n: "limit" is a keyword
       
   445     l = getargs(x, 2, 2, _("limit requires two arguments"))
       
   446     try:
       
   447         # i18n: "limit" is a keyword
       
   448         lim = int(getstring(l[1], _("limit requires a number")))
       
   449     except ValueError:
       
   450         # i18n: "limit" is a keyword
       
   451         raise error.ParseError(_("limit expects a number"))
       
   452     return getset(repo, subset, l[0])[:lim]
       
   453 
       
   454 def maxrev(repo, subset, x):
       
   455     """``max(set)``
       
   456     Changeset with highest revision number in set.
       
   457     """
       
   458     s = getset(repo, subset, x)
       
   459     if s:
       
   460         m = max(s)
       
   461         if m in subset:
       
   462             return [m]
       
   463     return []
       
   464 
       
   465 def merge(repo, subset, x):
       
   466     """``merge()``
       
   467     Changeset is a merge changeset.
       
   468     """
       
   469     # i18n: "merge" is a keyword
       
   470     getargs(x, 0, 0, _("merge takes no arguments"))
       
   471     cl = repo.changelog
       
   472     return [r for r in subset if cl.parentrevs(r)[1] != -1]
       
   473 
       
   474 def minrev(repo, subset, x):
       
   475     """``min(set)``
       
   476     Changeset with lowest revision number in set.
       
   477     """
       
   478     s = getset(repo, subset, x)
       
   479     if s:
       
   480         m = min(s)
       
   481         if m in subset:
       
   482             return [m]
       
   483     return []
       
   484 
       
   485 def modifies(repo, subset, x):
       
   486     """``modifies(pattern)``
       
   487     Changesets modifying files matched by pattern.
       
   488     """
       
   489     # i18n: "modifies" is a keyword
       
   490     pat = getstring(x, _("modifies requires a pattern"))
       
   491     return checkstatus(repo, subset, pat, 0)
       
   492 
       
   493 def node(repo, subset, x):
       
   494     """``id(string)``
       
   495     Revision non-ambiguously specified by the given hex string prefix.
       
   496     """
       
   497     # i18n: "id" is a keyword
       
   498     l = getargs(x, 1, 1, _("id requires one argument"))
       
   499     # i18n: "id" is a keyword
       
   500     n = getstring(l[0], _("id requires a string"))
       
   501     if len(n) == 40:
       
   502         rn = repo[n].rev()
       
   503     else:
       
   504         rn = repo.changelog.rev(repo.changelog._partialmatch(n))
       
   505     return [r for r in subset if r == rn]
       
   506 
       
   507 def outgoing(repo, subset, x):
       
   508     """``outgoing([path])``
       
   509     Changesets not found in the specified destination repository, or the
       
   510     default push location.
       
   511     """
       
   512     import hg # avoid start-up nasties
       
   513     # i18n: "outgoing" is a keyword
       
   514     l = getargs(x, 0, 1, _("outgoing requires a repository path"))
       
   515     # i18n: "outgoing" is a keyword
       
   516     dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
       
   517     dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
       
   518     dest, branches = hg.parseurl(dest)
       
   519     revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
       
   520     if revs:
       
   521         revs = [repo.lookup(rev) for rev in revs]
       
   522     other = hg.repository(hg.remoteui(repo, {}), dest)
       
   523     repo.ui.pushbuffer()
       
   524     o = discovery.findoutgoing(repo, other)
       
   525     repo.ui.popbuffer()
       
   526     cl = repo.changelog
       
   527     o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
       
   528     return [r for r in subset if r in o]
       
   529 
       
   530 def p1(repo, subset, x):
       
   531     """``p1([set])``
       
   532     First parent of changesets in set, or the working directory.
       
   533     """
       
   534     if x is None:
       
   535         p = repo[x].p1().rev()
       
   536         return [r for r in subset if r == p]
       
   537 
       
   538     ps = set()
       
   539     cl = repo.changelog
       
   540     for r in getset(repo, range(len(repo)), x):
       
   541         ps.add(cl.parentrevs(r)[0])
       
   542     return [r for r in subset if r in ps]
       
   543 
       
   544 def p2(repo, subset, x):
       
   545     """``p2([set])``
       
   546     Second parent of changesets in set, or the working directory.
       
   547     """
       
   548     if x is None:
       
   549         ps = repo[x].parents()
       
   550         try:
       
   551             p = ps[1].rev()
       
   552             return [r for r in subset if r == p]
       
   553         except IndexError:
       
   554             return []
       
   555 
       
   556     ps = set()
       
   557     cl = repo.changelog
       
   558     for r in getset(repo, range(len(repo)), x):
       
   559         ps.add(cl.parentrevs(r)[1])
       
   560     return [r for r in subset if r in ps]
       
   561 
       
   562 def parents(repo, subset, x):
       
   563     """``parents([set])``
       
   564     The set of all parents for all changesets in set, or the working directory.
       
   565     """
       
   566     if x is None:
       
   567         ps = tuple(p.rev() for p in repo[x].parents())
       
   568         return [r for r in subset if r in ps]
       
   569 
       
   570     ps = set()
       
   571     cl = repo.changelog
       
   572     for r in getset(repo, range(len(repo)), x):
       
   573         ps.update(cl.parentrevs(r))
       
   574     return [r for r in subset if r in ps]
   543 
   575 
   544 def present(repo, subset, x):
   576 def present(repo, subset, x):
   545     """``present(set)``
   577     """``present(set)``
   546     An empty set, if any revision in set isn't found; otherwise,
   578     An empty set, if any revision in set isn't found; otherwise,
   547     all revisions in set.
   579     all revisions in set.
   548     """
   580     """
   549     try:
   581     try:
   550         return getset(repo, subset, x)
   582         return getset(repo, subset, x)
   551     except error.RepoLookupError:
   583     except error.RepoLookupError:
   552         return []
   584         return []
       
   585 
       
   586 def removes(repo, subset, x):
       
   587     """``removes(pattern)``
       
   588     Changesets which remove files matching pattern.
       
   589     """
       
   590     # i18n: "removes" is a keyword
       
   591     pat = getstring(x, _("removes requires a pattern"))
       
   592     return checkstatus(repo, subset, pat, 2)
       
   593 
       
   594 def rev(repo, subset, x):
       
   595     """``rev(number)``
       
   596     Revision with the given numeric identifier.
       
   597     """
       
   598     # i18n: "rev" is a keyword
       
   599     l = getargs(x, 1, 1, _("rev requires one argument"))
       
   600     try:
       
   601         # i18n: "rev" is a keyword
       
   602         l = int(getstring(l[0], _("rev requires a number")))
       
   603     except ValueError:
       
   604         # i18n: "rev" is a keyword
       
   605         raise error.ParseError(_("rev expects a number"))
       
   606     return [r for r in subset if r == l]
       
   607 
       
   608 def reverse(repo, subset, x):
       
   609     """``reverse(set)``
       
   610     Reverse order of set.
       
   611     """
       
   612     l = getset(repo, subset, x)
       
   613     l.reverse()
       
   614     return l
       
   615 
       
   616 def roots(repo, subset, x):
       
   617     """``roots(set)``
       
   618     Changesets with no parent changeset in set.
       
   619     """
       
   620     s = getset(repo, subset, x)
       
   621     cs = set(children(repo, subset, x))
       
   622     return [r for r in s if r not in cs]
   553 
   623 
   554 def sort(repo, subset, x):
   624 def sort(repo, subset, x):
   555     """``sort(set[, [-]key...])``
   625     """``sort(set[, [-]key...])``
   556     Sort set by keys. The default sort order is ascending, specify a key
   626     Sort set by keys. The default sort order is ascending, specify a key
   557     as ``-key`` to sort in descending order.
   627     as ``-key`` to sort in descending order.
   604         e.append(r)
   674         e.append(r)
   605         l.append(e)
   675         l.append(e)
   606     l.sort()
   676     l.sort()
   607     return [e[-1] for e in l]
   677     return [e[-1] for e in l]
   608 
   678 
   609 def getall(repo, subset, x):
       
   610     """``all()``
       
   611     All changesets, the same as ``0:tip``.
       
   612     """
       
   613     # i18n: "all" is a keyword
       
   614     getargs(x, 0, 0, _("all takes no arguments"))
       
   615     return subset
       
   616 
       
   617 def heads(repo, subset, x):
       
   618     """``heads(set)``
       
   619     Members of set with no children in set.
       
   620     """
       
   621     s = getset(repo, subset, x)
       
   622     ps = set(parents(repo, subset, x))
       
   623     return [r for r in s if r not in ps]
       
   624 
       
   625 def roots(repo, subset, x):
       
   626     """``roots(set)``
       
   627     Changesets with no parent changeset in set.
       
   628     """
       
   629     s = getset(repo, subset, x)
       
   630     cs = set(children(repo, subset, x))
       
   631     return [r for r in s if r not in cs]
       
   632 
       
   633 def outgoing(repo, subset, x):
       
   634     """``outgoing([path])``
       
   635     Changesets not found in the specified destination repository, or the
       
   636     default push location.
       
   637     """
       
   638     import hg # avoid start-up nasties
       
   639     # i18n: "outgoing" is a keyword
       
   640     l = getargs(x, 0, 1, _("outgoing requires a repository path"))
       
   641     # i18n: "outgoing" is a keyword
       
   642     dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
       
   643     dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
       
   644     dest, branches = hg.parseurl(dest)
       
   645     revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
       
   646     if revs:
       
   647         revs = [repo.lookup(rev) for rev in revs]
       
   648     other = hg.repository(hg.remoteui(repo, {}), dest)
       
   649     repo.ui.pushbuffer()
       
   650     o = discovery.findoutgoing(repo, other)
       
   651     repo.ui.popbuffer()
       
   652     cl = repo.changelog
       
   653     o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
       
   654     return [r for r in subset if r in o]
       
   655 
       
   656 def tag(repo, subset, x):
   679 def tag(repo, subset, x):
   657     """``tag(name)``
   680     """``tag(name)``
   658     The specified tag by name, or all tagged revisions if no name is given.
   681     The specified tag by name, or all tagged revisions if no name is given.
   659     """
   682     """
   660     # i18n: "tag" is a keyword
   683     # i18n: "tag" is a keyword
   672     return [r for r in subset if r in s]
   695     return [r for r in subset if r in s]
   673 
   696 
   674 def tagged(repo, subset, x):
   697 def tagged(repo, subset, x):
   675     return tag(repo, subset, x)
   698     return tag(repo, subset, x)
   676 
   699 
   677 def bookmark(repo, subset, x):
   700 def user(repo, subset, x):
   678     """``bookmark([name])``
   701     """``user(string)``
   679     The named bookmark or all bookmarks.
   702     User name is string.
   680     """
   703     """
   681     # i18n: "bookmark" is a keyword
   704     return author(repo, subset, x)
   682     args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
       
   683     if args:
       
   684         bm = getstring(args[0],
       
   685                        # i18n: "bookmark" is a keyword
       
   686                        _('the argument to bookmark must be a string'))
       
   687         bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
       
   688         if not bmrev:
       
   689             raise util.Abort(_("bookmark '%s' does not exist") % bm)
       
   690         bmrev = repo[bmrev].rev()
       
   691         return [r for r in subset if r == bmrev]
       
   692     bms = set([repo[r].rev()
       
   693                for r in bookmarksmod.listbookmarks(repo).values()])
       
   694     return [r for r in subset if r in bms]
       
   695 
       
   696 def bisected(repo, subset, x):
       
   697     """``bisected(string)``
       
   698     Changesets marked in the specified bisect state (good, bad, skip).
       
   699     """
       
   700     state = getstring(x, _("bisect requires a string")).lower()
       
   701     if state not in ('good', 'bad', 'skip', 'unknown'):
       
   702         raise ParseError(_('invalid bisect state'))
       
   703     marked = set(repo.changelog.rev(n) for n in hbisect.load_state(repo)[state])
       
   704     return [r for r in subset if r in marked]
       
   705 
   705 
   706 symbols = {
   706 symbols = {
   707     "adds": adds,
   707     "adds": adds,
   708     "all": getall,
   708     "all": getall,
   709     "ancestor": ancestor,
   709     "ancestor": ancestor,