diff options
author | Dave Borowitz <dborowitz@google.com> | 2015-01-02 11:12:54 -0800 |
---|---|---|
committer | Dave Borowitz <dborowitz@google.com> | 2015-01-02 13:57:13 -0800 |
commit | 137d0131bf35b01db0d49e1d9720bbc526232c61 (patch) | |
tree | 116b3503d8b9c44a7c95311121bd3c577013c5b6 /project.py | |
parent | 42e679b9f63086dc1a27aed2d99deb3c1da428fc (diff) | |
download | git-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.py | 88 |
1 files changed, 47 insertions, 41 deletions
@@ -13,7 +13,7 @@ | |||
13 | # limitations under the License. | 13 | # limitations under the License. |
14 | 14 | ||
15 | from __future__ import print_function | 15 | from __future__ import print_function |
16 | import traceback | 16 | import contextlib |
17 | import errno | 17 | import errno |
18 | import filecmp | 18 | import filecmp |
19 | import os | 19 | import os |
@@ -26,6 +26,7 @@ import sys | |||
26 | import tarfile | 26 | import tarfile |
27 | import tempfile | 27 | import tempfile |
28 | import time | 28 | import time |
29 | import traceback | ||
29 | 30 | ||
30 | from color import Coloring | 31 | from color import Coloring |
31 | from git_command import GitCommand, git_require | 32 | from 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'] |