diff --git a/hgext/phabricator.py b/hgext/phabricator.py --- a/hgext/phabricator.py +++ b/hgext/phabricator.py @@ -37,6 +37,9 @@ # API token. Get it from https://$HOST/conduit/login/ example.phabtoken = cli-xxxxxxxxxxxxxxxxxxxxxxxxxxxx + +As a fallback, read config from arc config files (.arcconfig, ~/.arcrc and +/etc/arcconfig) """ from __future__ import absolute_import @@ -46,6 +49,7 @@ import json import operator import re +import os from mercurial.node import bin, nullid from mercurial.i18n import _ @@ -60,6 +64,7 @@ parser, patch, phases, + pycompat, registrar, scmutil, smartset, @@ -67,6 +72,7 @@ templateutil, url as urlmod, util, + vfs as vfsmod, ) from mercurial.utils import ( procutil, @@ -171,16 +177,49 @@ process(b'', params) return util.urlreq.urlencode(flatparams) +def readarcconfig(repo): + """Return url, token, callsign read from arcanist config files + + This read and merge content of /etc/arcconfig, ~/.arcrc and .arconfig. + """ + if pycompat.iswindows: + paths = [ + vfsmod.vfs(encoding.environ['ProgramData']).join( + 'Phabricator', 'Arcanist', 'config'), + vfsmod.vfs(encoding.environ['AppData']).join('.arcrc') + ] + else: + paths = [ + vfsmod.vfs('/etc').join('.arconfig'), + os.path.expanduser('~/.arcrc'), + ] + paths.append(vfsmod.vfs(repo.root).join('.arcconfig')) + config = {} + for path in paths: + if vfsmod.vfs(path).exists(): + with vfsmod.vfs(path).open(None, auditpath=False) as f: + config.update(json.load(f)) + callsign = config.get('repository.callsign') + conduit_uri = config.get('conduit_uri', config.get('config', {}).get('default')) + if conduit_uri is not None: + token = config.get('hosts', {}).get(conduit_uri, {}).get('token') + url = conduit_uri.rstrip('/api/') + return url, token, callsign + def readurltoken(repo): """return conduit url, token and make sure they exist - Currently read from [auth] config section. In the future, it might - make sense to read from .arcconfig and .arcrc as well. + Currently read from [auth] config section and fallback to reading arc + config files. """ url = repo.ui.config(b'phabricator', b'url') if not url: - raise error.Abort(_(b'config %s.%s is required') - % (b'phabricator', b'url')) + url, token, __ = readarcconfig(repo) + if not url or not token: + raise error.Abort(_(b'unable to read phabricator conduit url and ' + b'token from config %s.%s or from arc config ' + b'files') % (b'phabricator', b'url')) + return url, token res = httpconnectionmod.readauthforuri(repo.ui, url, util.url(url).user) token = None @@ -246,7 +285,9 @@ return repophid callsign = repo.ui.config(b'phabricator', b'callsign') if not callsign: - return None + __, __, callsign = readarcconfig(repo) + if not callsign: + return None query = callconduit(repo, b'diffusion.repository.search', {b'constraints': {b'callsigns': [callsign]}}) if len(query[r'data']) == 0: