summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--git_config.py39
-rw-r--r--project.py39
-rw-r--r--subcmds/sync.py105
3 files changed, 145 insertions, 38 deletions
diff --git a/git_config.py b/git_config.py
index 8ded7c25..0379181a 100644
--- a/git_config.py
+++ b/git_config.py
@@ -15,6 +15,8 @@
15 15
16from __future__ import print_function 16from __future__ import print_function
17 17
18import contextlib
19import errno
18import json 20import json
19import os 21import os
20import re 22import re
@@ -502,6 +504,43 @@ def GetSchemeFromUrl(url):
502 return m.group(1) 504 return m.group(1)
503 return None 505 return None
504 506
507@contextlib.contextmanager
508def GetUrlCookieFile(url, quiet):
509 if url.startswith('persistent-'):
510 try:
511 p = subprocess.Popen(
512 ['git-remote-persistent-https', '-print_config', url],
513 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
514 stderr=subprocess.PIPE)
515 try:
516 cookieprefix = 'http.cookiefile='
517 proxyprefix = 'http.proxy='
518 cookiefile = None
519 proxy = None
520 for line in p.stdout:
521 line = line.strip()
522 if line.startswith(cookieprefix):
523 cookiefile = line[len(cookieprefix):]
524 if line.startswith(proxyprefix):
525 proxy = line[len(proxyprefix):]
526 # Leave subprocess open, as cookie file may be transient.
527 if cookiefile or proxy:
528 yield cookiefile, proxy
529 return
530 finally:
531 p.stdin.close()
532 if p.wait():
533 err_msg = p.stderr.read()
534 if ' -print_config' in err_msg:
535 pass # Persistent proxy doesn't support -print_config.
536 elif not quiet:
537 print(err_msg, file=sys.stderr)
538 except OSError as e:
539 if e.errno == errno.ENOENT:
540 pass # No persistent proxy.
541 raise
542 yield GitConfig.ForUser().GetString('http.cookiefile'), None
543
505def _preconnect(url): 544def _preconnect(url):
506 m = URI_ALL.match(url) 545 m = URI_ALL.match(url)
507 if m: 546 if m:
diff --git a/project.py b/project.py
index a117f4df..c32c1f52 100644
--- a/project.py
+++ b/project.py
@@ -13,7 +13,6 @@
13# limitations under the License. 13# limitations under the License.
14 14
15from __future__ import print_function 15from __future__ import print_function
16import contextlib
17import errno 16import errno
18import filecmp 17import filecmp
19import glob 18import glob
@@ -31,7 +30,7 @@ import traceback
31 30
32from color import Coloring 31from color import Coloring
33from git_command import GitCommand, git_require 32from git_command import GitCommand, git_require
34from git_config import GitConfig, IsId, GetSchemeFromUrl, ID_RE 33from git_config import GitConfig, IsId, GetSchemeFromUrl, GetUrlCookieFile, ID_RE
35from error import GitError, HookError, UploadError, DownloadError 34from error import GitError, HookError, UploadError, DownloadError
36from error import ManifestInvalidRevisionError 35from error import ManifestInvalidRevisionError
37from error import NoManifestException 36from error import NoManifestException
@@ -2030,7 +2029,7 @@ class Project(object):
2030 os.remove(tmpPath) 2029 os.remove(tmpPath)
2031 if 'http_proxy' in os.environ and 'darwin' == sys.platform: 2030 if 'http_proxy' in os.environ and 'darwin' == sys.platform:
2032 cmd += ['--proxy', os.environ['http_proxy']] 2031 cmd += ['--proxy', os.environ['http_proxy']]
2033 with self._GetBundleCookieFile(srcUrl, quiet) as cookiefile: 2032 with GetUrlCookieFile(srcUrl, quiet) as (cookiefile, proxy):
2034 if cookiefile: 2033 if cookiefile:
2035 cmd += ['--cookie', cookiefile, '--cookie-jar', cookiefile] 2034 cmd += ['--cookie', cookiefile, '--cookie-jar', cookiefile]
2036 if srcUrl.startswith('persistent-'): 2035 if srcUrl.startswith('persistent-'):
@@ -2078,40 +2077,6 @@ class Project(object):
2078 except OSError: 2077 except OSError:
2079 return False 2078 return False
2080 2079
2081 @contextlib.contextmanager
2082 def _GetBundleCookieFile(self, url, quiet):
2083 if url.startswith('persistent-'):
2084 try:
2085 p = subprocess.Popen(
2086 ['git-remote-persistent-https', '-print_config', url],
2087 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2088 stderr=subprocess.PIPE)
2089 try:
2090 prefix = 'http.cookiefile='
2091 cookiefile = None
2092 for line in p.stdout:
2093 line = line.strip()
2094 if line.startswith(prefix):
2095 cookiefile = line[len(prefix):]
2096 break
2097 # Leave subprocess open, as cookie file may be transient.
2098 if cookiefile:
2099 yield cookiefile
2100 return
2101 finally:
2102 p.stdin.close()
2103 if p.wait():
2104 err_msg = p.stderr.read()
2105 if ' -print_config' in err_msg:
2106 pass # Persistent proxy doesn't support -print_config.
2107 elif not quiet:
2108 print(err_msg, file=sys.stderr)
2109 except OSError as e:
2110 if e.errno == errno.ENOENT:
2111 pass # No persistent proxy.
2112 raise
2113 yield GitConfig.ForUser().GetString('http.cookiefile')
2114
2115 def _Checkout(self, rev, quiet=False): 2080 def _Checkout(self, rev, quiet=False):
2116 cmd = ['checkout'] 2081 cmd = ['checkout']
2117 if quiet: 2082 if quiet:
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 43d450be..ed8622c1 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -23,18 +23,26 @@ import shutil
23import socket 23import socket
24import subprocess 24import subprocess
25import sys 25import sys
26import tempfile
26import time 27import time
27 28
28from pyversion import is_python3 29from pyversion import is_python3
29if is_python3(): 30if is_python3():
31 import http.cookiejar as cookielib
32 import urllib.error
30 import urllib.parse 33 import urllib.parse
34 import urllib.request
31 import xmlrpc.client 35 import xmlrpc.client
32else: 36else:
37 import cookielib
33 import imp 38 import imp
39 import urllib2
34 import urlparse 40 import urlparse
35 import xmlrpclib 41 import xmlrpclib
36 urllib = imp.new_module('urllib') 42 urllib = imp.new_module('urllib')
43 urllib.error = urllib2
37 urllib.parse = urlparse 44 urllib.parse = urlparse
45 urllib.request = urllib2
38 xmlrpc = imp.new_module('xmlrpc') 46 xmlrpc = imp.new_module('xmlrpc')
39 xmlrpc.client = xmlrpclib 47 xmlrpc.client = xmlrpclib
40 48
@@ -57,6 +65,7 @@ except ImportError:
57 multiprocessing = None 65 multiprocessing = None
58 66
59from git_command import GIT, git_require 67from git_command import GIT, git_require
68from git_config import GetSchemeFromUrl, GetUrlCookieFile
60from git_refs import R_HEADS, HEAD 69from git_refs import R_HEADS, HEAD
61from project import Project 70from project import Project
62from project import RemoteSpec 71from project import RemoteSpec
@@ -575,8 +584,12 @@ later is required to fix a server side protocol bug.
575 (username, password), 584 (username, password),
576 1) 585 1)
577 586
587 transport = PersistentTransport(manifest_server)
588 if manifest_server.startswith('persistent-'):
589 manifest_server = manifest_server[len('persistent-'):]
590
578 try: 591 try:
579 server = xmlrpc.client.Server(manifest_server) 592 server = xmlrpc.client.Server(manifest_server, transport=transport)
580 if opt.smart_sync: 593 if opt.smart_sync:
581 p = self.manifest.manifestProject 594 p = self.manifest.manifestProject
582 b = p.GetBranch(p.CurrentBranch) 595 b = p.GetBranch(p.CurrentBranch)
@@ -850,3 +863,93 @@ class _FetchTimes(object):
850 os.remove(self._path) 863 os.remove(self._path)
851 except OSError: 864 except OSError:
852 pass 865 pass
866
867# This is a replacement for xmlrpc.client.Transport using urllib2
868# and supporting persistent-http[s]. It cannot change hosts from
869# request to request like the normal transport, the real url
870# is passed during initialization.
871class PersistentTransport(xmlrpc.client.Transport):
872 def __init__(self, orig_host):
873 self.orig_host = orig_host
874
875 def request(self, host, handler, request_body, verbose=False):
876 with GetUrlCookieFile(self.orig_host, not verbose) as (cookiefile, proxy):
877 # Python doesn't understand cookies with the #HttpOnly_ prefix
878 # Since we're only using them for HTTP, copy the file temporarily,
879 # stripping those prefixes away.
880 tmpcookiefile = tempfile.NamedTemporaryFile()
881 try:
882 with open(cookiefile) as f:
883 for line in f:
884 if line.startswith("#HttpOnly_"):
885 line = line[len("#HttpOnly_"):]
886 tmpcookiefile.write(line)
887 tmpcookiefile.flush()
888
889 cookiejar = cookielib.MozillaCookieJar(tmpcookiefile.name)
890 cookiejar.load()
891 finally:
892 tmpcookiefile.close()
893
894 proxyhandler = urllib.request.ProxyHandler
895 if proxy:
896 proxyhandler = urllib.request.ProxyHandler({
897 "http": proxy,
898 "https": proxy })
899
900 opener = urllib.request.build_opener(
901 urllib.request.HTTPCookieProcessor(cookiejar),
902 proxyhandler)
903
904 url = urllib.parse.urljoin(self.orig_host, handler)
905 parse_results = urllib.parse.urlparse(url)
906
907 scheme = parse_results.scheme
908 if scheme == 'persistent-http':
909 scheme = 'http'
910 if scheme == 'persistent-https':
911 # If we're proxying through persistent-https, use http. The
912 # proxy itself will do the https.
913 if proxy:
914 scheme = 'http'
915 else:
916 scheme = 'https'
917
918 # Parse out any authentication information using the base class
919 host, extra_headers, _ = self.get_host_info(parse_results.netloc)
920
921 url = urllib.parse.urlunparse((
922 scheme,
923 host,
924 parse_results.path,
925 parse_results.params,
926 parse_results.query,
927 parse_results.fragment))
928
929 request = urllib.request.Request(url, request_body)
930 if extra_headers is not None:
931 for (name, header) in extra_headers:
932 request.add_header(name, header)
933 request.add_header('Content-Type', 'text/xml')
934 try:
935 response = opener.open(request)
936 except urllib.error.HTTPError as e:
937 if e.code == 501:
938 # We may have been redirected through a login process
939 # but our POST turned into a GET. Retry.
940 response = opener.open(request)
941 else:
942 raise
943
944 p, u = xmlrpc.client.getparser()
945 while 1:
946 data = response.read(1024)
947 if not data:
948 break
949 p.feed(data)
950 p.close()
951 return u.close()
952
953 def close(self):
954 pass
955