def revset_svnrev(repo, subset, x): '''``svnrev(number)`` Select changesets that originate in the given Subversion revision. ''' args = revset.getargs(x, 1, 1, "svnrev takes one argument") rev = revset.getstring(args[0], "the argument to svnrev() must be a number") try: revnum = int(rev) except ValueError: raise error.ParseError("the argument to svnrev() must be a number") rev = rev + ' ' revs = [] meta = repo.svnmeta(skiperrorcheck=True) try: for l in maps.RevMap.readmapfile(meta.revmap_file, missingok=False): if l.startswith(rev): n = l.split(' ', 2)[1] r = repo[node.bin(n)].rev() if r in subset: revs.append(r) return revs except IOError, err: if err.errno != errno.ENOENT: raise raise hgutil.Abort("svn metadata is missing - " "run 'hg svn rebuildmeta' to reconstruct it")
def revset_reviewer(repo, subset, x): """``reviewer(REVIEWER)`` Changesets reviewed by a specific person. """ n = revset.getstring(x, _('reviewer() requires a string argument.')) return [r for r in subset if n in parse_reviewers(repo[r].description())]
def revset_gitnode(repo, subset, x): '''``gitnode(hash)`` Select the changeset that originates in the given Git revision. The hash may be abbreviated: `gitnode(a5b)` selects the revision whose Git hash starts with `a5b`. Aborts if multiple changesets match the abbreviation. ''' args = revset.getargs(x, 1, 1, b"gitnode takes one argument") rev = revset.getstring(args[0], b"the argument to gitnode() must be a hash") git = repo.githandler node = repo.changelog.node def matches(r): gitnode = git.map_git_get(hex(node(r))) if gitnode is None: return False return gitnode.startswith(rev) result = revset.baseset(r for r in subset if matches(r)) if 0 <= len(result) < 2: return result raise error.AmbiguousPrefixLookupError( rev, git.map_file, _(b'ambiguous identifier'), )
def revset_pushid(repo, subset, x): """``pushid(int)`` Changesets that were part of the specified numeric push id. """ l = revset.getargs(x, 1, 1, 'pushid requires one argument') try: pushid = int(revset.getstring(l[0], 'pushid requires a number')) except (TypeError, ValueError): raise error.ParseError('pushid expects a number') with repo.pushlog.conn(readonly=True) as conn: push = repo.pushlog.pushfromid(conn, pushid) if conn else None if not push: return revset.baseset() to_rev = repo.changelog.rev pushrevs = set() for node in push.nodes: try: pushrevs.add(to_rev(bin(node))) except RepoLookupError: pass return subset & pushrevs
def revset_reviewer(repo, subset, x): """``reviewer(REVIEWER)`` Changesets reviewed by a specific person. """ n = revset.getstring(x, _('reviewer() requires a string argument.')) return subset.filter(lambda x: n in parse_reviewers(repo[x].description()))
def gitnode(repo, subset, x): """``gitnode(id)`` Return the hg revision corresponding to a given git rev.""" l = revset.getargs(x, 1, 1, _("id requires one argument")) n = revset.getstring(l[0], _("id requires a string")) hexhgnode = _lookup_node(repo, n, from_scm_type='git') if not hexhgnode: raise error.RepoLookupError(_("unknown revision '%s'") % n) rev = repo[hexhgnode].rev() return subset.filter(lambda r: r == rev)
def branch(repo, subset, x): # type: (gitrepository, abstractsmartset, Tuple) -> abstractsmartset """ All changesets belonging to the given branch or the branches of the given changesets. Pattern matching is supported for `string`. See :hg:`help revisions.patterns`. """ def getbranchrevs(r): return set(branches_with(repo._repo, r)) # FIXME: look into sorting by branch name, to keep results stable branchrevs = set() revspec = False try: b = revset.getstring(x, '') except error.ParseError: # not a string, but another revspec, e.g. tip() revspec = True else: kind, pattern, matcher = stringutil.stringmatcher(b) branchmap = repo.branchmap() if kind == 'literal': # note: falls through to the revspec case if no branch with # this name exists and pattern kind is not specified explicitly if pattern in branchmap: branchrevs.add(branchmap[b][0]) elif b.startswith('literal:'): raise error.RepoLookupError( _("branch '%s' does not exist") % pattern) else: revspec = True else: branchrevs.update(r[0] for b, r in branchmap.items() if matcher(b)) if revspec: # get all the branches in x s = revset.getset(repo, gitfullreposet(repo), x) for r in s: branchrevs.update(getbranchrevs(r)) if not branchrevs: # FIXME: return empty set or subset? raise NotImplementedError brs = list(branchrevs) s = gitfullreposet(repo, heads=brs) return subset & s
def revset_gitnode(repo, subset, x): '''``gitnode(hash)`` Select changesets that originate in the given Git revision. ''' args = revset.getargs(x, 1, 1, "gitnode takes one argument") rev = revset.getstring(args[0], "the argument to gitnode() must be a hash") git = GitHandler(repo, repo.ui) def matches(r): gitnode = git.map_git_get(repo[r].hex()) if gitnode is None: return False return rev in [gitnode, gitnode[:12]] return [r for r in subset if matches(r)]
def revset_pushdate(repo, subset, x): """Changesets that were pushed within the interval, see :hg:`help dates`.""" l = revset.getargs(x, 1, 1, 'pushdate requires one argument') ds = revset.getstring(l[0], 'pushdate requires a string argument') dm = util.matchdate(ds) def getrevs(): for push in repo.pushlog.pushes(): if dm(push.when): for node in push.nodes: yield repo[node].rev() return subset & revset.generatorset(getrevs())
def revset_pushdate(repo, subset, x): """``pushdate(interval)`` Changesets that were pushed within the interval, see :hg:`help dates`. """ l = revset.getargs(x, 1, 1, 'pushdate requires one argument') ds = revset.getstring(l[0], 'pushdate requires a string argument') dm = util.matchdate(ds) def getrevs(): for pushid, who, when, nodes in repo.pushlog.pushes(): if dm(when): for node in nodes: yield repo[node].rev() return subset & revset.generatorset(getrevs())
def bmrevset(repo, subset, x): """``bookmark([name])`` The named bookmark or all bookmarks. """ # i18n: "bookmark" is a keyword args = revset.getargs(x, 0, 1, _('bookmark takes one or no arguments')) if args: bm = revset.getstring(args[0], # i18n: "bookmark" is a keyword _('the argument to bookmark must be a string')) bmrev = listbookmarks(repo).get(bm, None) if bmrev: bmrev = repo.changelog.rev(bin(bmrev)) return [r for r in subset if r == bmrev] bms = set([repo.changelog.rev(bin(r)) for r in listbookmarks(repo).values()]) return [r for r in subset if r in bms]
def revset_pushhead(repo, subset, x): """``pushhead([TREE])`` Changesets that are push heads. A push head is a changeset that was a head when it was pushed to a repository. In other words, the automation infrastructure likely kicked off a build using this changeset. If an argument is given, we limit ourselves to pushes on the specified tree. If no argument is given, we return all push heads for all trees. Note that a changeset can be a push head multiple times. This function doesn't care where the push was made if no argument was given. """ # We have separate code paths because the single tree path uses a single # query and is faster. if x: tree = revset.getstring(x, _('pushhead() requires a string argument.')) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) def pushheads(): for push_id, head_changeset in repo.changetracker.tree_push_head_changesets( tree): try: head = repo[head_changeset].rev() yield head except error.RepoLookupError: # There are some malformed pushes. Ignore them. continue # Push heads are returned in order of ascending push ID, which # corresponds to ascending commit order in hg. return subset & revset.generatorset(pushheads(), iterasc=True) else: def is_pushhead(r): node = repo[r].node() for push in repo.changetracker.pushes_for_changeset(node): if str(push[4]) == node: return True return False return subset.filter(is_pushhead)
def revset_bug(repo, subset, x): """``bug(N)``` Changesets referencing a specified Bugzilla bug. e.g. bug(123456). """ err = _('bug() requires an integer argument.') bugstring = revset.getstring(x, err) try: bug = int(bugstring) except Exception: raise ParseError(err) # We do a simple string test first because avoiding regular expressions # is good for performance. return [r for r in subset if bugstring in repo[r].description() and bug in parse_bugs(repo[r].description())]
def revset_bug(repo, subset, x): """Changesets referencing a specified Bugzilla bug. e.g. bug(123456).""" err = _('bug() requires an integer argument.') bugstring = revset.getstring(x, err) try: bug = int(bugstring) except Exception: raise ParseError(err) def fltr(x): # We do a simple string test first because avoiding regular expressions # is good for performance. desc = repo[x].description() return bugstring in desc and bug in parse_bugs(desc) return subset.filter(fltr)
def revset_pushhead(repo, subset, x): """``pushhead([TREE])`` Changesets that are push heads. A push head is a changeset that was a head when it was pushed to a repository. In other words, the automation infrastructure likely kicked off a build using this changeset. If an argument is given, we limit ourselves to pushes on the specified tree. If no argument is given, we return all push heads for all trees. Note that a changeset can be a push head multiple times. This function doesn't care where the push was made if no argument was given. """ # We have separate code paths because the single tree path uses a single # query and is faster. if x: tree = revset.getstring(x, _('pushhead() requires a string argument.')) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) def pushheads(): for push_id, head_changeset in repo.changetracker.tree_push_head_changesets(tree): try: head = repo[head_changeset].rev() yield head except error.RepoLookupError: # There are some malformed pushes. Ignore them. continue # Push heads are returned in order of ascending push ID, which # corresponds to ascending commit order in hg. return subset & revset.generatorset(pushheads(), iterasc=True) else: def is_pushhead(r): node = repo[r].node() for push in repo.changetracker.pushes_for_changeset(node): if str(push[4]) == node: return True return False return subset.filter(is_pushhead)
def revset_reviewer(repo, subset, x): """``reviewer(REVIEWER)`` Changesets reviewed by a specific person. """ l = revset.getargs(x, 1, 1, b'reviewer requires one argument') n = encoding.lower(revset.getstring(l[0], b'reviewer requires a string')) # Do not use a matcher here because regular expressions are not safe # for remote execution and may DoS the server. def hasreviewer(r): for reviewer in commitparser.parse_reviewers(repo[r].description()): if encoding.lower(reviewer) == n: return True return False return subset.filter(hasreviewer)
def revset_firstpushdate(repo, subset, x): """``firstpushdate(DATE)`` Changesets that were initially pushed according to the date spec provided. """ ds = revset.getstring(x, _('firstpushdate() requires a string')) dm = util.matchdate(ds) def fltr(x): pushes = list(repo.changetracker.pushes_for_changeset(repo[x].node())) if not pushes: return False when = pushes[0][2] return dm(when) return subset.filter(fltr)
def revset_pushdate(repo, subset, x): """``pushdate(interval)`` Changesets that were pushed within the interval. See :hg:`help dates`. """ l = revset.getargs(x, 1, 1, 'pushdate requires one argument') ds = revset.getstring(l[0], 'pushdate requires a string argument') dm = dateutil.matchdate(ds) def getrevs(): to_rev = repo.changelog.rev for push in repo.pushlog.pushes(): if dm(push.when): for node in push.nodes: yield to_rev(bin(node)) return subset & revset.generatorset(getrevs())
def revset_reviewer(repo, subset, x): """``reviewer(REVIEWER)`` Changesets reviewed by a specific person. """ l = revset.getargs(x, 1, 1, 'reviewer requires one argument') n = encoding.lower(revset.getstring(l[0], 'reviewer requires a string')) # Do not use a matcher here because regular expressions are not safe # for remote execution and may DoS the server. def hasreviewer(r): for reviewer in commitparser.parse_reviewers(repo[r].description()): if encoding.lower(reviewer) == n: return True return False return subset.filter(hasreviewer)
def revset_tree(repo, subset, x): """``tree(X)`` Changesets currently in the specified Mozilla tree. A tree is the name of a repository. e.g. ``central``. """ err = _('tree() requires a string argument.') tree = revset.getstring(x, err) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) ref = '%s/default' % tree head = repo[ref].rev() ancestors = set(repo.changelog.ancestors([head], inclusive=True)) return subset & revset.baseset(ancestors)
def revset_pushdate(repo, subset, x): """``pushdate(DATE)`` Changesets that were pushed according to the date spec provided. All pushes are examined. """ ds = revset.getstring(x, _('pushdate() requires a string')) dm = util.matchdate(ds) def fltr(x): for push in repo.changetracker.pushes_for_changeset(repo[x].node()): when = push[2] if dm(when): return True return False return subset.filter(fltr)
def revset_tree(repo, subset, x): """``tree(X)`` Changesets currently in the specified Mozilla tree. A tree is the name of a repository. e.g. ``central``. """ err = _('tree() requires a string argument.') tree = revset.getstring(x, err) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) ref = '%s/default' % tree head = repo[ref].rev() ancestors = set(repo.changelog.ancestors([head], inclusive=True)) return [r for r in subset if r in ancestors]
def revset_svnrev(repo, subset, x): '''``svnrev(number)`` Select changesets that originate in the given Subversion revision. ''' args = revset.getargs(x, 1, 1, "svnrev takes one argument") rev = revset.getstring(args[0], "the argument to svnrev() must be a number") try: rev = int(rev) except ValueError: raise error.ParseError("the argument to svnrev() must be a number") def matches(r): convertinfo = repo[r].extra().get('convert_revision', '') if convertinfo[:4] != 'svn:': return False return int(convertinfo[40:].rsplit('@', 1)[-1]) == rev return [r for r in subset if matches(r)]
def revset_firstpushtree(repo, subset, x): """``firstpushtree(X)`` Changesets that were initially pushed to tree X. """ tree = revset.getstring(x, _('firstpushtree() requires a string argument.')) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) def fltr(x): pushes = list(repo.changetracker.pushes_for_changeset( repo[x].node())) if not pushes: return False return pushes[0][0] == tree return subset.filter(fltr)
def revset_svnrev(repo, subset, x): '''``svnrev(number)`` Select changesets that originate in the given Subversion revision. ''' args = revset.getargs(x, 1, 1, "svnrev takes one argument") rev = revset.getstring(args[0], "the argument to svnrev() must be a number") try: revnum = int(rev) except ValueError: raise error.ParseError("the argument to svnrev() must be a number") meta = repo.svnmeta(skiperrorcheck=True) if not meta.revmapexists: raise error.Abort("svn metadata is missing - " "run 'hg svn rebuildmeta' to reconstruct it") torev = repo.changelog.rev revs = revset.baseset(torev(r) for r in meta.revmap.revhashes(revnum)) return subset & revs
def revset_pushdate(repo, subset, x): """``pushdate(DATE)`` Changesets that were pushed according to the date spec provided. All pushes are examined. """ ds = revset.getstring(x, _('pushdate() requires a string')) dm = util.matchdate(ds) revs = [] for rev in subset: for push in repo.changetracker.pushes_for_changeset(repo[rev].node()): when = push[2] if dm(when): revs.append(rev) break return revs
def revset_pushuser(repo, subset, x): """User name that pushed the changeset contains string. The match is case-insensitive. If `string` starts with `re:`, the remainder of the string is treated as a regular expression. To match a user that actually contains `re:`, use the prefix `literal:`. """ l = revset.getargs(x, 1, 1, 'pushuser requires one argument') n = encoding.lower(revset.getstring(l[0], 'pushuser requires a string')) kind, pattern, matcher = revset._substringmatcher(n) def getrevs(): for push in repo.pushlog.pushes(): if matcher(encoding.lower(push.user)): for node in push.nodes: yield repo[node].rev() return subset & revset.generatorset(getrevs())
def revset_firstpushtree(repo, subset, x): """``firstpushtree(X)`` Changesets that were initially pushed to tree X. """ tree = revset.getstring(x, _('firstpushtree() requires a string argument.')) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) def fltr(x): pushes = list(repo.changetracker.pushes_for_changeset(repo[x].node())) if not pushes: return False return pushes[0][0] == tree return subset.filter(fltr)
def revset_pushuser(repo, subset, x): """``pushuser(string)`` User name that pushed the changeset contains string. The match is case-insensitive. If `string` starts with `re:`, the remainder of the string is treated as a regular expression. To match a user that actually contains `re:`, use the prefix `literal:`. """ l = revset.getargs(x, 1, 1, 'pushuser requires one argument') n = encoding.lower(revset.getstring(l[0], 'pushuser requires a string')) kind, pattern, matcher = revset._substringmatcher(n) def getrevs(): for pushid, who, when, nodes in repo.pushlog.pushes(): if matcher(encoding.lower(who)): for node in nodes: yield repo[node].rev() return subset & revset.generatorset(getrevs())
def revset_firstpushdate(repo, subset, x): """``firstpushdate(DATE)`` Changesets that were initially pushed according to the date spec provided. """ ds = revset.getstring(x, _('firstpushdate() requires a string')) dm = util.matchdate(ds) revs = [] for rev in subset: pushes = list(repo.changetracker.pushes_for_changeset(repo[rev].node())) if not pushes: continue when = pushes[0][2] if dm(when): revs.append(rev) return revs
def revset_pushhead(repo, subset, x): """``pushhead([TREE])`` Changesets that are push heads. A push head is a changeset that was a head when it was pushed to a repository. In other words, the automation infrastructure likely kicked off a build using this changeset. If an argument is given, we limit ourselves to pushes on the specified tree. If no argument is given, we return all push heads for all trees. Note that a changeset can be a push head multiple times. This function doesn't care where the push was made if no argument was given. """ # We have separate code paths because the single tree path uses a single # query and is faster. if x: tree = revset.getstring(x, _('pushhead() requires a string argument.')) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) heads = set(repo[r[4]].rev() for r in repo.changetracker.tree_push_heads(tree)) return [r for r in subset if r in heads] revs = [] for r in subset: node = repo[r].node() for push in repo.changetracker.pushes_for_changeset(node): if str(push[4]) == node: revs.append(r) break return revs
def filelogrevset(orig, repo, subset, x): """``filelog(pattern)`` Changesets connected to the specified filelog. For performance reasons, ``filelog()`` does not show every changeset that affects the requested file(s). See :hg:`help log` for details. For a slower, more accurate result, use ``file()``. """ if not shallowrepo.requirement in repo.requirements: return orig(repo, subset, x) # i18n: "filelog" is a keyword pat = revset.getstring(x, _("filelog requires a pattern")) m = match.match(repo.root, repo.getcwd(), [pat], default='relpath', ctx=repo[None]) s = set() if not match.patkind(pat): # slow for r in subset: ctx = repo[r] cfiles = ctx.files() for f in m.files(): if f in cfiles: s.add(ctx.rev()) break else: # partial for f in repo[None]: filenode = m(f) if filenode: fctx = repo.filectx(f, fileid=filenode) s.add(fctx.linkrev()) for actx in fctx.ancestors(): s.add(actx.linkrev()) return [r for r in subset if r in s]
def gitnode(repo, subset, x): """``gitnode(id)`` Return the hg revision corresponding to a given git rev.""" l = revset.getargs(x, 1, 1, _("id requires one argument")) n = revset.getstring(l[0], _("id requires a string")) reponame = repo.ui.config('fbconduit', 'reponame') if not reponame: # We don't know who we are, so we can't ask for a translation return subset.filter(lambda r: False) backingrepos = repo.ui.configlist('fbconduit', 'backingrepos', default=[reponame]) lasterror = None hghash = None for backingrepo in backingrepos: try: result = call_conduit('scmquery.get.mirrored.revs', from_repo=backingrepo, from_scm='git', to_repo=reponame, to_scm='hg', revs=[n] ) hghash = result[n] if hghash != '': break except Exception as ex: lasterror = ex if not hghash: if lasterror: repo.ui.warn(("Could not translate revision {0}: {1}\n".format( n, lasterror))) else: repo.ui.warn(("Could not translate revision {0}\n".format(n))) return subset.filter(lambda r: False) rn = repo[node.bin(hghash)].rev() return subset.filter(lambda r: r == rn)
def revset_firstpushtree(repo, subset, x): """``firstpushtree(X)`` Changesets that were initially pushed to tree X. """ tree = revset.getstring(x, _('firstpushtree() requires a string argument.')) tree, uri = resolve_trees_to_uris([tree])[0] if not uri: raise util.Abort(_("Don't know about tree: %s") % tree) revs = [] for rev in subset: pushes = list(repo.changetracker.pushes_for_changeset( repo[rev].node())) if not pushes: continue if pushes[0][0] == tree: revs.append(rev) return revs
def revset_gittag(repo, subset, x): """``gittag([name])`` The specified Git tag by name, or all revisions tagged with Git if no name is given. Pattern matching is supported for `name`. See :hg:`help revisions.patterns`. """ # mostly copied from tag() mercurial/revset.py # i18n: "tag" is a keyword args = revset.getargs(x, 0, 1, _(b"tag takes one or no arguments")) cl = repo.changelog git = repo.githandler if args: pattern = revset.getstring( args[0], # i18n: "tag" is a keyword _(b'the argument to tag must be a string'), ) kind, pattern, matcher = stringutil.stringmatcher(pattern) if kind == b'literal': # avoid resolving all tags tn = git.tags.get(pattern, None) if tn is None: raise error.RepoLookupError( _(b"git tag '%s' does not exist") % pattern) s = {repo[bin(tn)].rev()} else: s = {cl.rev(bin(n)) for t, n in git.tags.items() if matcher(t)} else: s = {cl.rev(bin(n)) for t, n in git.tags.items()} return subset & s