Mercurial > evolve
view hgext3rd/evolve/templatekw.py @ 2595:54ac473663ff mercurial-4.1
compat-test: merge with stable
* Blackbox format seems to have change when displaying config CLI options.
* As obsfate template is now only compatible with hg 4.2+, remove all references
to it in test files.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Fri, 16 Jun 2017 11:42:00 +0200 |
parents | d3d686f05458 a3fbe5293bf6 |
children | 44dd9d76afb2 01e32f11f1ef |
line wrap: on
line source
# Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com> # Logilab SA <contact@logilab.fr> # Pierre-Yves David <pierre-yves.david@ens-lyon.org> # Patrick Mezard <patrick@mezard.eu> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. """evolve templates """ from . import ( exthelper, obshistory ) from mercurial import ( templatekw, node, ) eh = exthelper.exthelper() ### template keywords # XXX it does not handle troubles well :-/ @eh.templatekw('obsolete') def obsoletekw(repo, ctx, templ, **args): """:obsolete: String. Whether the changeset is ``obsolete``. """ if ctx.obsolete(): return 'obsolete' return '' @eh.templatekw('troubles') def showtroubles(**args): """:troubles: List of strings. Evolution troubles affecting the changeset (zero or more of "unstable", "divergent" or "bumped").""" ctx = args['ctx'] try: # specify plural= explicitly to trigger TypeError on hg < 4.2 return templatekw.showlist('trouble', ctx.troubles(), args, plural='troubles') except TypeError: return templatekw.showlist('trouble', ctx.troubles(), plural='troubles', **args) def closestprecursors(repo, nodeid): """ Yield the list of next precursors pointing on visible changectx nodes """ precursors = repo.obsstore.precursors stack = [nodeid] while stack: current = stack.pop() currentpreccs = precursors.get(current, ()) for prec in currentpreccs: precnodeid = prec[0] if precnodeid in repo: yield precnodeid else: stack.append(precnodeid) @eh.templatekw("precursors") def shownextvisibleprecursors(repo, ctx, **args): """Returns a string containing the list if the closest successors displayed """ precursors = sorted(closestprecursors(repo, ctx.node())) # <= hg-4.1 requires an explicite gen. # we can use None once the support is dropped # # They also requires an iterator instead of an iterable. gen = iter(" ".join(map(node.short, precursors))) return templatekw._hybrid(gen.__iter__(), precursors, lambda x: {'precursor': x}, lambda d: "%s" % node.short(d['precursor'])) def closestsuccessors(repo, nodeid): """ returns the closest visible successors sets instead. """ return directsuccessorssets(repo, nodeid) @eh.templatekw("successors") def shownextvisiblesuccessors(repo, ctx, templ, **args): """Returns a string of sets of successors for a changectx in this format: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2 while also diverged into ctx3""" if not ctx.obsolete(): return '' ssets, _ = closestsuccessors(repo, ctx.node()) data = [] gen = [] for ss in ssets: subgen = '[%s]' % ', '.join(map(node.short, ss)) gen.append(subgen) h = templatekw._hybrid(iter(subgen), ss, lambda x: {'successor': x}, lambda d: "%s" % d["successor"]) data.append(h) gen = ', '.join(gen) return templatekw._hybrid(iter(gen), data, lambda x: {'successorset': x}, lambda d: d["successorset"]) def obsfatedefaulttempl(): """ Returns a dict with the default templates for obs fate """ # Prepare templates verbtempl = '{verb}' usertempl = '{if(users, " by {join(users, ", ")}")}' succtempl = '{if(successors, " as ")}{successors}' # Bypass if limitation datetempleq = ' (at {min_date|isodate})' datetemplnoteq = ' (between {min_date|isodate} and {max_date|isodate})' datetempl = '{if(max_date, "{ifeq(min_date, max_date, "%s", "%s")}")}' % (datetempleq, datetemplnoteq) newline = '\n' # Assemble them return { 'obsfate_quiet': verbtempl + succtempl + newline, 'obsfate': verbtempl + usertempl + succtempl + newline, 'obsfate_verbose': verbtempl + usertempl + succtempl + datetempl + newline } @eh.templatekw("obsfate") def showobsfate(repo, ctx, **args): if not ctx.obsolete(): return '' successorssets, pathcache = closestsuccessors(repo, ctx.node()) # closestsuccessors returns an empty list for pruned revisions, remap it # into a list containing en empty list for future processing if successorssets == []: successorssets = [[]] values = [] for successorset in successorssets: raw = obshistory._preparesuccessorset(successorset, pathcache) # As we can't do something like # "{join(map(nodeshort, successors), ', '}" in template, manually # create a correct textual representation gen = ', '.join(map(node.short, raw['successors'])) makemap = lambda x: {'successor': x} joinfmt = lambda d: "%s" % d['successor'] raw['successors'] = templatekw._hybrid(gen, raw['successors'], makemap, joinfmt) values.append(raw) # Insert default obsfate templates args['templ'].cache.update(obsfatedefaulttempl()) if repo.ui.quiet: name = "obsfate_quiet" elif repo.ui.verbose: name = "obsfate_verbose" elif repo.ui.debugflag: name = "obsfate_debug" else: name = "obsfate" return templatekw.showlist(name, values, args, separator=' + ') # copy from mercurial.obsolete with a small change to stop at first known changeset. def directsuccessorssets(repo, initialnode, cache=None): """return set of all direct successors of initial nodes """ succmarkers = repo.obsstore.successors # Stack of nodes we search successors sets for toproceed = [initialnode] # set version of above list for fast loop detection # element added to "toproceed" must be added here stackedset = set(toproceed) pathscache = {} if cache is None: cache = {} while toproceed: current = toproceed[-1] if current in cache: stackedset.remove(toproceed.pop()) elif current != initialnode and current in repo: # We have a valid direct successors. cache[current] = [(current,)] elif current not in succmarkers: if current in repo: # We have a valid last successors. cache[current] = [(current,)] else: # Final obsolete version is unknown locally. # Do not count that as a valid successors cache[current] = [] else: for mark in sorted(succmarkers[current]): for suc in mark[1]: if suc not in cache: if suc in stackedset: # cycle breaking cache[suc] = [] else: # case (3) If we have not computed successors sets # of one of those successors we add it to the # `toproceed` stack and stop all work for this # iteration. pathscache.setdefault(suc, []).append((current, mark)) toproceed.append(suc) stackedset.add(suc) break else: continue break else: succssets = [] for mark in sorted(succmarkers[current]): # successors sets contributed by this marker markss = [[]] for suc in mark[1]: # cardinal product with previous successors productresult = [] for prefix in markss: for suffix in cache[suc]: newss = list(prefix) for part in suffix: # do not duplicated entry in successors set # first entry wins. if part not in newss: newss.append(part) productresult.append(newss) markss = productresult succssets.extend(markss) # remove duplicated and subset seen = [] final = [] candidate = sorted(((set(s), s) for s in succssets if s), key=lambda x: len(x[1]), reverse=True) for setversion, listversion in candidate: for seenset in seen: if setversion.issubset(seenset): break else: final.append(listversion) seen.append(setversion) final.reverse() # put small successors set first cache[current] = final return cache[initialnode], pathscache