diff --git a/git_config.py b/git_config.py index 1382d5db..138470c5 100644 --- a/git_config.py +++ b/git_config.py @@ -356,18 +356,21 @@ class RefSpec(object): return s -_ssh_cache = {} +_master_processes = [] +_master_keys = set() _ssh_master = True def _open_ssh(host, port=None): global _ssh_master + # Check to see whether we already think that the master is running; if we + # think it's already running, return right away. if port is not None: key = '%s:%s' % (host, port) else: key = host - if key in _ssh_cache: + if key in _master_keys: return True if not _ssh_master \ @@ -377,15 +380,39 @@ def _open_ssh(host, port=None): # return False - command = ['ssh', - '-o','ControlPath %s' % ssh_sock(), - '-M', - '-N', - host] - + # We will make two calls to ssh; this is the common part of both calls. + command_base = ['ssh', + '-o','ControlPath %s' % ssh_sock(), + host] if port is not None: - command[3:3] = ['-p',str(port)] + command_base[1:1] = ['-p',str(port)] + # Since the key wasn't in _master_keys, we think that master isn't running. + # ...but before actually starting a master, we'll double-check. This can + # be important because we can't tell that that 'git@myhost.com' is the same + # as 'myhost.com' where "User git" is setup in the user's ~/.ssh/config file. + check_command = command_base + ['-O','check'] + try: + Trace(': %s', ' '.join(check_command)) + check_process = subprocess.Popen(check_command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + check_process.communicate() # read output, but ignore it... + isnt_running = check_process.wait() + + if not isnt_running: + # Our double-check found that the master _was_ infact running. Add to + # the list of keys. + _master_keys.add(key) + return True + except Exception: + # Ignore excpetions. We we will fall back to the normal command and print + # to the log there. + pass + + command = command_base[:1] + \ + ['-M', '-N'] + \ + command_base[1:] try: Trace(': %s', ' '.join(command)) p = subprocess.Popen(command) @@ -396,20 +423,22 @@ def _open_ssh(host, port=None): % (host,port, str(e)) return False - _ssh_cache[key] = p + _master_processes.append(p) + _master_keys.add(key) time.sleep(1) return True def close_ssh(): terminate_ssh_clients() - for key,p in _ssh_cache.iteritems(): + for p in _master_processes: try: os.kill(p.pid, SIGTERM) p.wait() except OSError: pass - _ssh_cache.clear() + del _master_processes[:] + _master_keys.clear() d = ssh_sock(create=False) if d: