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