def underwayrevset(repo, subset, x): args = revset.getargsdict(x, 'underway', 'commitage headage') if 'commitage' not in args: args['commitage'] = None if 'headage' not in args: args['headage'] = None # We assume callers of this revset add a topographical sort on the # result. This means there is no benefit to making the revset lazy # since the topographical sort needs to consume all revs. # # With this in mind, we build up the set manually instead of constructing # a complex revset. This enables faster execution. # Mutable changesets (non-public) are the most important changesets # to return. ``not public()`` will also pull in obsolete changesets if # there is a non-obsolete changeset with obsolete ancestors. This is # why we exclude obsolete changesets from this query. rs = 'not public() and not obsolete()' rsargs = [] if args['commitage']: rs += ' and date(%s)' rsargs.append( revsetlang.getstring(args['commitage'], _('commitage requires a string'))) mutable = repo.revs(rs, *rsargs) relevant = revset.baseset(mutable) # Add parents of mutable changesets to provide context. relevant += repo.revs('parents(%ld)', mutable) # We also pull in (public) heads if they a) aren't closing a branch # b) are recent. rs = 'head() and not closed()' rsargs = [] if args['headage']: rs += ' and date(%s)' rsargs.append( revsetlang.getstring(args['headage'], _('headage requires a string'))) relevant += repo.revs(rs, *rsargs) # Add working directory parent. wdirrev = repo['.'].rev() if wdirrev != nullrev: relevant += revset.baseset(set([wdirrev])) return subset & relevant
def _revsetutil(repo, subset, x, rtypes): """utility function to return a set of revs based on the rtypes""" args = revsetlang.getargs(x, 0, 1, _(b'only one argument accepted')) if args: kind, pattern, matcher = stringutil.stringmatcher( revsetlang.getstring(args[0], _(b'argument must be a string'))) else: kind = pattern = None matcher = util.always nodes = set() cl = repo.changelog for rtype in rtypes: if rtype in repo.names: ns = repo.names[rtype] for name in ns.listnames(repo): if not matcher(name): continue nodes.update(ns.nodes(repo, name)) if kind == b'literal' and not nodes: raise error.RepoLookupError( _(b"remote name '%s' does not exist") % pattern) revs = (cl.rev(n) for n in nodes if cl.hasnode(n)) return subset & smartset.baseset(revs)
def _localbranch(repo, subset, x): """``_localbranch(changectx)`` localbranch changesets Returns all commits within the same localbranch as the changeset(s). A local branch is all draft changesets that are connected, uninterupted by public changesets. Any draft commit within a branch, or a public commit at the base of the branch, can be passed used to identify localbranches. """ # executed on an filtered repo args = revset.getargsdict(x, 'branchrevset', 'changectx') revstring = revsetlang.getstring(args.get('changectx'), _('localbranch argument must be a changectx')) revs = repo.revs(revstring) # we assume that there is only a single rev if repo[revs.first()].phase() == phases.public: querystring = revsetlang.formatspec('(children(%d) & draft())::', revs.first()) else: querystring = revsetlang.formatspec('((::%ld) & draft())::', revs) return subset & smartset.baseset(repo.revs(querystring))
def smartlogrevset(repo, subset, x): """``smartlog([master], [recentdays=N])`` Changesets relevent to you. 'master' is the head of the public branch. Unnamed heads will be hidden unless it's within 'recentdays'. """ args = revset.getargsdict(x, 'smartlogrevset', 'master recentdays') if 'master' in args: masterstring = revsetlang.getstring(args['master'], _('master must be a string')) else: masterstring = '' recentdays = revsetlang.getinteger(args.get('recentdays'), _("recentdays should be int"), -1) revs = set() heads = set() rev = repo.changelog.rev ancestor = repo.changelog.ancestor node = repo.changelog.node parentrevs = repo.changelog.parentrevs books = bookmarks.bmstore(repo) ignore = re.compile(repo.ui.config('smartlog', 'ignorebookmarks', '!')) for b in books: if not ignore.match(b): heads.add(rev(books[b])) # add 'interesting' remote bookmarks as well remotebooks = set() if util.safehasattr(repo, 'names') and 'remotebookmarks' in repo.names: ns = repo.names['remotebookmarks'] remotebooks = set(ns.listnames(repo)) for name in _reposnames(repo.ui): if name in remotebooks: heads.add(rev(ns.namemap(repo, name)[0])) heads.update(repo.revs('.')) global hiddenchanges headquery = 'head()' if remotebooks: # When we have remote bookmarks, only show draft heads, since public # heads should have a remote bookmark indicating them. This allows us # to force push server bookmarks to new locations, and not have the # commits clutter the user's smartlog. headquery = 'heads(draft())' allheads = set(repo.revs(headquery)) if recentdays >= 0: recentquery = revsetlang.formatspec('%r & date(-%d)', headquery, recentdays) recentrevs = set(repo.revs(recentquery)) hiddenchanges += len(allheads - heads) - len(recentrevs - heads) heads.update(recentrevs) else: heads.update(allheads) masterrevset = _masterrevset(repo.ui, repo, masterstring) masterrev = _masterrev(repo, masterrevset) if masterrev is None: masterrev = repo['tip'].rev() masternode = node(masterrev) # Find all draft ancestors and latest public ancestor of heads # that are not in master. # We don't want to draw all public commits because there can be too # many of them. # Don't use revsets, they are too slow for head in heads: anc = rev(ancestor(node(head), masternode)) queue = [head] while queue: current = queue.pop(0) if current not in revs: revs.add(current) # stop as soon as we find public commit ispublic = repo[current].phase() == phases.public if current != anc and not ispublic: parents = parentrevs(current) for p in parents: if p > anc: queue.append(p) # add context: master, current commit, and the common ancestor revs.add(masterrev) return subset & revs
def smartlogrevset(repo, subset, x): """``smartlog([master], [recentdays=N])`` Changesets relevent to you. 'master' is the head of the public branch. Unnamed heads will be hidden unless it's within 'recentdays'. """ args = revset.getargsdict(x, 'smartlogrevset', 'master recentdays') if 'master' in args: masterstring = revsetlang.getstring(args['master'], _('master must be a string')) else: masterstring = '' recentdays = revsetlang.getinteger(args.get('recentdays'), _("recentdays should be int"), -1) revs = set() heads = set() rev = repo.changelog.rev branchinfo = repo.changelog.branchinfo ancestor = repo.changelog.ancestor node = repo.changelog.node parentrevs = repo.changelog.parentrevs books = bookmarks.bmstore(repo) ignore = re.compile(repo.ui.config('smartlog', 'ignorebookmarks', '!')) for b in books: if not ignore.match(b): heads.add(rev(books[b])) # add 'interesting' remote bookmarks as well remotebooks = set() if util.safehasattr(repo, 'names') and 'remotebookmarks' in repo.names: ns = repo.names['remotebookmarks'] remotebooks = set(ns.listnames(repo)) for name in _reposnames(repo.ui): if name in remotebooks: heads.add(rev(ns.namemap(repo, name)[0])) heads.update(repo.revs('.')) global hiddenchanges headquery = 'head() & branch(.)' if remotebooks: # When we have remote bookmarks, only show draft heads, since public # heads should have a remote bookmark indicating them. This allows us # to force push server bookmarks to new locations, and not have the # commits clutter the user's smartlog. headquery = 'draft() &' + headquery allheads = set(repo.revs(headquery)) if recentdays >= 0: recentquery = revsetlang.formatspec('%r & date(-%d)', headquery, recentdays) recentrevs = set(repo.revs(recentquery)) hiddenchanges += len(allheads - heads) - len(recentrevs - heads) heads.update(recentrevs) else: heads.update(allheads) branches = set() for head in heads: branches.add(branchinfo(head)[0]) masterrevset = _masterrevset(repo.ui, repo, masterstring) masterrev = _masterrev(repo, masterrevset) if masterrev is None: masterbranch = None else: masterbranch = branchinfo(masterrev)[0] for branch in branches: if branch != masterbranch: try: rs = 'first(reverse(branch("%s")) & public())' % branch branchmaster = repo.revs(rs).first() if branchmaster is None: # local-only (draft) branch rs = 'branch("%s")' % branch branchmaster = repo.revs(rs).first() except Exception: branchmaster = repo.revs('tip').first() else: branchmaster = masterrev # Find all draft ancestors and latest public ancestor of heads # that are not in master. # We don't want to draw all public commits because there can be too # many of them. # Don't use revsets, they are too slow for head in heads: if branchinfo(head)[0] != branch: continue anc = rev(ancestor(node(head), node(branchmaster))) queue = [head] while queue: current = queue.pop(0) if current not in revs: revs.add(current) # stop as soon as we find public commit ispublic = repo[current].phase() == phases.public if current != anc and not ispublic: parents = parentrevs(current) for p in parents: if p > anc: queue.append(p) # add context: master, current commit, and the common ancestor revs.add(branchmaster) # get common branch ancestor if branch != masterbranch: anc = None for r in revs: if branchinfo(r)[0] != branch: continue if anc is None: anc = r else: anc = rev(ancestor(node(anc), node(r))) if anc: revs.add(anc) return subset & revs