# HG changeset patch # User Matt Mackall <m...@selenic.com> # Date 1473794045 18000 # Tue Sep 13 14:14:05 2016 -0500 # Node ID 19bf2776dfe39befdc479253e1e7d030b41c08f9 # Parent 5271ae66615207f39cc41d78f4541bc6f8ca6ff6 extdata: add extdatasource reader
This adds basic support for extdata, a way to add external data sources for revsets and templates. An extdata data source is simply a list of lines of the form: <revision identifier>[<space><freeform text>]\n An extdata source is configured thusly: [extdata] name = <a url or path> urls of the form shell: are launch shell commands to generate data. diff -r 5271ae666152 -r 19bf2776dfe3 mercurial/scmutil.py --- a/mercurial/scmutil.py Wed Sep 21 17:05:27 2016 -0400 +++ b/mercurial/scmutil.py Tue Sep 13 14:14:05 2016 -0500 @@ -29,6 +29,7 @@ phases, revset, similar, + url, util, ) @@ -1418,3 +1419,66 @@ return self._queue.put(fh, block=True, timeout=None) + +def extdatasources(repo): + sources = set() + for k, v in repo.ui.configitems("extdata"): + sources.add(k) + return sources + +def extdatasource(repo, source): + """gather a map of rev -> value dict from the specified source + + A source spec is treated as a URL, with a special case shell: type + for parsing the output from a shell command. + + The data is parsed as a series of newline-separated records where + each record is a revision specifier optionally followed by a space + and a freeform string value. If the revision is known locally, it + is converted to a rev, otherwise the record is skipped. + + Note that both key and value are treated as UTF-8 and converted to + the local encoding. This allows uniformity between local and + remote data sources. + """ + + spec = repo.ui.config("extdata", source) + if not spec: + raise util.Abourt(_("unknown extdata source '%s'") % source) + + try: + # prepare for future expansion + expand = spec % () + except TypeError: + raise error.Abort(_("extdata doesn't support parameters yet"), + hint=_("use double % for escaping")) + + data = {} + if spec.startswith("shell:"): + # external commands should be run relative to the repo root + cmd = spec[6:] + cwd = os.getcwd() + os.chdir(repo.root) + try: + src = util.popen(cmd) + finally: + os.chdir(cwd) + else: + # treat as a URL or file + src = url.open(repo.ui, spec) + + try: + for l in src.readlines(): + if " " in l: + k, v = l.strip().split(" ", 1) + else: + k, v = l.strip(), "" + + k = encoding.tolocal(k) + if k in repo: + # we ignore data for nodes that don't exist locally + data[repo[k].rev()] = encoding.tolocal(v) + finally: + src.close() + + return data _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel