diff options
-rw-r--r-- | git_config.py | 148 | ||||
-rwxr-xr-x | main.py | 3 |
2 files changed, 90 insertions, 61 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 | |||
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 | import urllib2 | 26 | import 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 | |||
380 | def 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 | ||
375 | def _open_ssh(host, port=None): | 389 | def _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 | ||
443 | def close_ssh(): | 466 | def 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 | |||
462 | URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):') | 490 | URI_SCP = re.compile(r'^([^@:]*@?[^:/]{1,}):') |
463 | URI_ALL = re.compile(r'^([a-z][a-z+]*)://([^@/]*@?[^/]*)/') | 491 | URI_ALL = re.compile(r'^([a-z][a-z+]*)://([^@/]*@?[^/]*)/') |
464 | 492 | ||
@@ -28,7 +28,7 @@ import re | |||
28 | import sys | 28 | import sys |
29 | 29 | ||
30 | from trace import SetTrace | 30 | from trace import SetTrace |
31 | from git_config import close_ssh | 31 | from git_config import init_ssh, close_ssh |
32 | from command import InteractiveCommand | 32 | from command import InteractiveCommand |
33 | from command import MirrorSafeCommand | 33 | from command import MirrorSafeCommand |
34 | from command import PagedCommand | 34 | from command import PagedCommand |
@@ -212,6 +212,7 @@ def _Main(argv): | |||
212 | repo = _Repo(opt.repodir) | 212 | repo = _Repo(opt.repodir) |
213 | try: | 213 | try: |
214 | try: | 214 | try: |
215 | init_ssh() | ||
215 | repo._Run(argv) | 216 | repo._Run(argv) |
216 | finally: | 217 | finally: |
217 | close_ssh() | 218 | close_ssh() |