summaryrefslogtreecommitdiffstats
path: root/git_config.py
diff options
context:
space:
mode:
Diffstat (limited to 'git_config.py')
-rw-r--r--git_config.py148
1 files changed, 88 insertions, 60 deletions
diff --git a/git_config.py b/git_config.py
index 286e89ca..ff815e35 100644
--- a/git_config.py
+++ b/git_config.py
@@ -18,6 +18,10 @@ import os
18import re 18import re
19import subprocess 19import subprocess
20import sys 20import sys
21try:
22 import threading as _threading
23except ImportError:
24 import dummy_threading as _threading
21import time 25import time
22import urllib2 26import urllib2
23 27
@@ -371,76 +375,97 @@ class RefSpec(object):
371_master_processes = [] 375_master_processes = []
372_master_keys = set() 376_master_keys = set()
373_ssh_master = True 377_ssh_master = True
378_master_keys_lock = None
379
380def init_ssh():
381 """Should be called once at the start of repo to init ssh master handling.
382
383 At the moment, all we do is to create our lock.
384 """
385 global _master_keys_lock
386 assert _master_keys_lock is None, "Should only call init_ssh once"
387 _master_keys_lock = _threading.Lock()
374 388
375def _open_ssh(host, port=None): 389def _open_ssh(host, port=None):
376 global _ssh_master 390 global _ssh_master
377 391
378 # Check to see whether we already think that the master is running; if we 392 # Acquire the lock. This is needed to prevent opening multiple masters for
379 # think it's already running, return right away. 393 # the same host when we're running "repo sync -jN" (for N > 1) _and_ the
380 if port is not None: 394 # manifest <remote fetch="ssh://xyz"> specifies a different host from the
381 key = '%s:%s' % (host, port) 395 # one that was passed to repo init.
382 else: 396 _master_keys_lock.acquire()
383 key = host 397 try:
384
385 if key in _master_keys:
386 return True
387 398
388 if not _ssh_master \ 399 # Check to see whether we already think that the master is running; if we
389 or 'GIT_SSH' in os.environ \ 400 # think it's already running, return right away.
390 or sys.platform in ('win32', 'cygwin'): 401 if port is not None:
391 # failed earlier, or cygwin ssh can't do this 402 key = '%s:%s' % (host, port)
392 # 403 else:
393 return False 404 key = host
394 405
395 # We will make two calls to ssh; this is the common part of both calls. 406 if key in _master_keys:
396 command_base = ['ssh',
397 '-o','ControlPath %s' % ssh_sock(),
398 host]
399 if port is not None:
400 command_base[1:1] = ['-p',str(port)]
401
402 # Since the key wasn't in _master_keys, we think that master isn't running.
403 # ...but before actually starting a master, we'll double-check. This can
404 # be important because we can't tell that that 'git@myhost.com' is the same
405 # as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file.
406 check_command = command_base + ['-O','check']
407 try:
408 Trace(': %s', ' '.join(check_command))
409 check_process = subprocess.Popen(check_command,
410 stdout=subprocess.PIPE,
411 stderr=subprocess.PIPE)
412 check_process.communicate() # read output, but ignore it...
413 isnt_running = check_process.wait()
414
415 if not isnt_running:
416 # Our double-check found that the master _was_ infact running. Add to
417 # the list of keys.
418 _master_keys.add(key)
419 return True 407 return True
420 except Exception:
421 # Ignore excpetions. We we will fall back to the normal command and print
422 # to the log there.
423 pass
424
425 command = command_base[:1] + \
426 ['-M', '-N'] + \
427 command_base[1:]
428 try:
429 Trace(': %s', ' '.join(command))
430 p = subprocess.Popen(command)
431 except Exception, e:
432 _ssh_master = False
433 print >>sys.stderr, \
434 '\nwarn: cannot enable ssh control master for %s:%s\n%s' \
435 % (host,port, str(e))
436 return False
437 408
438 _master_processes.append(p) 409 if not _ssh_master \
439 _master_keys.add(key) 410 or 'GIT_SSH' in os.environ \
440 time.sleep(1) 411 or sys.platform in ('win32', 'cygwin'):
441 return True 412 # failed earlier, or cygwin ssh can't do this
413 #
414 return False
415
416 # We will make two calls to ssh; this is the common part of both calls.
417 command_base = ['ssh',
418 '-o','ControlPath %s' % ssh_sock(),
419 host]
420 if port is not None:
421 command_base[1:1] = ['-p',str(port)]
422
423 # Since the key wasn't in _master_keys, we think that master isn't running.
424 # ...but before actually starting a master, we'll double-check. This can
425 # be important because we can't tell that that 'git@myhost.com' is the same
426 # as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file.
427 check_command = command_base + ['-O','check']
428 try:
429 Trace(': %s', ' '.join(check_command))
430 check_process = subprocess.Popen(check_command,
431 stdout=subprocess.PIPE,
432 stderr=subprocess.PIPE)
433 check_process.communicate() # read output, but ignore it...
434 isnt_running = check_process.wait()
435
436 if not isnt_running:
437 # Our double-check found that the master _was_ infact running. Add to
438 # the list of keys.
439 _master_keys.add(key)
440 return True
441 except Exception:
442 # Ignore excpetions. We we will fall back to the normal command and print
443 # to the log there.
444 pass
445
446 command = command_base[:1] + \
447 ['-M', '-N'] + \
448 command_base[1:]
449 try:
450 Trace(': %s', ' '.join(command))
451 p = subprocess.Popen(command)
452 except Exception, e:
453 _ssh_master = False
454 print >>sys.stderr, \
455 '\nwarn: cannot enable ssh control master for %s:%s\n%s' \
456 % (host,port, str(e))
457 return False
458
459 _master_processes.append(p)
460 _master_keys.add(key)
461 time.sleep(1)
462 return True
463 finally:
464 _master_keys_lock.release()
442 465
443def close_ssh(): 466def close_ssh():
467 global _master_keys_lock
468
444 terminate_ssh_clients() 469 terminate_ssh_clients()
445 470
446 for p in _master_processes: 471 for p in _master_processes:
@@ -459,6 +484,9 @@ def close_ssh():
459 except OSError: 484 except OSError:
460 pass 485 pass
461 486
487 # We're done with the lock, so we can delete it.
488 _master_keys_lock = None
489
462URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):') 490URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):')
463URI_ALL = re.compile(r'^([a-z][a-z+]*)://([^@/]*@?[^/]*)/') 491URI_ALL = re.compile(r'^([a-z][a-z+]*)://([^@/]*@?[^/]*)/')
464 492