# HG changeset patch # User Matt Mackall # Date 1473794045 18000 # Node ID 7757cc48b7660f802f51dde04429fcdc797bef22 # Parent 5c122b41070680fba1b82838abc6c141876cc19e 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: []\n An extdata source is configured thusly: [extdata] name = 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 diff -r 5c122b410706 -r 7757cc48b766 mercurial/scmutil.py --- 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(