From 1c85f4e43ba2d337b1e8c49bb3c7814a5cb163ae Mon Sep 17 00:00:00 2001 From: Nico Sallembien Date: Tue, 27 Apr 2010 14:35:27 -0700 Subject: Rename _ssh_sock() to fix code style issue. Since _ssh_sock is imported out of the git_command module, the leading underscore should be removed from the function name. --- git_config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'git_config.py') diff --git a/git_config.py b/git_config.py index 45a2d257..a7c82107 100644 --- a/git_config.py +++ b/git_config.py @@ -23,7 +23,7 @@ from signal import SIGTERM from urllib2 import urlopen, HTTPError from error import GitError, UploadError from trace import Trace -from git_command import GitCommand, _ssh_sock +from git_command import GitCommand, ssh_sock R_HEADS = 'refs/heads/' R_TAGS = 'refs/tags/' @@ -371,7 +371,7 @@ def _open_ssh(host, port): return False command = ['ssh', - '-o','ControlPath %s' % _ssh_sock(), + '-o','ControlPath %s' % ssh_sock(), '-p',str(port), '-M', '-N', @@ -399,7 +399,7 @@ def close_ssh(): pass _ssh_cache.clear() - d = _ssh_sock(create=False) + d = ssh_sock(create=False) if d: try: os.rmdir(os.path.dirname(d)) -- cgit v1.2.3-54-g00ecf From ca8c32cd7ae7c3ae27bb6b649eafbfd54d77f916 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 11 May 2010 18:21:33 -0700 Subject: sync: kill git fetch process before SSH control master process If the SSH control master process is killed while an active git fetch is using its network socket, the underlying SSH client may not realize the connection was broken. This can lead to both the client and the server waiting indefinitely for network messages which will never be sent. Work around the problem by keeping track of any processes that use the tunnels we establish. If we are about to kill any of the SSH control masters that we started, ensure the clients using them are successfully killed first. Change-Id: Ida6c124dcb0c6a26bf7dd69cba2fbdc2ecd5b2fc Signed-off-by: Shawn O. Pearce --- git_command.py | 29 ++++++++++++++++++++++++++++- git_config.py | 7 ++++++- 2 files changed, 34 insertions(+), 2 deletions(-) (limited to 'git_config.py') diff --git a/git_command.py b/git_command.py index 3309f378..4ad908f6 100644 --- a/git_command.py +++ b/git_command.py @@ -17,6 +17,7 @@ import os import sys import subprocess import tempfile +from signal import SIGTERM from error import GitError from trace import REPO_TRACE, IsTrace, Trace @@ -29,6 +30,7 @@ LAST_CWD = None _ssh_proxy_path = None _ssh_sock_path = None +_ssh_clients = [] def ssh_sock(create=True): global _ssh_sock_path @@ -51,6 +53,24 @@ def _ssh_proxy(): 'git_ssh') return _ssh_proxy_path +def _add_ssh_client(p): + _ssh_clients.append(p) + +def _remove_ssh_client(p): + try: + _ssh_clients.remove(p) + except ValueError: + pass + +def terminate_ssh_clients(): + global _ssh_clients + for p in _ssh_clients: + try: + os.kill(p.pid, SIGTERM) + p.wait() + except OSError: + pass + _ssh_clients = [] class _GitCall(object): def version(self): @@ -188,6 +208,9 @@ class GitCommand(object): except Exception, e: raise GitError('%s: %s' % (command[1], e)) + if ssh_proxy: + _add_ssh_client(p) + self.process = p self.stdin = p.stdin @@ -210,4 +233,8 @@ class GitCommand(object): else: p.stderr = None - return self.process.wait() + try: + rc = p.wait() + finally: + _remove_ssh_client(p) + return rc diff --git a/git_config.py b/git_config.py index a7c82107..75936d40 100644 --- a/git_config.py +++ b/git_config.py @@ -23,7 +23,10 @@ from signal import SIGTERM from urllib2 import urlopen, HTTPError from error import GitError, UploadError from trace import Trace -from git_command import GitCommand, ssh_sock + +from git_command import GitCommand +from git_command import ssh_sock +from git_command import terminate_ssh_clients R_HEADS = 'refs/heads/' R_TAGS = 'refs/tags/' @@ -391,6 +394,8 @@ def _open_ssh(host, port): return True def close_ssh(): + terminate_ssh_clients() + for key,p in _ssh_cache.iteritems(): try: os.kill(p.pid, SIGTERM) -- cgit v1.2.3-54-g00ecf From 7198572dd7f5b9d95d83733a98691948a3eb9da3 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Sun, 16 Aug 2009 09:44:40 -0700 Subject: Do not invoke ssh with -p argument when no port has been specified. This change allows local SSH configuration to choose the port number to use when not explicitly set in the manifest. (cherry picked from commit 4c0f67046543c7c6ab24175e143001f14b76ea01) Change-Id: Ibea99cfe46b6a2cc27f754cc3944a2fe10f6fda4 --- git_config.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'git_config.py') diff --git a/git_config.py b/git_config.py index 75936d40..dc209ba8 100644 --- a/git_config.py +++ b/git_config.py @@ -359,10 +359,14 @@ class RefSpec(object): _ssh_cache = {} _ssh_master = True -def _open_ssh(host, port): +def _open_ssh(host, port=None): global _ssh_master - key = '%s:%s' % (host, port) + if port is not None: + key = '%s:%s' % (host, port) + else: + key = host + if key in _ssh_cache: return True @@ -375,10 +379,13 @@ def _open_ssh(host, port): command = ['ssh', '-o','ControlPath %s' % ssh_sock(), - '-p',str(port), '-M', '-N', host] + + if port is not None: + command[3:3] = ['-p',str(port)] + try: Trace(': %s', ' '.join(command)) p = subprocess.Popen(command) @@ -422,7 +429,7 @@ def _preconnect(url): if ':' in host: host, port = host.split(':') else: - port = 22 + port = None if scheme in ('ssh', 'git+ssh', 'ssh+git'): return _open_ssh(host, port) return False @@ -430,7 +437,7 @@ def _preconnect(url): m = URI_SCP.match(url) if m: host = m.group(1) - return _open_ssh(host, 22) + return _open_ssh(host) return False -- cgit v1.2.3-54-g00ecf From 3575b8f8bdc5f15de23db82499e0ce152f634a19 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 15 Jul 2010 17:00:14 -0700 Subject: upload: Allow review.HOST.username to override email Some users might need to use a different login name than the local part of their email address for their Gerrit Code Review user account. Allow it to be overridden with the review.HOST.username configuration variable. Change-Id: I714469142ac7feadf09fee9c26680c0e09076b75 Signed-off-by: Shawn O. Pearce --- git_config.py | 5 ++++- subcmds/upload.py | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'git_config.py') diff --git a/git_config.py b/git_config.py index dc209ba8..1382d5db 100644 --- a/git_config.py +++ b/git_config.py @@ -531,8 +531,11 @@ class Remote(object): def SshReviewUrl(self, userEmail): if self.ReviewProtocol != 'ssh': return None + username = self._config.GetString('review.%s.username' % self.review) + if username is None: + username = userEmail.split("@")[0] return 'ssh://%s@%s:%s/%s' % ( - userEmail.split("@")[0], + username, self._review_host, self._review_port, self.projectname) diff --git a/subcmds/upload.py b/subcmds/upload.py index 569e31c1..b47b37b8 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py @@ -92,6 +92,11 @@ review.URL.autocopy can be set to a comma separated list of reviewers who you always want copied on all uploads with a non-empty --re argument. +review.URL.username: + +Override the username used to connect to Gerrit Code Review. +By default the local part of the email address is used. + The URL must match the review URL listed in the manifest XML file, or in the .git/config within the project. For example: -- cgit v1.2.3-54-g00ecf From 06d029c1c8c06a6d446b7cc4d5e763ff0754b149 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 27 Oct 2010 17:06:01 -0700 Subject: Check for existing SSH ControlMaster Be more thorough about checking for an existing ssh master by running a test command first, and only opening up a new master if the test fails to connect. Change-Id: I56fe8e7b4dbc123675b7f259e81d359ed0cd55cf Signed-off-by: Shawn O. Pearce --- git_config.py | 53 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 12 deletions(-) (limited to 'git_config.py') 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: -- cgit v1.2.3-54-g00ecf From 99482ae58a74e236fb40b65c267163a5690f39e1 Mon Sep 17 00:00:00 2001 From: Ulrik Sjölin Date: Fri, 29 Oct 2010 08:23:30 -0700 Subject: Only delete corrupt pickle config files if they exist os.remove() raises OSError if the file being removed doesn't exist. Check before calling to ensure we don't raise a useless exception on an already deleted file. Change-Id: I44c1c7dd97a47fcab8afb6c18fdf179158b6dab7 Signed-off-by: Shawn O. Pearce --- git_config.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'git_config.py') diff --git a/git_config.py b/git_config.py index 138470c5..8e3dfb1b 100644 --- a/git_config.py +++ b/git_config.py @@ -257,9 +257,11 @@ class GitConfig(object): finally: fd.close() except IOError: - os.remove(self._pickle) + if os.path.exists(self._pickle): + os.remove(self._pickle) except cPickle.PickleError: - os.remove(self._pickle) + if os.path.exists(self._pickle): + os.remove(self._pickle) def _ReadGit(self): """ -- cgit v1.2.3-54-g00ecf