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'] |
