summaryrefslogtreecommitdiffstats
path: root/project.py
diff options
context:
space:
mode:
authorDave Borowitz <dborowitz@google.com>2015-01-02 11:12:54 -0800
committerDave Borowitz <dborowitz@google.com>2015-01-02 13:57:13 -0800
commit137d0131bf35b01db0d49e1d9720bbc526232c61 (patch)
tree116b3503d8b9c44a7c95311121bd3c577013c5b6 /project.py
parent42e679b9f63086dc1a27aed2d99deb3c1da428fc (diff)
downloadgit-repo-137d0131bf35b01db0d49e1d9720bbc526232c61.tar.gz
Hold persistent proxy connection open while fetching clone.bundle
The persistent proxy may choose to present a per-process cookie file that gets cleaned up after the process exits, to help with the fact that libcurl cannot save cookies atomically when a cookie file is shared across processes. We were letting this cleanup happen immediately by closing stdin as soon as we read the configuration option, resulting in a nonexistent cookie file by the time we use the config option. Work around this by converting the cookie logic to a context manager method, which closes the process only when we're done with the cookie file. Change-Id: I12a88b25cc19621ef8161337144c1b264264211a
Diffstat (limited to 'project.py')
-rw-r--r--project.py88
1 files changed, 47 insertions, 41 deletions
diff --git a/project.py b/project.py
index 339f1a14..ce27e7ab 100644
--- a/project.py
+++ b/project.py
@@ -13,7 +13,7 @@
13# limitations under the License. 13# limitations under the License.
14 14
15from __future__ import print_function 15from __future__ import print_function
16import traceback 16import contextlib
17import errno 17import errno
18import filecmp 18import filecmp
19import os 19import os
@@ -26,6 +26,7 @@ import sys
26import tarfile 26import tarfile
27import tempfile 27import tempfile
28import time 28import time
29import traceback
29 30
30from color import Coloring 31from color import Coloring
31from git_command import GitCommand, git_require 32from git_command import GitCommand, git_require
@@ -1946,31 +1947,31 @@ class Project(object):
1946 os.remove(tmpPath) 1947 os.remove(tmpPath)
1947 if 'http_proxy' in os.environ and 'darwin' == sys.platform: 1948 if 'http_proxy' in os.environ and 'darwin' == sys.platform:
1948 cmd += ['--proxy', os.environ['http_proxy']] 1949 cmd += ['--proxy', os.environ['http_proxy']]
1949 cookiefile = self._GetBundleCookieFile(srcUrl) 1950 with self._GetBundleCookieFile(srcUrl) as cookiefile:
1950 if cookiefile: 1951 if cookiefile:
1951 cmd += ['--cookie', cookiefile] 1952 cmd += ['--cookie', cookiefile]
1952 if srcUrl.startswith('persistent-'): 1953 if srcUrl.startswith('persistent-'):
1953 srcUrl = srcUrl[len('persistent-'):] 1954 srcUrl = srcUrl[len('persistent-'):]
1954 cmd += [srcUrl] 1955 cmd += [srcUrl]
1955 1956
1956 if IsTrace(): 1957 if IsTrace():
1957 Trace('%s', ' '.join(cmd)) 1958 Trace('%s', ' '.join(cmd))
1958 try: 1959 try:
1959 proc = subprocess.Popen(cmd) 1960 proc = subprocess.Popen(cmd)
1960 except OSError: 1961 except OSError:
1961 return False 1962 return False
1962 1963
1963 curlret = proc.wait() 1964 curlret = proc.wait()
1964 1965
1965 if curlret == 22: 1966 if curlret == 22:
1966 # From curl man page: 1967 # From curl man page:
1967 # 22: HTTP page not retrieved. The requested url was not found or 1968 # 22: HTTP page not retrieved. The requested url was not found or
1968 # returned another error with the HTTP error code being 400 or above. 1969 # returned another error with the HTTP error code being 400 or above.
1969 # This return code only appears if -f, --fail is used. 1970 # This return code only appears if -f, --fail is used.
1970 if not quiet: 1971 if not quiet:
1971 print("Server does not provide clone.bundle; ignoring.", 1972 print("Server does not provide clone.bundle; ignoring.",
1972 file=sys.stderr) 1973 file=sys.stderr)
1973 return False 1974 return False
1974 1975
1975 if os.path.exists(tmpPath): 1976 if os.path.exists(tmpPath):
1976 if curlret == 0 and self._IsValidBundle(tmpPath, quiet): 1977 if curlret == 0 and self._IsValidBundle(tmpPath, quiet):
@@ -1994,6 +1995,7 @@ class Project(object):
1994 except OSError: 1995 except OSError:
1995 return False 1996 return False
1996 1997
1998 @contextlib.contextmanager
1997 def _GetBundleCookieFile(self, url): 1999 def _GetBundleCookieFile(self, url):
1998 if url.startswith('persistent-'): 2000 if url.startswith('persistent-'):
1999 try: 2001 try:
@@ -2001,27 +2003,31 @@ class Project(object):
2001 ['git-remote-persistent-https', '-print_config', url], 2003 ['git-remote-persistent-https', '-print_config', url],
2002 stdin=subprocess.PIPE, stdout=subprocess.PIPE, 2004 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2003 stderr=subprocess.PIPE) 2005 stderr=subprocess.PIPE)
2004 p.stdin.close() # Tell subprocess it's ok to close. 2006 try:
2005 prefix = 'http.cookiefile=' 2007 prefix = 'http.cookiefile='
2006 cookiefile = None 2008 cookiefile = None
2007 for line in p.stdout: 2009 for line in p.stdout:
2008 line = line.strip() 2010 line = line.strip()
2009 if line.startswith(prefix): 2011 if line.startswith(prefix):
2010 cookiefile = line[len(prefix):] 2012 cookiefile = line[len(prefix):]
2011 break 2013 break
2012 if p.wait(): 2014 # Leave subprocess open, as cookie file may be transient.
2013 err_msg = p.stderr.read() 2015 if cookiefile:
2014 if ' -print_config' in err_msg: 2016 yield cookiefile
2015 pass # Persistent proxy doesn't support -print_config. 2017 return
2016 else: 2018 finally:
2017 print(err_msg, file=sys.stderr) 2019 p.stdin.close()
2018 if cookiefile: 2020 if p.wait():
2019 return cookiefile 2021 err_msg = p.stderr.read()
2022 if ' -print_config' in err_msg:
2023 pass # Persistent proxy doesn't support -print_config.
2024 else:
2025 print(err_msg, file=sys.stderr)
2020 except OSError as e: 2026 except OSError as e:
2021 if e.errno == errno.ENOENT: 2027 if e.errno == errno.ENOENT:
2022 pass # No persistent proxy. 2028 pass # No persistent proxy.
2023 raise 2029 raise
2024 return GitConfig.ForUser().GetString('http.cookiefile') 2030 yield GitConfig.ForUser().GetString('http.cookiefile')
2025 2031
2026 def _Checkout(self, rev, quiet=False): 2032 def _Checkout(self, rev, quiet=False):
2027 cmd = ['checkout'] 2033 cmd = ['checkout']