summaryrefslogtreecommitdiffstats
path: root/subcmds/sync.py
diff options
context:
space:
mode:
Diffstat (limited to 'subcmds/sync.py')
-rw-r--r--subcmds/sync.py163
1 files changed, 153 insertions, 10 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 43d450be..a99d7e74 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,7 +65,9 @@ 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 GetUrlCookieFile
60from git_refs import R_HEADS, HEAD 69from git_refs import R_HEADS, HEAD
70import gitc_utils
61from project import Project 71from project import Project
62from project import RemoteSpec 72from project import RemoteSpec
63from command import Command, MirrorSafeCommand 73from command import Command, MirrorSafeCommand
@@ -65,6 +75,7 @@ from error import RepoChangedException, GitError, ManifestParseError
65from project import SyncBuffer 75from project import SyncBuffer
66from progress import Progress 76from progress import Progress
67from wrapper import Wrapper 77from wrapper import Wrapper
78from manifest_xml import GitcManifest
68 79
69_ONE_DAY_S = 24 * 60 * 60 80_ONE_DAY_S = 24 * 60 * 60
70 81
@@ -554,19 +565,18 @@ later is required to fix a server side protocol bug.
554 try: 565 try:
555 info = netrc.netrc() 566 info = netrc.netrc()
556 except IOError: 567 except IOError:
557 print('.netrc file does not exist or could not be opened', 568 # .netrc file does not exist or could not be opened
558 file=sys.stderr) 569 pass
559 else: 570 else:
560 try: 571 try:
561 parse_result = urllib.parse.urlparse(manifest_server) 572 parse_result = urllib.parse.urlparse(manifest_server)
562 if parse_result.hostname: 573 if parse_result.hostname:
563 username, _account, password = \ 574 auth = info.authenticators(parse_result.hostname)
564 info.authenticators(parse_result.hostname) 575 if auth:
565 except TypeError: 576 username, _account, password = auth
566 # TypeError is raised when the given hostname is not present 577 else:
567 # in the .netrc file. 578 print('No credentials found for %s in .netrc'
568 print('No credentials found for %s in .netrc' 579 % parse_result.hostname, file=sys.stderr)
569 % parse_result.hostname, file=sys.stderr)
570 except netrc.NetrcParseError as e: 580 except netrc.NetrcParseError as e:
571 print('Error parsing .netrc file: %s' % e, file=sys.stderr) 581 print('Error parsing .netrc file: %s' % e, file=sys.stderr)
572 582
@@ -575,8 +585,12 @@ later is required to fix a server side protocol bug.
575 (username, password), 585 (username, password),
576 1) 586 1)
577 587
588 transport = PersistentTransport(manifest_server)
589 if manifest_server.startswith('persistent-'):
590 manifest_server = manifest_server[len('persistent-'):]
591
578 try: 592 try:
579 server = xmlrpc.client.Server(manifest_server) 593 server = xmlrpc.client.Server(manifest_server, transport=transport)
580 if opt.smart_sync: 594 if opt.smart_sync:
581 p = self.manifest.manifestProject 595 p = self.manifest.manifestProject
582 b = p.GetBranch(p.CurrentBranch) 596 b = p.GetBranch(p.CurrentBranch)
@@ -656,6 +670,42 @@ later is required to fix a server side protocol bug.
656 self._ReloadManifest(manifest_name) 670 self._ReloadManifest(manifest_name)
657 if opt.jobs is None: 671 if opt.jobs is None:
658 self.jobs = self.manifest.default.sync_j 672 self.jobs = self.manifest.default.sync_j
673
674 if self.gitc_manifest:
675 gitc_manifest_projects = self.GetProjects(args,
676 missing_ok=True)
677 gitc_projects = []
678 opened_projects = []
679 for project in gitc_manifest_projects:
680 if project.relpath in self.gitc_manifest.paths and \
681 self.gitc_manifest.paths[project.relpath].old_revision:
682 opened_projects.append(project.relpath)
683 else:
684 gitc_projects.append(project.relpath)
685
686 if not args:
687 gitc_projects = None
688
689 if gitc_projects != [] and not opt.local_only:
690 print('Updating GITC client: %s' % self.gitc_manifest.gitc_client_name)
691 manifest = GitcManifest(self.repodir, self.gitc_manifest.gitc_client_name)
692 if manifest_name:
693 manifest.Override(manifest_name)
694 else:
695 manifest.Override(self.manifest.manifestFile)
696 gitc_utils.generate_gitc_manifest(self.gitc_manifest,
697 manifest,
698 gitc_projects)
699 print('GITC client successfully synced.')
700
701 # The opened projects need to be synced as normal, therefore we
702 # generate a new args list to represent the opened projects.
703 # TODO: make this more reliable -- if there's a project name/path overlap,
704 # this may choose the wrong project.
705 args = [os.path.relpath(self.manifest.paths[p].worktree, os.getcwd())
706 for p in opened_projects]
707 if not args:
708 return
659 all_projects = self.GetProjects(args, 709 all_projects = self.GetProjects(args,
660 missing_ok=True, 710 missing_ok=True,
661 submodules_ok=opt.fetch_submodules) 711 submodules_ok=opt.fetch_submodules)
@@ -850,3 +900,96 @@ class _FetchTimes(object):
850 os.remove(self._path) 900 os.remove(self._path)
851 except OSError: 901 except OSError:
852 pass 902 pass
903
904# This is a replacement for xmlrpc.client.Transport using urllib2
905# and supporting persistent-http[s]. It cannot change hosts from
906# request to request like the normal transport, the real url
907# is passed during initialization.
908class PersistentTransport(xmlrpc.client.Transport):
909 def __init__(self, orig_host):
910 self.orig_host = orig_host
911
912 def request(self, host, handler, request_body, verbose=False):
913 with GetUrlCookieFile(self.orig_host, not verbose) as (cookiefile, proxy):
914 # Python doesn't understand cookies with the #HttpOnly_ prefix
915 # Since we're only using them for HTTP, copy the file temporarily,
916 # stripping those prefixes away.
917 if cookiefile:
918 tmpcookiefile = tempfile.NamedTemporaryFile()
919 try:
920 with open(cookiefile) as f:
921 for line in f:
922 if line.startswith("#HttpOnly_"):
923 line = line[len("#HttpOnly_"):]
924 tmpcookiefile.write(line)
925 tmpcookiefile.flush()
926
927 cookiejar = cookielib.MozillaCookieJar(tmpcookiefile.name)
928 cookiejar.load()
929 finally:
930 tmpcookiefile.close()
931 else:
932 cookiejar = cookielib.CookieJar()
933
934 proxyhandler = urllib.request.ProxyHandler
935 if proxy:
936 proxyhandler = urllib.request.ProxyHandler({
937 "http": proxy,
938 "https": proxy })
939
940 opener = urllib.request.build_opener(
941 urllib.request.HTTPCookieProcessor(cookiejar),
942 proxyhandler)
943
944 url = urllib.parse.urljoin(self.orig_host, handler)
945 parse_results = urllib.parse.urlparse(url)
946
947 scheme = parse_results.scheme
948 if scheme == 'persistent-http':
949 scheme = 'http'
950 if scheme == 'persistent-https':
951 # If we're proxying through persistent-https, use http. The
952 # proxy itself will do the https.
953 if proxy:
954 scheme = 'http'
955 else:
956 scheme = 'https'
957
958 # Parse out any authentication information using the base class
959 host, extra_headers, _ = self.get_host_info(parse_results.netloc)
960
961 url = urllib.parse.urlunparse((
962 scheme,
963 host,
964 parse_results.path,
965 parse_results.params,
966 parse_results.query,
967 parse_results.fragment))
968
969 request = urllib.request.Request(url, request_body)
970 if extra_headers is not None:
971 for (name, header) in extra_headers:
972 request.add_header(name, header)
973 request.add_header('Content-Type', 'text/xml')
974 try:
975 response = opener.open(request)
976 except urllib.error.HTTPError as e:
977 if e.code == 501:
978 # We may have been redirected through a login process
979 # but our POST turned into a GET. Retry.
980 response = opener.open(request)
981 else:
982 raise
983
984 p, u = xmlrpc.client.getparser()
985 while 1:
986 data = response.read(1024)
987 if not data:
988 break
989 p.feed(data)
990 p.close()
991 return u.close()
992
993 def close(self):
994 pass
995