Mercurial > hg
changeset 34456:7757cc48b766
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.
This patch is slightly modified by Yuya Nishihara as follows:
- fix typo
- remove unused function
- remove future expansion point for parameter (which can be added later
as the extdata revset/template are experimental)
You can see the original patch at
https://www.mercurial-scm.org/pipermail/mercurial-devel/2016-September/088426.html
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Tue, 13 Sep 2016 14:14:05 -0500 |
parents | 5c122b410706 |
children | 2c3b8fa3211b |
files | mercurial/scmutil.py |
diffstat | 1 files changed, 51 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/scmutil.py Wed Oct 04 10:02:15 2017 +0200 +++ b/mercurial/scmutil.py Tue Sep 13 14:14:05 2016 -0500 @@ -35,6 +35,7 @@ pycompat, revsetlang, similar, + url, util, ) @@ -1016,6 +1017,56 @@ except KeyError: raise AttributeError(self.name) +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 error.Abort(_("unknown extdata source '%s'") % source) + + 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 + def _locksub(repo, lock, envvar, cmd, environ=None, *args, **kwargs): if lock is None: raise error.LockInheritanceContractViolation(