mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
fbconduit extension
Summary: Adds a template method to fetch hash translations from scmquery Test Plan: [ericsumner@dev2048 ~/fbcode] time hg log -T '{node} {mirrornode("git")}\n' --config extensions.conduit=~/fb-hgext/fbconduit.py -r 'master~5::master' --config fbconduit.reponame=fbcode 744def84d4821ae847ca9e2c31147ec495b0ff2a e498cef35914c5a7a8de648888e47b0d6c452044 86d589bbed310cac765d1d2822f350c66f55ee30 a49473c0f0a0eaa532f0f25f8e632015dc57de87 74e5eddf18a9e911b561d2f2f79c433971e36234 608e41cd9c4e8a0ba8dcd3f53162fed656354db0 95a4cce9686558864af97631142a23eee1ffd1b0 228cbfc779da14306ae43002317bf59be9b3844d 9ec5dfd21c5360bcff66ddd3db4747742da9bd56 115df93aa18a5003323f5419bbd135a9a08d96b9 721fd7f98313aec4513bf86817bf98e01238ebdc 170cde24839d9213efa11f4f965402fd5e13cc9b real 0m0.407s user 0m0.229s sys 0m0.080s [ericsumner@dev2048 ~/fbcode] time hg log -T '{node} {mirrornode("git")}\n' --config extensions.conduit=~/fb-hgext/fbconduit.py -r 'ancestor(.,master)::master' --config fbconduit.reponame=fbcode | wc -l 157 real 0m2.718s user 0m0.504s sys 0m0.066s Reviewers: #sourcecontrol, durham Reviewed By: #sourcecontrol, durham Subscribers: sid0, durham, lcharignon Differential Revision: https://phabricator.fb.com/D2070465
This commit is contained in:
parent
6653644dc8
commit
cc30c1fd65
103
fbconduit.py
Normal file
103
fbconduit.py
Normal file
@ -0,0 +1,103 @@
|
||||
# fbconduit.py
|
||||
#
|
||||
# An extension to query remote servers for extra information via conduit RPC
|
||||
#
|
||||
# Copyright 2015 Facebook, Inc.
|
||||
|
||||
from mercurial import templater
|
||||
import json
|
||||
from urllib import urlencode
|
||||
import httplib
|
||||
|
||||
conduit_host = None
|
||||
conduit_path = None
|
||||
connection = None
|
||||
|
||||
MAX_CONNECT_RETRIES = 3
|
||||
|
||||
class ConduitError(Exception):
|
||||
pass
|
||||
|
||||
class HttpError(Exception):
|
||||
pass
|
||||
|
||||
def extsetup(ui):
|
||||
global conduit_host, conduit_path
|
||||
conduit_host = ui.config('fbconduit', 'host')
|
||||
conduit_path = ui.config('fbconduit', 'path')
|
||||
|
||||
if not conduit_host:
|
||||
ui.warn('No conduit host specified in config; disabling fbconduit\n')
|
||||
return
|
||||
templater.funcs['mirrornode'] = mirrornode
|
||||
|
||||
def _call_conduit(method, **kwargs):
|
||||
global connection, conduit_host, conduit_path
|
||||
|
||||
# start connection
|
||||
if connection is None:
|
||||
connection = httplib.HTTPSConnection(conduit_host)
|
||||
|
||||
# send request
|
||||
path = conduit_path + method
|
||||
args = urlencode({'params': json.dumps(kwargs)})
|
||||
for attempt in xrange(MAX_CONNECT_RETRIES):
|
||||
try:
|
||||
connection.request('POST', path, args, {'Connection': 'Keep-Alive'})
|
||||
break;
|
||||
except httplib.HTTPException as e:
|
||||
connection.connect()
|
||||
else:
|
||||
raise e
|
||||
|
||||
# read http response
|
||||
response = connection.getresponse()
|
||||
if response.status != 200:
|
||||
raise HttpError(response.reason)
|
||||
result = response.read()
|
||||
|
||||
# strip jsonp header and parse
|
||||
assert result.startswith('for(;;);')
|
||||
result = json.loads(result[8:])
|
||||
|
||||
# check for conduit errors
|
||||
if result['error_code']:
|
||||
raise ConduitError(result['error_info'])
|
||||
|
||||
# return RPC result
|
||||
return result['result']
|
||||
|
||||
# don't close the connection b/c we want to avoid the connection overhead
|
||||
|
||||
def mirrornode(ctx, mapping, args):
|
||||
'''template: find this commit in other repositories'''
|
||||
|
||||
reponame = mapping['repo'].ui.config('fbconduit', 'reponame')
|
||||
if not reponame:
|
||||
# We don't know who we are, so we can't ask for a translation
|
||||
return ''
|
||||
|
||||
if mapping['ctx'].mutable():
|
||||
# Local commits don't have translations
|
||||
return ''
|
||||
|
||||
node = mapping['ctx'].hex()
|
||||
args = [f(ctx, mapping, a) for f, a in args]
|
||||
if len(args) == 1:
|
||||
torepo, totype = reponame, args[0]
|
||||
else:
|
||||
torepo, totype = args
|
||||
|
||||
try:
|
||||
result = _call_conduit('scmquery.get.mirrored.revs',
|
||||
from_repo=reponame,
|
||||
from_scm='hg',
|
||||
to_repo=torepo,
|
||||
to_scm=totype,
|
||||
revs=[node]
|
||||
)
|
||||
except ConduitError as e:
|
||||
if 'unknown revision' not in str(e.args):
|
||||
mapping['repo'].ui.warn(str(e.args) + '\n')
|
||||
return ''
|
||||
return result.get(node, '')
|
Loading…
Reference in New Issue
Block a user