summaryrefslogtreecommitdiffstats
path: root/git_config.py
diff options
context:
space:
mode:
Diffstat (limited to 'git_config.py')
-rw-r--r--git_config.py81
1 files changed, 80 insertions, 1 deletions
diff --git a/git_config.py b/git_config.py
index 7e642a4c..163b0809 100644
--- a/git_config.py
+++ b/git_config.py
@@ -16,11 +16,14 @@
16import cPickle 16import cPickle
17import os 17import os
18import re 18import re
19import subprocess
19import sys 20import sys
21import time
22from signal import SIGTERM
20from urllib2 import urlopen, HTTPError 23from urllib2 import urlopen, HTTPError
21from error import GitError, UploadError 24from error import GitError, UploadError
22from trace import Trace 25from trace import Trace
23from git_command import GitCommand 26from git_command import GitCommand, _ssh_sock
24 27
25R_HEADS = 'refs/heads/' 28R_HEADS = 'refs/heads/'
26R_TAGS = 'refs/tags/' 29R_TAGS = 'refs/tags/'
@@ -331,6 +334,79 @@ class RefSpec(object):
331 return s 334 return s
332 335
333 336
337_ssh_cache = {}
338_ssh_master = True
339
340def _open_ssh(host, port=None):
341 global _ssh_master
342
343 if port is None:
344 port = 22
345
346 key = '%s:%s' % (host, port)
347 if key in _ssh_cache:
348 return True
349
350 if not _ssh_master \
351 or 'GIT_SSH' in os.environ \
352 or sys.platform == 'win32':
353 # failed earlier, or cygwin ssh can't do this
354 #
355 return False
356
357 command = ['ssh',
358 '-o','ControlPath %s' % _ssh_sock(),
359 '-p',str(port),
360 '-M',
361 '-N',
362 host]
363 try:
364 Trace(': %s', ' '.join(command))
365 p = subprocess.Popen(command)
366 except Exception, e:
367 _ssh_master = False
368 print >>sys.stderr, \
369 '\nwarn: cannot enable ssh control master for %s:%s\n%s' \
370 % (host,port, str(e))
371 return False
372
373 _ssh_cache[key] = p
374 time.sleep(1)
375 return True
376
377def close_ssh():
378 for key,p in _ssh_cache.iteritems():
379 os.kill(p.pid, SIGTERM)
380 p.wait()
381 _ssh_cache.clear()
382
383 d = _ssh_sock(create=False)
384 if d:
385 try:
386 os.rmdir(os.path.dirname(d))
387 except OSError:
388 pass
389
390URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):')
391URI_ALL = re.compile(r'^([a-z][a-z+]*)://([^@/]*@?[^/])/')
392
393def _preconnect(url):
394 m = URI_ALL.match(url)
395 if m:
396 scheme = m.group(1)
397 host = m.group(2)
398 if ':' in host:
399 host, port = host.split(':')
400 if scheme in ('ssh', 'git+ssh', 'ssh+git'):
401 return _open_ssh(host, port)
402 return False
403
404 m = URI_SCP.match(url)
405 if m:
406 host = m.group(1)
407 return _open_ssh(host)
408
409
334class Remote(object): 410class Remote(object):
335 """Configuration options related to a remote. 411 """Configuration options related to a remote.
336 """ 412 """
@@ -344,6 +420,9 @@ class Remote(object):
344 self._Get('fetch', all=True)) 420 self._Get('fetch', all=True))
345 self._review_protocol = None 421 self._review_protocol = None
346 422
423 def PreConnectFetch(self):
424 return _preconnect(self.url)
425
347 @property 426 @property
348 def ReviewProtocol(self): 427 def ReviewProtocol(self):
349 if self._review_protocol is None: 428 if self._review_protocol is None: