blob: b1b6a6ef7f8850c1912bd5a1dc01b8f008660f24 [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001# Copyright (C) 2008 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Mike Frysingeracf63b22019-06-13 02:24:21 -040015import http.cookiejar as cookielib
Anthony King85b24ac2014-05-06 15:57:48 +010016import json
David Pursehouse86d973d2012-08-24 10:21:02 +090017import netrc
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -070018from optparse import SUPPRESS_HELP
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070019import os
20import re
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070021import socket
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070022import subprocess
23import sys
Dan Willemsen0745bb22015-08-17 13:41:45 -070024import tempfile
Shawn O. Pearcef6906872009-04-18 10:49:00 -070025import time
Mike Frysingeracf63b22019-06-13 02:24:21 -040026import urllib.error
27import urllib.parse
28import urllib.request
29import xmlrpc.client
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070030
Roy Lee18afd7f2010-05-09 04:32:08 +080031try:
32 import threading as _threading
33except ImportError:
34 import dummy_threading as _threading
35
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -070036try:
37 import resource
David Pursehouse819827a2020-02-12 15:20:19 +090038
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -070039 def _rlimit_nofile():
40 return resource.getrlimit(resource.RLIMIT_NOFILE)
41except ImportError:
42 def _rlimit_nofile():
43 return (256, 256)
44
Dave Borowitz18857212012-10-23 17:02:59 -070045try:
46 import multiprocessing
47except ImportError:
48 multiprocessing = None
49
David Rileye0684ad2017-04-05 00:02:59 -070050import event_log
Dave Borowitze2152672012-10-31 12:24:38 -070051from git_command import GIT, git_require
David Pursehouseba7bc732015-08-20 16:55:42 +090052from git_config import GetUrlCookieFile
David Pursehoused94aaef2012-09-07 09:52:04 +090053from git_refs import R_HEADS, HEAD
Raman Tenneti6a872c92021-01-14 19:17:50 -080054import git_superproject
Simran Basibdb52712015-08-10 13:23:23 -070055import gitc_utils
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070056from project import Project
57from project import RemoteSpec
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080058from command import Command, MirrorSafeCommand
Raman Tenneti1fd7bc22021-02-04 14:39:38 -080059from error import RepoChangedException, GitError, ManifestParseError
Renaud Paquaya65adf72016-11-03 10:37:53 -070060import platform_utils
Shawn O. Pearce350cde42009-04-16 11:21:18 -070061from project import SyncBuffer
Shawn O. Pearce68194f42009-04-10 16:48:52 -070062from progress import Progress
Conley Owens094cdbe2014-01-30 15:09:59 -080063from wrapper import Wrapper
Dan Willemsen5ea32d12015-09-08 13:27:20 -070064from manifest_xml import GitcManifest
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070065
Dave Borowitz67700e92012-10-23 15:00:54 -070066_ONE_DAY_S = 24 * 60 * 60
67
David Pursehouse819827a2020-02-12 15:20:19 +090068
Doug Andersonfc06ced2011-03-16 15:49:18 -070069class _FetchError(Exception):
70 """Internal error thrown in _FetchHelper() when we don't want stack trace."""
Doug Andersonfc06ced2011-03-16 15:49:18 -070071
David Pursehouse819827a2020-02-12 15:20:19 +090072
Xin Li745be2e2019-06-03 11:24:30 -070073class _CheckoutError(Exception):
74 """Internal error thrown in _CheckoutOne() when we don't want stack trace."""
75
David Pursehouse819827a2020-02-12 15:20:19 +090076
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080077class Sync(Command, MirrorSafeCommand):
Roy Lee18afd7f2010-05-09 04:32:08 +080078 jobs = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070079 common = True
80 helpSummary = "Update working tree to the latest revision"
81 helpUsage = """
82%prog [<project>...]
83"""
84 helpDescription = """
85The '%prog' command synchronizes local project directories
86with the remote repositories specified in the manifest. If a local
87project does not yet exist, it will clone a new local directory from
88the remote repository and set up tracking branches as specified in
89the manifest. If the local project already exists, '%prog'
90will update the remote branches and rebase any new local changes
91on top of the new remote changes.
92
93'%prog' will synchronize all projects listed at the command
94line. Projects can be specified either by name, or by a relative
95or absolute path to the project's local directory. If no projects
96are specified, '%prog' will synchronize all projects listed in
97the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070098
99The -d/--detach option can be used to switch specified projects
100back to the manifest revision. This option is especially helpful
101if the project is currently on a topic branch, but the manifest
102revision is temporarily needed.
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700103
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700104The -s/--smart-sync option can be used to sync to a known good
105build as specified by the manifest-server element in the current
Victor Boivie08c880d2011-04-19 10:32:52 +0200106manifest. The -t/--smart-tag option is similar and allows you to
107specify a custom tag/label.
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700108
David Pursehousecf76b1b2012-09-14 10:31:42 +0900109The -u/--manifest-server-username and -p/--manifest-server-password
110options can be used to specify a username and password to authenticate
111with the manifest server when using the -s or -t option.
112
113If -u and -p are not specified when using the -s or -t option, '%prog'
114will attempt to read authentication credentials for the manifest server
115from the user's .netrc file.
116
117'%prog' will not use authentication credentials from -u/-p or .netrc
118if the manifest server specified in the manifest file already includes
119credentials.
120
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400121By default, all projects will be synced. The --fail-fast option can be used
Mike Frysinger7ae210a2020-05-24 14:56:52 -0400122to halt syncing as soon as possible when the first project fails to sync.
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500123
Kevin Degiabaa7f32014-11-12 11:27:45 -0700124The --force-sync option can be used to overwrite existing git
125directories if they have previously been linked to a different
Roger Shimizuac29ac32020-06-06 02:33:40 +0900126object directory. WARNING: This may cause data to be lost since
Kevin Degiabaa7f32014-11-12 11:27:45 -0700127refs may be removed when overwriting.
128
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500129The --force-remove-dirty option can be used to remove previously used
130projects with uncommitted changes. WARNING: This may cause data to be
131lost since uncommitted changes may be removed with projects that no longer
132exist in the manifest.
133
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700134The --no-clone-bundle option disables any attempt to use
135$URL/clone.bundle to bootstrap a new Git repository from a
136resumeable bundle file on a content delivery network. This
137may be necessary if there are problems with the local Python
138HTTP client or proxy configuration, but the Git binary works.
139
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800140The --fetch-submodules option enables fetching Git submodules
141of a project from server.
142
David Pursehousef2fad612015-01-29 14:36:28 +0900143The -c/--current-branch option can be used to only fetch objects that
144are on the branch specified by a project's revision.
145
David Pursehouseb1553542014-09-04 21:28:09 +0900146The --optimized-fetch option can be used to only fetch projects that
147are fixed to a sha1 revision if the sha1 revision does not already
148exist locally.
149
David Pursehouse74cfd272015-10-14 10:50:15 +0900150The --prune option can be used to remove any refs that no longer
151exist on the remote.
152
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400153# SSH Connections
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700154
155If at least one project remote URL uses an SSH connection (ssh://,
156git+ssh://, or user@host:path syntax) repo will automatically
157enable the SSH ControlMaster option when connecting to that host.
158This feature permits other projects in the same '%prog' session to
159reuse the same SSH tunnel, saving connection setup overheads.
160
161To disable this behavior on UNIX platforms, set the GIT_SSH
162environment variable to 'ssh'. For example:
163
164 export GIT_SSH=ssh
165 %prog
166
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400167# Compatibility
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700168
169This feature is automatically disabled on Windows, due to the lack
170of UNIX domain socket support.
171
172This feature is not compatible with url.insteadof rewrites in the
173user's ~/.gitconfig. '%prog' is currently not able to perform the
174rewrite early enough to establish the ControlMaster tunnel.
175
176If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or
177later is required to fix a server side protocol bug.
178
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700179"""
Mike Frysinger6a2400a2021-02-16 01:43:31 -0500180 PARALLEL_JOBS = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700181
Nico Sallembien6623b212010-05-11 12:57:01 -0700182 def _Options(self, p, show_smart=True):
Torne (Richard Coles)7bdbde72012-12-05 10:58:06 +0000183 try:
Mike Frysinger6a2400a2021-02-16 01:43:31 -0500184 self.PARALLEL_JOBS = self.manifest.default.sync_j
Torne (Richard Coles)7bdbde72012-12-05 10:58:06 +0000185 except ManifestParseError:
Mike Frysinger6a2400a2021-02-16 01:43:31 -0500186 pass
187 super()._Options(p)
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700188
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500189 p.add_option('-f', '--force-broken',
Stefan Müller-Klieser46702ed2019-08-30 10:20:15 +0200190 dest='force_broken', action='store_true',
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400191 help='obsolete option (to be deleted in the future)')
192 p.add_option('--fail-fast',
193 dest='fail_fast', action='store_true',
194 help='stop syncing after first error is hit')
Kevin Degiabaa7f32014-11-12 11:27:45 -0700195 p.add_option('--force-sync',
196 dest='force_sync', action='store_true',
197 help="overwrite an existing git directory if it needs to "
198 "point to a different object directory. WARNING: this "
199 "may cause loss of data")
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500200 p.add_option('--force-remove-dirty',
201 dest='force_remove_dirty', action='store_true',
202 help="force remove projects with uncommitted modifications if "
203 "projects no longer exist in the manifest. "
204 "WARNING: this may cause loss of data")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900205 p.add_option('-l', '--local-only',
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700206 dest='local_only', action='store_true',
207 help="only update working tree, don't fetch")
David Pursehouse54a4e602020-02-12 14:31:05 +0900208 p.add_option('--no-manifest-update', '--nmu',
Fredrik de Grootcc960972019-11-22 09:04:31 +0100209 dest='mp_update', action='store_false', default='true',
210 help='use the existing manifest checkout as-is. '
211 '(do not update to the latest revision)')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900212 p.add_option('-n', '--network-only',
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700213 dest='network_only', action='store_true',
214 help="fetch only, don't update working tree")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900215 p.add_option('-d', '--detach',
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700216 dest='detach_head', action='store_true',
217 help='detach projects back to manifest revision')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900218 p.add_option('-c', '--current-branch',
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700219 dest='current_branch_only', action='store_true',
220 help='fetch only current branch from server')
Mike Frysinger521d01b2020-02-17 01:51:49 -0500221 p.add_option('-v', '--verbose',
222 dest='output_mode', action='store_true',
223 help='show all sync output')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900224 p.add_option('-q', '--quiet',
Mike Frysinger521d01b2020-02-17 01:51:49 -0500225 dest='output_mode', action='store_false',
226 help='only show errors')
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500227 p.add_option('-m', '--manifest-name',
228 dest='manifest_name',
229 help='temporary manifest to use for this sync', metavar='NAME.xml')
Xin Lid79a4bc2020-05-20 16:03:45 -0700230 p.add_option('--clone-bundle', action='store_true',
231 help='enable use of /clone.bundle on HTTP/HTTPS')
232 p.add_option('--no-clone-bundle', dest='clone_bundle', action='store_false',
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700233 help='disable use of /clone.bundle on HTTP/HTTPS')
Conley Owens8d070cf2012-11-06 13:14:31 -0800234 p.add_option('-u', '--manifest-server-username', action='store',
235 dest='manifest_server_username',
236 help='username to authenticate with the manifest server')
237 p.add_option('-p', '--manifest-server-password', action='store',
238 dest='manifest_server_password',
239 help='password to authenticate with the manifest server')
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800240 p.add_option('--fetch-submodules',
241 dest='fetch_submodules', action='store_true',
242 help='fetch submodules from server')
Raman Tenneti6a872c92021-01-14 19:17:50 -0800243 p.add_option('--use-superproject', action='store_true',
244 help='use the manifest superproject to sync projects')
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700245 p.add_option('--no-tags',
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500246 dest='tags', default=True, action='store_false',
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700247 help="don't fetch tags")
David Pursehouseb1553542014-09-04 21:28:09 +0900248 p.add_option('--optimized-fetch',
249 dest='optimized_fetch', action='store_true',
250 help='only fetch projects fixed to sha1 if revision does not exist locally')
George Engelbrecht9bc283e2020-04-02 12:36:09 -0600251 p.add_option('--retry-fetches',
252 default=0, action='store', type='int',
253 help='number of times to retry fetches on transient errors')
David Pursehouse74cfd272015-10-14 10:50:15 +0900254 p.add_option('--prune', dest='prune', action='store_true',
255 help='delete refs that no longer exist on the remote')
Nico Sallembien6623b212010-05-11 12:57:01 -0700256 if show_smart:
257 p.add_option('-s', '--smart-sync',
258 dest='smart_sync', action='store_true',
David Pursehouse79fba682016-04-13 18:03:00 +0900259 help='smart sync using manifest from the latest known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200260 p.add_option('-t', '--smart-tag',
261 dest='smart_tag', action='store',
262 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700263
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700264 g = p.add_option_group('repo Version options')
265 g.add_option('--no-repo-verify',
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500266 dest='repo_verify', default=True, action='store_false',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700267 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700268 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800269 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700270 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700271
Raman Tenneti8d43dea2021-02-07 16:30:27 -0800272 def _GetBranch(self):
273 """Returns the branch name for getting the approved manifest."""
274 p = self.manifest.manifestProject
275 b = p.GetBranch(p.CurrentBranch)
276 branch = b.merge
277 if branch.startswith(R_HEADS):
278 branch = branch[len(R_HEADS):]
279 return branch
280
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800281 def _UpdateProjectsRevisionId(self, opt, args):
282 """Update revisionId of every project with the SHA from superproject.
283
284 This function updates each project's revisionId with SHA from superproject.
285 It writes the updated manifest into a file and reloads the manifest from it.
286
287 Args:
288 opt: Program options returned from optparse. See _Options().
289 args: Arguments to pass to GetProjects. See the GetProjects
290 docstring for details.
291
292 Returns:
293 Returns path to the overriding manifest file.
294 """
Raman Tenneti21dce3d2021-02-09 00:26:31 -0800295 superproject = git_superproject.Superproject(self.manifest,
296 self.repodir)
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800297 all_projects = self.GetProjects(args,
298 missing_ok=True,
299 submodules_ok=opt.fetch_submodules)
Raman Tenneti21dce3d2021-02-09 00:26:31 -0800300 manifest_path = superproject.UpdateProjectsRevisionId(all_projects)
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800301 if not manifest_path:
302 print('error: Update of revsionId from superproject has failed',
303 file=sys.stderr)
304 sys.exit(1)
305 self._ReloadManifest(manifest_path)
306 return manifest_path
307
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500308 def _FetchProjectList(self, opt, projects, sem, *args, **kwargs):
Xin Li745be2e2019-06-03 11:24:30 -0700309 """Main function of the fetch threads.
Roy Lee18afd7f2010-05-09 04:32:08 +0800310
David James8d201162013-10-11 17:03:19 -0700311 Delegates most of the work to _FetchHelper.
312
313 Args:
314 opt: Program options returned from optparse. See _Options().
315 projects: Projects to fetch.
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500316 sem: We'll release() this semaphore when we exit so that another thread
317 can be started up.
David James89ece422014-01-09 18:51:58 -0800318 *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the
David James8d201162013-10-11 17:03:19 -0700319 _FetchHelper docstring for details.
320 """
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500321 try:
322 for project in projects:
323 success = self._FetchHelper(opt, project, *args, **kwargs)
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400324 if not success and opt.fail_fast:
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500325 break
326 finally:
327 sem.release()
David James8d201162013-10-11 17:03:19 -0700328
Xin Li745be2e2019-06-03 11:24:30 -0700329 def _FetchHelper(self, opt, project, lock, fetched, pm, err_event,
330 clone_filter):
David James8d201162013-10-11 17:03:19 -0700331 """Fetch git objects for a single project.
332
David Pursehousec1b86a22012-11-14 11:36:51 +0900333 Args:
334 opt: Program options returned from optparse. See _Options().
335 project: Project object for the project to fetch.
336 lock: Lock for accessing objects that are shared amongst multiple
337 _FetchHelper() threads.
338 fetched: set object that we will add project.gitdir to when we're done
339 (with our lock held).
340 pm: Instance of a Project object. We will call pm.update() (with our
341 lock held).
David Pursehousec1b86a22012-11-14 11:36:51 +0900342 err_event: We'll set this event in the case of an error (after printing
343 out info about the error).
Xin Li745be2e2019-06-03 11:24:30 -0700344 clone_filter: Filter for use in a partial clone.
David James8d201162013-10-11 17:03:19 -0700345
346 Returns:
347 Whether the fetch was successful.
David Pursehousec1b86a22012-11-14 11:36:51 +0900348 """
349 # We'll set to true once we've locked the lock.
350 did_lock = False
Doug Andersonfc06ced2011-03-16 15:49:18 -0700351
David Pursehousec1b86a22012-11-14 11:36:51 +0900352 # Encapsulate everything in a try/except/finally so that:
353 # - We always set err_event in the case of an exception.
David Pursehousec1b86a22012-11-14 11:36:51 +0900354 # - We always make sure we unlock the lock if we locked it.
David Rileye0684ad2017-04-05 00:02:59 -0700355 start = time.time()
356 success = False
Mike Frysingerfbb95a42021-02-23 17:34:35 -0500357 with lock:
358 pm.start(project.name)
David Pursehousec1b86a22012-11-14 11:36:51 +0900359 try:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700360 try:
David Pursehousec1b86a22012-11-14 11:36:51 +0900361 success = project.Sync_NetworkHalf(
David Pursehouseabdf7502020-02-12 14:58:39 +0900362 quiet=opt.quiet,
Mike Frysinger521d01b2020-02-17 01:51:49 -0500363 verbose=opt.verbose,
David Pursehouseabdf7502020-02-12 14:58:39 +0900364 current_branch_only=opt.current_branch_only,
365 force_sync=opt.force_sync,
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500366 clone_bundle=opt.clone_bundle,
367 tags=opt.tags, archive=self.manifest.IsArchive,
David Pursehouseabdf7502020-02-12 14:58:39 +0900368 optimized_fetch=opt.optimized_fetch,
George Engelbrecht9bc283e2020-04-02 12:36:09 -0600369 retry_fetches=opt.retry_fetches,
David Pursehouseabdf7502020-02-12 14:58:39 +0900370 prune=opt.prune,
371 clone_filter=clone_filter)
David Pursehousec1b86a22012-11-14 11:36:51 +0900372 self._fetch_times.Set(project, time.time() - start)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700373
David Pursehousec1b86a22012-11-14 11:36:51 +0900374 # Lock around all the rest of the code, since printing, updating a set
375 # and Progress.update() are not thread safe.
376 lock.acquire()
377 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700378
David Pursehousec1b86a22012-11-14 11:36:51 +0900379 if not success:
Hu Xiuyune9becc02015-11-25 15:52:26 +0800380 err_event.set()
Marc Herbertffb4b892017-04-04 22:03:53 -0700381 print('error: Cannot fetch %s from %s'
382 % (project.name, project.remote.url),
383 file=sys.stderr)
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400384 if opt.fail_fast:
David Pursehousec1b86a22012-11-14 11:36:51 +0900385 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700386
David Pursehousec1b86a22012-11-14 11:36:51 +0900387 fetched.add(project.gitdir)
David Pursehousec1b86a22012-11-14 11:36:51 +0900388 except _FetchError:
Hu Xiuyune9becc02015-11-25 15:52:26 +0800389 pass
Dan Sandlerc5cd4332015-07-31 09:37:53 -0400390 except Exception as e:
David Pursehouse42339d72020-02-12 14:37:15 +0900391 print('error: Cannot fetch %s (%s: %s)'
David Pursehouseabdf7502020-02-12 14:58:39 +0900392 % (project.name, type(e).__name__, str(e)), file=sys.stderr)
David Pursehousec1b86a22012-11-14 11:36:51 +0900393 err_event.set()
394 raise
395 finally:
Mike Frysingerfbb95a42021-02-23 17:34:35 -0500396 if not did_lock:
397 lock.acquire()
398 pm.finish(project.name)
399 lock.release()
David Rileye0684ad2017-04-05 00:02:59 -0700400 finish = time.time()
401 self.event_log.AddSync(project, event_log.TASK_SYNC_NETWORK,
402 start, finish, success)
Roy Lee18afd7f2010-05-09 04:32:08 +0800403
David James8d201162013-10-11 17:03:19 -0700404 return success
405
Mike Frysinger5a033082019-09-23 19:21:20 -0400406 def _Fetch(self, projects, opt, err_event):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700407 fetched = set()
David James89ece422014-01-09 18:51:58 -0800408 lock = _threading.Lock()
Mike Frysingerfbb95a42021-02-23 17:34:35 -0500409 pm = Progress('Fetching', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800410
David James89ece422014-01-09 18:51:58 -0800411 objdir_project_map = dict()
412 for project in projects:
413 objdir_project_map.setdefault(project.objdir, []).append(project)
David James8d201162013-10-11 17:03:19 -0700414
David James89ece422014-01-09 18:51:58 -0800415 threads = set()
416 sem = _threading.Semaphore(self.jobs)
David James89ece422014-01-09 18:51:58 -0800417 for project_list in objdir_project_map.values():
418 # Check for any errors before running any more tasks.
419 # ...we'll let existing threads finish, though.
Mike Frysingerbe24a542021-02-23 03:24:12 -0500420 if err_event.is_set() and opt.fail_fast:
David James89ece422014-01-09 18:51:58 -0800421 break
Doug Andersonfc06ced2011-03-16 15:49:18 -0700422
David James89ece422014-01-09 18:51:58 -0800423 sem.acquire()
424 kwargs = dict(opt=opt,
425 projects=project_list,
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500426 sem=sem,
David James89ece422014-01-09 18:51:58 -0800427 lock=lock,
428 fetched=fetched,
429 pm=pm,
Xin Li745be2e2019-06-03 11:24:30 -0700430 err_event=err_event,
431 clone_filter=self.manifest.CloneFilter)
David James89ece422014-01-09 18:51:58 -0800432 if self.jobs > 1:
David Pursehousee5913ae2020-02-12 13:56:59 +0900433 t = _threading.Thread(target=self._FetchProjectList,
434 kwargs=kwargs)
David 'Digit' Turnere2126652012-09-05 10:35:06 +0200435 # Ensure that Ctrl-C will not freeze the repo process.
436 t.daemon = True
Roy Lee18afd7f2010-05-09 04:32:08 +0800437 threads.add(t)
438 t.start()
David James89ece422014-01-09 18:51:58 -0800439 else:
440 self._FetchProjectList(**kwargs)
Roy Lee18afd7f2010-05-09 04:32:08 +0800441
David James89ece422014-01-09 18:51:58 -0800442 for t in threads:
443 t.join()
Roy Lee18afd7f2010-05-09 04:32:08 +0800444
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700445 pm.end()
Dave Borowitz67700e92012-10-23 15:00:54 -0700446 self._fetch_times.Save()
Dave Borowitz18857212012-10-23 17:02:59 -0700447
Julien Campergue335f5ef2013-10-16 11:02:35 +0200448 if not self.manifest.IsArchive:
Mike Frysinger5a033082019-09-23 19:21:20 -0400449 self._GCProjects(projects, opt, err_event)
Julien Campergue335f5ef2013-10-16 11:02:35 +0200450
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700451 return fetched
452
Xin Li745be2e2019-06-03 11:24:30 -0700453 def _CheckoutWorker(self, opt, sem, project, *args, **kwargs):
454 """Main function of the fetch threads.
455
456 Delegates most of the work to _CheckoutOne.
457
458 Args:
459 opt: Program options returned from optparse. See _Options().
460 projects: Projects to fetch.
461 sem: We'll release() this semaphore when we exit so that another thread
462 can be started up.
463 *args, **kwargs: Remaining arguments to pass to _CheckoutOne. See the
464 _CheckoutOne docstring for details.
465 """
466 try:
Mike Frysingera34186e2019-08-07 18:07:31 -0400467 return self._CheckoutOne(opt, project, *args, **kwargs)
Xin Li745be2e2019-06-03 11:24:30 -0700468 finally:
469 sem.release()
470
Vadim Bendeburydff91942019-11-06 11:05:00 -0800471 def _CheckoutOne(self, opt, project, lock, pm, err_event, err_results):
Xin Li745be2e2019-06-03 11:24:30 -0700472 """Checkout work tree for one project
473
474 Args:
475 opt: Program options returned from optparse. See _Options().
476 project: Project object for the project to checkout.
477 lock: Lock for accessing objects that are shared amongst multiple
478 _CheckoutWorker() threads.
479 pm: Instance of a Project object. We will call pm.update() (with our
480 lock held).
481 err_event: We'll set this event in the case of an error (after printing
482 out info about the error).
Vadim Bendeburydff91942019-11-06 11:05:00 -0800483 err_results: A list of strings, paths to git repos where checkout
484 failed.
Xin Li745be2e2019-06-03 11:24:30 -0700485
486 Returns:
487 Whether the fetch was successful.
488 """
489 # We'll set to true once we've locked the lock.
490 did_lock = False
491
Xin Li745be2e2019-06-03 11:24:30 -0700492 # Encapsulate everything in a try/except/finally so that:
493 # - We always set err_event in the case of an exception.
494 # - We always make sure we unlock the lock if we locked it.
495 start = time.time()
496 syncbuf = SyncBuffer(self.manifest.manifestProject.config,
497 detach_head=opt.detach_head)
498 success = False
Mike Frysingerfbb95a42021-02-23 17:34:35 -0500499 with lock:
500 pm.start(project.name)
Xin Li745be2e2019-06-03 11:24:30 -0700501 try:
502 try:
503 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
Xin Li745be2e2019-06-03 11:24:30 -0700504
505 # Lock around all the rest of the code, since printing, updating a set
506 # and Progress.update() are not thread safe.
507 lock.acquire()
Mike Frysinger3538dd22019-08-26 15:32:06 -0400508 success = syncbuf.Finish()
Xin Li745be2e2019-06-03 11:24:30 -0700509 did_lock = True
510
511 if not success:
512 err_event.set()
513 print('error: Cannot checkout %s' % (project.name),
514 file=sys.stderr)
515 raise _CheckoutError()
Xin Li745be2e2019-06-03 11:24:30 -0700516 except _CheckoutError:
517 pass
518 except Exception as e:
519 print('error: Cannot checkout %s: %s: %s' %
520 (project.name, type(e).__name__, str(e)),
521 file=sys.stderr)
522 err_event.set()
523 raise
524 finally:
Mike Frysingerfbb95a42021-02-23 17:34:35 -0500525 if not did_lock:
526 lock.acquire()
527 if not success:
528 err_results.append(project.relpath)
529 pm.finish(project.name)
530 lock.release()
Xin Li745be2e2019-06-03 11:24:30 -0700531 finish = time.time()
532 self.event_log.AddSync(project, event_log.TASK_SYNC_LOCAL,
533 start, finish, success)
534
535 return success
536
Mike Frysinger5a033082019-09-23 19:21:20 -0400537 def _Checkout(self, all_projects, opt, err_event, err_results):
Xin Li745be2e2019-06-03 11:24:30 -0700538 """Checkout projects listed in all_projects
539
540 Args:
541 all_projects: List of all projects that should be checked out.
542 opt: Program options returned from optparse. See _Options().
Mike Frysinger5a033082019-09-23 19:21:20 -0400543 err_event: We'll set this event in the case of an error (after printing
544 out info about the error).
545 err_results: A list of strings, paths to git repos where checkout
546 failed.
Xin Li745be2e2019-06-03 11:24:30 -0700547 """
548
549 # Perform checkouts in multiple threads when we are using partial clone.
550 # Without partial clone, all needed git objects are already downloaded,
551 # in this situation it's better to use only one process because the checkout
552 # would be mostly disk I/O; with partial clone, the objects are only
553 # downloaded when demanded (at checkout time), which is similar to the
554 # Sync_NetworkHalf case and parallelism would be helpful.
555 if self.manifest.CloneFilter:
556 syncjobs = self.jobs
557 else:
558 syncjobs = 1
559
560 lock = _threading.Lock()
Mike Frysingerfbb95a42021-02-23 17:34:35 -0500561 pm = Progress('Checking out', len(all_projects))
Xin Li745be2e2019-06-03 11:24:30 -0700562
563 threads = set()
564 sem = _threading.Semaphore(syncjobs)
Xin Li745be2e2019-06-03 11:24:30 -0700565
566 for project in all_projects:
567 # Check for any errors before running any more tasks.
568 # ...we'll let existing threads finish, though.
Mike Frysingerbe24a542021-02-23 03:24:12 -0500569 if err_event.is_set() and opt.fail_fast:
Xin Li745be2e2019-06-03 11:24:30 -0700570 break
571
572 sem.acquire()
573 if project.worktree:
574 kwargs = dict(opt=opt,
575 sem=sem,
576 project=project,
577 lock=lock,
578 pm=pm,
Vadim Bendeburydff91942019-11-06 11:05:00 -0800579 err_event=err_event,
580 err_results=err_results)
Xin Li745be2e2019-06-03 11:24:30 -0700581 if syncjobs > 1:
582 t = _threading.Thread(target=self._CheckoutWorker,
583 kwargs=kwargs)
584 # Ensure that Ctrl-C will not freeze the repo process.
585 t.daemon = True
586 threads.add(t)
587 t.start()
588 else:
589 self._CheckoutWorker(**kwargs)
590
591 for t in threads:
592 t.join()
593
594 pm.end()
Xin Li745be2e2019-06-03 11:24:30 -0700595
Mike Frysinger5a033082019-09-23 19:21:20 -0400596 def _GCProjects(self, projects, opt, err_event):
Gabe Black2ff30292014-10-09 17:54:35 -0700597 gc_gitdirs = {}
David James8d201162013-10-11 17:03:19 -0700598 for project in projects:
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500599 # Make sure pruning never kicks in with shared projects.
Mike Frysinger979d5bd2020-02-09 02:28:34 -0500600 if (not project.use_git_worktrees and
David Pursehouseaa611a22020-02-20 10:47:26 +0900601 len(project.manifest.GetProjectsWithName(project.name)) > 1):
Anders Björklund2a2da802021-01-18 10:32:36 +0100602 if not opt.quiet:
603 print('%s: Shared project %s found, disabling pruning.' %
604 (project.relpath, project.name))
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500605 if git_require((2, 7, 0)):
Mike Frysingerf81c72e2020-02-19 15:50:00 -0500606 project.EnableRepositoryExtension('preciousObjects')
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500607 else:
608 # This isn't perfect, but it's the best we can do with old git.
609 print('%s: WARNING: shared projects are unreliable when using old '
610 'versions of git; please upgrade to git-2.7.0+.'
611 % (project.relpath,),
612 file=sys.stderr)
613 project.config.SetString('gc.pruneExpire', 'never')
Gabe Black2ff30292014-10-09 17:54:35 -0700614 gc_gitdirs[project.gitdir] = project.bare_git
David James8d201162013-10-11 17:03:19 -0700615
Mike Frysinger6f1c6262020-02-04 00:09:23 -0500616 if multiprocessing:
Dave Borowitz18857212012-10-23 17:02:59 -0700617 cpu_count = multiprocessing.cpu_count()
618 else:
619 cpu_count = 1
620 jobs = min(self.jobs, cpu_count)
621
622 if jobs < 2:
Gabe Black2ff30292014-10-09 17:54:35 -0700623 for bare_git in gc_gitdirs.values():
David James8d201162013-10-11 17:03:19 -0700624 bare_git.gc('--auto')
Dave Borowitz18857212012-10-23 17:02:59 -0700625 return
626
Mike Frysinger0c0e9342019-06-13 12:42:39 -0400627 config = {'pack.threads': cpu_count // jobs if cpu_count > jobs else 1}
Dave Borowitz18857212012-10-23 17:02:59 -0700628
629 threads = set()
630 sem = _threading.Semaphore(jobs)
Dave Borowitz18857212012-10-23 17:02:59 -0700631
David James8d201162013-10-11 17:03:19 -0700632 def GC(bare_git):
Dave Borowitz18857212012-10-23 17:02:59 -0700633 try:
634 try:
David James8d201162013-10-11 17:03:19 -0700635 bare_git.gc('--auto', config=config)
Dave Borowitz18857212012-10-23 17:02:59 -0700636 except GitError:
637 err_event.set()
David Pursehouse145e35b2020-02-12 15:40:47 +0900638 except Exception:
Dave Borowitz18857212012-10-23 17:02:59 -0700639 err_event.set()
640 raise
641 finally:
642 sem.release()
643
Gabe Black2ff30292014-10-09 17:54:35 -0700644 for bare_git in gc_gitdirs.values():
Mike Frysingerbe24a542021-02-23 03:24:12 -0500645 if err_event.is_set() and opt.fail_fast:
Dave Borowitz18857212012-10-23 17:02:59 -0700646 break
647 sem.acquire()
David James8d201162013-10-11 17:03:19 -0700648 t = _threading.Thread(target=GC, args=(bare_git,))
Dave Borowitz18857212012-10-23 17:02:59 -0700649 t.daemon = True
650 threads.add(t)
651 t.start()
652
653 for t in threads:
654 t.join()
655
Tim Kilbourn07669002013-03-08 15:02:49 -0800656 def _ReloadManifest(self, manifest_name=None):
657 if manifest_name:
658 # Override calls _Unload already
659 self.manifest.Override(manifest_name)
660 else:
661 self.manifest._Unload()
662
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500663 def UpdateProjectList(self, opt):
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700664 new_project_paths = []
Colin Cross5acde752012-03-28 20:15:45 -0700665 for project in self.GetProjects(None, missing_ok=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700666 if project.relpath:
667 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700668 file_name = 'project.list'
Mike Frysingere3315bb2021-02-09 23:45:28 -0500669 file_path = os.path.join(self.repodir, file_name)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700670 old_project_paths = []
671
672 if os.path.exists(file_path):
Mike Frysinger3164d402019-11-11 05:40:22 -0500673 with open(file_path, 'r') as fd:
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700674 old_project_paths = fd.read().split('\n')
Kuang-che Wu0d9b16d2019-04-06 00:49:47 +0800675 # In reversed order, so subfolders are deleted before parent folder.
676 for path in sorted(old_project_paths, reverse=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700677 if not path:
678 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700679 if path not in new_project_paths:
David Pursehouse8a68ff92012-09-24 12:15:13 +0900680 # If the path has already been deleted, we don't need to do it
Dan Willemsen43507912016-09-01 16:26:02 -0700681 gitdir = os.path.join(self.manifest.topdir, path, '.git')
682 if os.path.exists(gitdir):
David Pursehousec1b86a22012-11-14 11:36:51 +0900683 project = Project(
David Pursehouseabdf7502020-02-12 14:58:39 +0900684 manifest=self.manifest,
685 name=path,
686 remote=RemoteSpec('origin'),
687 gitdir=gitdir,
688 objdir=gitdir,
Mike Frysingerc0d18662020-02-19 19:19:18 -0500689 use_git_worktrees=os.path.isfile(gitdir),
David Pursehouseabdf7502020-02-12 14:58:39 +0900690 worktree=os.path.join(self.manifest.topdir, path),
691 relpath=path,
692 revisionExpr='HEAD',
693 revisionId=None,
694 groups=None)
Mike Frysingerc0d18662020-02-19 19:19:18 -0500695 if not project.DeleteWorktree(
David Pursehouseaa611a22020-02-20 10:47:26 +0900696 quiet=opt.quiet,
697 force=opt.force_remove_dirty):
Mike Frysingera850ca22019-08-07 17:19:24 -0400698 return 1
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700699
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700700 new_project_paths.sort()
Mike Frysinger3164d402019-11-11 05:40:22 -0500701 with open(file_path, 'w') as fd:
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700702 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700703 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700704 return 0
705
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400706 def _SmartSyncSetup(self, opt, smart_sync_manifest_path):
707 if not self.manifest.manifest_server:
708 print('error: cannot smart sync: no manifest server defined in '
709 'manifest', file=sys.stderr)
710 sys.exit(1)
711
712 manifest_server = self.manifest.manifest_server
713 if not opt.quiet:
714 print('Using manifest server %s' % manifest_server)
715
David Pursehouseeeff3532020-02-12 11:24:10 +0900716 if '@' not in manifest_server:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400717 username = None
718 password = None
719 if opt.manifest_server_username and opt.manifest_server_password:
720 username = opt.manifest_server_username
721 password = opt.manifest_server_password
722 else:
723 try:
724 info = netrc.netrc()
725 except IOError:
726 # .netrc file does not exist or could not be opened
727 pass
728 else:
729 try:
730 parse_result = urllib.parse.urlparse(manifest_server)
731 if parse_result.hostname:
732 auth = info.authenticators(parse_result.hostname)
733 if auth:
734 username, _account, password = auth
735 else:
736 print('No credentials found for %s in .netrc'
737 % parse_result.hostname, file=sys.stderr)
738 except netrc.NetrcParseError as e:
739 print('Error parsing .netrc file: %s' % e, file=sys.stderr)
740
741 if (username and password):
742 manifest_server = manifest_server.replace('://', '://%s:%s@' %
743 (username, password),
744 1)
745
746 transport = PersistentTransport(manifest_server)
747 if manifest_server.startswith('persistent-'):
748 manifest_server = manifest_server[len('persistent-'):]
749
750 try:
751 server = xmlrpc.client.Server(manifest_server, transport=transport)
752 if opt.smart_sync:
Raman Tenneti8d43dea2021-02-07 16:30:27 -0800753 branch = self._GetBranch()
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400754
Mike Frysinger56ce3462019-12-04 19:30:48 -0500755 if 'SYNC_TARGET' in os.environ:
Mike Frysingere20da3e2020-03-07 01:53:53 -0500756 target = os.environ['SYNC_TARGET']
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400757 [success, manifest_str] = server.GetApprovedManifest(branch, target)
Mike Frysinger56ce3462019-12-04 19:30:48 -0500758 elif ('TARGET_PRODUCT' in os.environ and
759 'TARGET_BUILD_VARIANT' in os.environ):
Mike Frysingere20da3e2020-03-07 01:53:53 -0500760 target = '%s-%s' % (os.environ['TARGET_PRODUCT'],
761 os.environ['TARGET_BUILD_VARIANT'])
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400762 [success, manifest_str] = server.GetApprovedManifest(branch, target)
763 else:
764 [success, manifest_str] = server.GetApprovedManifest(branch)
765 else:
766 assert(opt.smart_tag)
767 [success, manifest_str] = server.GetManifest(opt.smart_tag)
768
769 if success:
770 manifest_name = os.path.basename(smart_sync_manifest_path)
771 try:
Mike Frysinger3164d402019-11-11 05:40:22 -0500772 with open(smart_sync_manifest_path, 'w') as f:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400773 f.write(manifest_str)
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400774 except IOError as e:
775 print('error: cannot write manifest to %s:\n%s'
776 % (smart_sync_manifest_path, e),
777 file=sys.stderr)
778 sys.exit(1)
779 self._ReloadManifest(manifest_name)
780 else:
781 print('error: manifest server RPC call failed: %s' %
782 manifest_str, file=sys.stderr)
783 sys.exit(1)
784 except (socket.error, IOError, xmlrpc.client.Fault) as e:
785 print('error: cannot connect to manifest server %s:\n%s'
786 % (self.manifest.manifest_server, e), file=sys.stderr)
787 sys.exit(1)
788 except xmlrpc.client.ProtocolError as e:
789 print('error: cannot connect to manifest server %s:\n%d %s'
790 % (self.manifest.manifest_server, e.errcode, e.errmsg),
791 file=sys.stderr)
792 sys.exit(1)
793
794 return manifest_name
795
Mike Frysingerfb527e32019-08-27 02:34:32 -0400796 def _UpdateManifestProject(self, opt, mp, manifest_name):
797 """Fetch & update the local manifest project."""
798 if not opt.local_only:
799 start = time.time()
Mike Frysinger521d01b2020-02-17 01:51:49 -0500800 success = mp.Sync_NetworkHalf(quiet=opt.quiet, verbose=opt.verbose,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400801 current_branch_only=opt.current_branch_only,
Erwan Yvindc5c4d12019-06-18 13:49:12 +0200802 force_sync=opt.force_sync,
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500803 tags=opt.tags,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400804 optimized_fetch=opt.optimized_fetch,
George Engelbrecht9bc283e2020-04-02 12:36:09 -0600805 retry_fetches=opt.retry_fetches,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400806 submodules=self.manifest.HasSubmodules,
807 clone_filter=self.manifest.CloneFilter)
808 finish = time.time()
809 self.event_log.AddSync(mp, event_log.TASK_SYNC_NETWORK,
810 start, finish, success)
811
812 if mp.HasChanges:
813 syncbuf = SyncBuffer(mp.config)
814 start = time.time()
815 mp.Sync_LocalHalf(syncbuf, submodules=self.manifest.HasSubmodules)
816 clean = syncbuf.Finish()
817 self.event_log.AddSync(mp, event_log.TASK_SYNC_LOCAL,
818 start, time.time(), clean)
819 if not clean:
820 sys.exit(1)
821 self._ReloadManifest(opt.manifest_name)
822 if opt.jobs is None:
823 self.jobs = self.manifest.default.sync_j
824
Mike Frysingerae6cb082019-08-27 01:10:59 -0400825 def ValidateOptions(self, opt, args):
826 if opt.force_broken:
827 print('warning: -f/--force-broken is now the default behavior, and the '
828 'options are deprecated', file=sys.stderr)
829 if opt.network_only and opt.detach_head:
830 self.OptionParser.error('cannot combine -n and -d')
831 if opt.network_only and opt.local_only:
832 self.OptionParser.error('cannot combine -n and -l')
833 if opt.manifest_name and opt.smart_sync:
834 self.OptionParser.error('cannot combine -m and -s')
835 if opt.manifest_name and opt.smart_tag:
836 self.OptionParser.error('cannot combine -m and -t')
837 if opt.manifest_server_username or opt.manifest_server_password:
838 if not (opt.smart_sync or opt.smart_tag):
839 self.OptionParser.error('-u and -p may only be combined with -s or -t')
840 if None in [opt.manifest_server_username, opt.manifest_server_password]:
841 self.OptionParser.error('both -u and -p must be given')
842
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700843 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800844 if opt.jobs:
845 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700846 if self.jobs > 1:
847 soft_limit, _ = _rlimit_nofile()
Mike Frysinger0c0e9342019-06-13 12:42:39 -0400848 self.jobs = min(self.jobs, (soft_limit - 5) // 3)
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700849
Mike Frysinger521d01b2020-02-17 01:51:49 -0500850 opt.quiet = opt.output_mode is False
851 opt.verbose = opt.output_mode is True
852
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500853 if opt.manifest_name:
854 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700855
Chirayu Desaia892b102013-06-11 14:18:46 +0530856 manifest_name = opt.manifest_name
David Pursehouse59b41742015-05-07 14:36:09 +0900857 smart_sync_manifest_path = os.path.join(
David Pursehouseabdf7502020-02-12 14:58:39 +0900858 self.manifest.manifestProject.worktree, 'smart_sync_override.xml')
Chirayu Desaia892b102013-06-11 14:18:46 +0530859
Xin Lid79a4bc2020-05-20 16:03:45 -0700860 if opt.clone_bundle is None:
861 opt.clone_bundle = self.manifest.CloneBundle
862
Victor Boivie08c880d2011-04-19 10:32:52 +0200863 if opt.smart_sync or opt.smart_tag:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400864 manifest_name = self._SmartSyncSetup(opt, smart_sync_manifest_path)
865 else:
David Pursehouse59b41742015-05-07 14:36:09 +0900866 if os.path.isfile(smart_sync_manifest_path):
867 try:
Renaud Paquay010fed72016-11-11 14:25:29 -0800868 platform_utils.remove(smart_sync_manifest_path)
David Pursehouse59b41742015-05-07 14:36:09 +0900869 except OSError as e:
870 print('error: failed to remove existing smart sync override manifest: %s' %
871 e, file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700872
Mike Frysinger5a033082019-09-23 19:21:20 -0400873 err_event = _threading.Event()
874
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700875 rp = self.manifest.repoProject
876 rp.PreSync()
Mike Frysinger23c900f2020-02-29 02:52:44 -0500877 cb = rp.CurrentBranch
878 if cb:
879 base = rp.GetBranch(cb).merge
880 if not base or not base.startswith('refs/heads/'):
881 print('warning: repo is not tracking a remote branch, so it will not '
Mike Frysinger58ac1672020-03-14 14:35:26 -0400882 'receive updates; run `repo init --repo-rev=stable` to fix.',
Mike Frysinger23c900f2020-02-29 02:52:44 -0500883 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700884
885 mp = self.manifest.manifestProject
886 mp.PreSync()
887
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800888 if opt.repo_upgraded:
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700889 _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800890
Fredrik de Grootcc960972019-11-22 09:04:31 +0100891 if not opt.mp_update:
892 print('Skipping update of local manifest project.')
893 else:
894 self._UpdateManifestProject(opt, mp, manifest_name)
Simran Basib9a1b732015-08-20 12:19:28 -0700895
Raman Tenneti55d6a5a2021-02-24 14:37:01 -0800896 if (opt.use_superproject or
897 self.manifest.manifestProject.config.GetBoolean(
898 'repo.superproject')):
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800899 manifest_name = self._UpdateProjectsRevisionId(opt, args)
900
Simran Basib9a1b732015-08-20 12:19:28 -0700901 if self.gitc_manifest:
902 gitc_manifest_projects = self.GetProjects(args,
Simran Basib9a1b732015-08-20 12:19:28 -0700903 missing_ok=True)
904 gitc_projects = []
905 opened_projects = []
906 for project in gitc_manifest_projects:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700907 if project.relpath in self.gitc_manifest.paths and \
908 self.gitc_manifest.paths[project.relpath].old_revision:
909 opened_projects.append(project.relpath)
Simran Basib9a1b732015-08-20 12:19:28 -0700910 else:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700911 gitc_projects.append(project.relpath)
Simran Basib9a1b732015-08-20 12:19:28 -0700912
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700913 if not args:
914 gitc_projects = None
915
916 if gitc_projects != [] and not opt.local_only:
Simran Basib9a1b732015-08-20 12:19:28 -0700917 print('Updating GITC client: %s' % self.gitc_manifest.gitc_client_name)
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700918 manifest = GitcManifest(self.repodir, self.gitc_manifest.gitc_client_name)
919 if manifest_name:
920 manifest.Override(manifest_name)
921 else:
922 manifest.Override(self.manifest.manifestFile)
923 gitc_utils.generate_gitc_manifest(self.gitc_manifest,
924 manifest,
Simran Basib9a1b732015-08-20 12:19:28 -0700925 gitc_projects)
926 print('GITC client successfully synced.')
927
928 # The opened projects need to be synced as normal, therefore we
929 # generate a new args list to represent the opened projects.
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700930 # TODO: make this more reliable -- if there's a project name/path overlap,
931 # this may choose the wrong project.
David Pursehouse3bcd3052017-07-10 22:42:22 +0900932 args = [os.path.relpath(self.manifest.paths[path].worktree, os.getcwd())
933 for path in opened_projects]
Simran Basib9a1b732015-08-20 12:19:28 -0700934 if not args:
935 return
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800936 all_projects = self.GetProjects(args,
937 missing_ok=True,
938 submodules_ok=opt.fetch_submodules)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700939
Mike Frysinger5a033082019-09-23 19:21:20 -0400940 err_network_sync = False
941 err_update_projects = False
942 err_checkout = False
943
Dave Borowitz67700e92012-10-23 15:00:54 -0700944 self._fetch_times = _FetchTimes(self.manifest)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700945 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700946 to_fetch = []
947 now = time.time()
Dave Borowitz67700e92012-10-23 15:00:54 -0700948 if _ONE_DAY_S <= (now - rp.LastFetch):
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700949 to_fetch.append(rp)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900950 to_fetch.extend(all_projects)
Dave Borowitz67700e92012-10-23 15:00:54 -0700951 to_fetch.sort(key=self._fetch_times.Get, reverse=True)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700952
Mike Frysinger5a033082019-09-23 19:21:20 -0400953 fetched = self._Fetch(to_fetch, opt, err_event)
954
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500955 _PostRepoFetch(rp, opt.repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700956 if opt.network_only:
957 # bail out now; the rest touches the working tree
Mike Frysingerbe24a542021-02-23 03:24:12 -0500958 if err_event.is_set():
Mike Frysinger5a033082019-09-23 19:21:20 -0400959 print('\nerror: Exited sync due to fetch errors.\n', file=sys.stderr)
960 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700961 return
962
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800963 # Iteratively fetch missing and/or nested unregistered submodules
964 previously_missing_set = set()
965 while True:
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100966 self._ReloadManifest(manifest_name)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800967 all_projects = self.GetProjects(args,
968 missing_ok=True,
969 submodules_ok=opt.fetch_submodules)
970 missing = []
971 for project in all_projects:
972 if project.gitdir not in fetched:
973 missing.append(project)
974 if not missing:
975 break
976 # Stop us from non-stopped fetching actually-missing repos: If set of
977 # missing repos has not been changed from last fetch, we break.
978 missing_set = set(p.name for p in missing)
979 if previously_missing_set == missing_set:
980 break
981 previously_missing_set = missing_set
Mike Frysinger5a033082019-09-23 19:21:20 -0400982 fetched.update(self._Fetch(missing, opt, err_event))
983
984 # If we saw an error, exit with code 1 so that other scripts can check.
Mike Frysingerbe24a542021-02-23 03:24:12 -0500985 if err_event.is_set():
Mike Frysinger5a033082019-09-23 19:21:20 -0400986 err_network_sync = True
987 if opt.fail_fast:
988 print('\nerror: Exited sync due to fetch errors.\n'
989 'Local checkouts *not* updated. Resolve network issues & '
990 'retry.\n'
991 '`repo sync -l` will update some local checkouts.',
992 file=sys.stderr)
993 sys.exit(1)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800994
Julien Campergue335f5ef2013-10-16 11:02:35 +0200995 if self.manifest.IsMirror or self.manifest.IsArchive:
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700996 # bail out now, we have no working tree
997 return
998
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500999 if self.UpdateProjectList(opt):
Mike Frysinger5a033082019-09-23 19:21:20 -04001000 err_event.set()
1001 err_update_projects = True
1002 if opt.fail_fast:
1003 print('\nerror: Local checkouts *not* updated.', file=sys.stderr)
1004 sys.exit(1)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -07001005
Mike Frysinger5a033082019-09-23 19:21:20 -04001006 err_results = []
1007 self._Checkout(all_projects, opt, err_event, err_results)
Mike Frysingerbe24a542021-02-23 03:24:12 -05001008 if err_event.is_set():
Mike Frysinger5a033082019-09-23 19:21:20 -04001009 err_checkout = True
1010 # NB: We don't exit here because this is the last step.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001011
Doug Anderson2b8db3c2010-11-01 15:08:06 -07001012 # If there's a notice that's supposed to print at the end of the sync, print
1013 # it now...
1014 if self.manifest.notice:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001015 print(self.manifest.notice)
Doug Anderson2b8db3c2010-11-01 15:08:06 -07001016
Mike Frysinger5a033082019-09-23 19:21:20 -04001017 # If we saw an error, exit with code 1 so that other scripts can check.
Mike Frysingerbe24a542021-02-23 03:24:12 -05001018 if err_event.is_set():
Mike Frysinger5a033082019-09-23 19:21:20 -04001019 print('\nerror: Unable to fully sync the tree.', file=sys.stderr)
1020 if err_network_sync:
1021 print('error: Downloading network changes failed.', file=sys.stderr)
1022 if err_update_projects:
1023 print('error: Updating local project lists failed.', file=sys.stderr)
1024 if err_checkout:
1025 print('error: Checking out local projects failed.', file=sys.stderr)
1026 if err_results:
1027 print('Failing repos:\n%s' % '\n'.join(err_results), file=sys.stderr)
1028 print('Try re-running with "-j1 --fail-fast" to exit at the first error.',
1029 file=sys.stderr)
1030 sys.exit(1)
1031
Mike Frysingere19d9e12020-02-12 11:23:32 -05001032 if not opt.quiet:
1033 print('repo sync has finished successfully.')
1034
David Pursehouse819827a2020-02-12 15:20:19 +09001035
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -07001036def _PostRepoUpgrade(manifest, quiet=False):
Conley Owens094cdbe2014-01-30 15:09:59 -08001037 wrapper = Wrapper()
Conley Owensc9129d92012-10-01 16:12:28 -07001038 if wrapper.NeedSetupGnuPG():
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -07001039 wrapper.SetupGnuPG(quiet)
Conley Owensf2fe2d92014-01-29 13:53:43 -08001040 for project in manifest.projects:
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001041 if project.Exists:
1042 project.PostRepoUpgrade()
1043
David Pursehouse819827a2020-02-12 15:20:19 +09001044
Mike Frysingerc58ec4d2020-02-17 14:36:08 -05001045def _PostRepoFetch(rp, repo_verify=True, verbose=False):
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001046 if rp.HasChanges:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001047 print('info: A new version of repo is available', file=sys.stderr)
1048 print(file=sys.stderr)
Mike Frysingerc58ec4d2020-02-17 14:36:08 -05001049 if not repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -07001050 syncbuf = SyncBuffer(rp.config)
1051 rp.Sync_LocalHalf(syncbuf)
1052 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001053 sys.exit(1)
Sarah Owenscecd1d82012-11-01 22:59:27 -07001054 print('info: Restarting repo with latest version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001055 raise RepoChangedException(['--repo-upgraded'])
1056 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001057 print('warning: Skipped upgrade to unverified version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001058 else:
1059 if verbose:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001060 print('repo version %s is current' % rp.work_git.describe(HEAD),
1061 file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001062
David Pursehouse819827a2020-02-12 15:20:19 +09001063
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001064def _VerifyTag(project):
1065 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
1066 if not os.path.exists(gpg_dir):
Sarah Owenscecd1d82012-11-01 22:59:27 -07001067 print('warning: GnuPG was not available during last "repo init"\n'
1068 'warning: Cannot automatically authenticate repo."""',
1069 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001070 return True
1071
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001072 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -07001073 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001074 except GitError:
1075 cur = None
1076
1077 if not cur \
1078 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -07001079 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001080 if rev.startswith(R_HEADS):
1081 rev = rev[len(R_HEADS):]
1082
Sarah Owenscecd1d82012-11-01 22:59:27 -07001083 print(file=sys.stderr)
1084 print("warning: project '%s' branch '%s' is not signed"
1085 % (project.name, rev), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001086 return False
1087
Shawn O. Pearcef18cb762010-12-07 11:41:05 -08001088 env = os.environ.copy()
Mike Frysinger56ce3462019-12-04 19:30:48 -05001089 env['GIT_DIR'] = project.gitdir
1090 env['GNUPGHOME'] = gpg_dir
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001091
1092 cmd = [GIT, 'tag', '-v', cur]
Mike Frysingerfb21d6a2021-02-16 02:37:55 -05001093 result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
1094 env=env, check=False)
1095 if result.returncode:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001096 print(file=sys.stderr)
Mike Frysingerfb21d6a2021-02-16 02:37:55 -05001097 print(result.stdout, file=sys.stderr)
Sarah Owenscecd1d82012-11-01 22:59:27 -07001098 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001099 return False
1100 return True
Dave Borowitz67700e92012-10-23 15:00:54 -07001101
David Rileye0684ad2017-04-05 00:02:59 -07001102
Dave Borowitz67700e92012-10-23 15:00:54 -07001103class _FetchTimes(object):
Dave Borowitzd9478582012-10-23 16:35:39 -07001104 _ALPHA = 0.5
1105
Dave Borowitz67700e92012-10-23 15:00:54 -07001106 def __init__(self, manifest):
Anthony King85b24ac2014-05-06 15:57:48 +01001107 self._path = os.path.join(manifest.repodir, '.repo_fetchtimes.json')
Dave Borowitz67700e92012-10-23 15:00:54 -07001108 self._times = None
Dave Borowitzd9478582012-10-23 16:35:39 -07001109 self._seen = set()
Dave Borowitz67700e92012-10-23 15:00:54 -07001110
1111 def Get(self, project):
1112 self._Load()
1113 return self._times.get(project.name, _ONE_DAY_S)
1114
1115 def Set(self, project, t):
Dave Borowitzd9478582012-10-23 16:35:39 -07001116 self._Load()
1117 name = project.name
1118 old = self._times.get(name, t)
1119 self._seen.add(name)
1120 a = self._ALPHA
David Pursehouse54a4e602020-02-12 14:31:05 +09001121 self._times[name] = (a * t) + ((1 - a) * old)
Dave Borowitz67700e92012-10-23 15:00:54 -07001122
1123 def _Load(self):
1124 if self._times is None:
1125 try:
Mike Frysinger3164d402019-11-11 05:40:22 -05001126 with open(self._path) as f:
Anthony King85b24ac2014-05-06 15:57:48 +01001127 self._times = json.load(f)
Anthony King85b24ac2014-05-06 15:57:48 +01001128 except (IOError, ValueError):
1129 try:
Renaud Paquay010fed72016-11-11 14:25:29 -08001130 platform_utils.remove(self._path)
Anthony King85b24ac2014-05-06 15:57:48 +01001131 except OSError:
1132 pass
1133 self._times = {}
Dave Borowitz67700e92012-10-23 15:00:54 -07001134
1135 def Save(self):
1136 if self._times is None:
1137 return
Dave Borowitzd9478582012-10-23 16:35:39 -07001138
1139 to_delete = []
1140 for name in self._times:
1141 if name not in self._seen:
1142 to_delete.append(name)
1143 for name in to_delete:
1144 del self._times[name]
1145
Dave Borowitz67700e92012-10-23 15:00:54 -07001146 try:
Mike Frysinger3164d402019-11-11 05:40:22 -05001147 with open(self._path, 'w') as f:
Anthony King85b24ac2014-05-06 15:57:48 +01001148 json.dump(self._times, f, indent=2)
Anthony King85b24ac2014-05-06 15:57:48 +01001149 except (IOError, TypeError):
1150 try:
Renaud Paquay010fed72016-11-11 14:25:29 -08001151 platform_utils.remove(self._path)
Anthony King85b24ac2014-05-06 15:57:48 +01001152 except OSError:
1153 pass
Dan Willemsen0745bb22015-08-17 13:41:45 -07001154
1155# This is a replacement for xmlrpc.client.Transport using urllib2
1156# and supporting persistent-http[s]. It cannot change hosts from
1157# request to request like the normal transport, the real url
1158# is passed during initialization.
David Pursehouse819827a2020-02-12 15:20:19 +09001159
1160
Dan Willemsen0745bb22015-08-17 13:41:45 -07001161class PersistentTransport(xmlrpc.client.Transport):
1162 def __init__(self, orig_host):
1163 self.orig_host = orig_host
1164
1165 def request(self, host, handler, request_body, verbose=False):
1166 with GetUrlCookieFile(self.orig_host, not verbose) as (cookiefile, proxy):
1167 # Python doesn't understand cookies with the #HttpOnly_ prefix
1168 # Since we're only using them for HTTP, copy the file temporarily,
1169 # stripping those prefixes away.
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001170 if cookiefile:
Collin Fijalkoviche1191b32020-02-18 10:57:32 -08001171 tmpcookiefile = tempfile.NamedTemporaryFile(mode='w')
David Pursehouse4c5f74e2015-10-02 11:10:10 +09001172 tmpcookiefile.write("# HTTP Cookie File")
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001173 try:
1174 with open(cookiefile) as f:
1175 for line in f:
1176 if line.startswith("#HttpOnly_"):
1177 line = line[len("#HttpOnly_"):]
1178 tmpcookiefile.write(line)
1179 tmpcookiefile.flush()
Dan Willemsen0745bb22015-08-17 13:41:45 -07001180
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001181 cookiejar = cookielib.MozillaCookieJar(tmpcookiefile.name)
David Pursehouseb1ad2192015-09-30 10:35:43 +09001182 try:
1183 cookiejar.load()
1184 except cookielib.LoadError:
1185 cookiejar = cookielib.CookieJar()
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001186 finally:
1187 tmpcookiefile.close()
1188 else:
1189 cookiejar = cookielib.CookieJar()
Dan Willemsen0745bb22015-08-17 13:41:45 -07001190
1191 proxyhandler = urllib.request.ProxyHandler
1192 if proxy:
1193 proxyhandler = urllib.request.ProxyHandler({
1194 "http": proxy,
David Pursehouse54a4e602020-02-12 14:31:05 +09001195 "https": proxy})
Dan Willemsen0745bb22015-08-17 13:41:45 -07001196
1197 opener = urllib.request.build_opener(
1198 urllib.request.HTTPCookieProcessor(cookiejar),
1199 proxyhandler)
1200
1201 url = urllib.parse.urljoin(self.orig_host, handler)
1202 parse_results = urllib.parse.urlparse(url)
1203
1204 scheme = parse_results.scheme
1205 if scheme == 'persistent-http':
1206 scheme = 'http'
1207 if scheme == 'persistent-https':
1208 # If we're proxying through persistent-https, use http. The
1209 # proxy itself will do the https.
1210 if proxy:
1211 scheme = 'http'
1212 else:
1213 scheme = 'https'
1214
1215 # Parse out any authentication information using the base class
1216 host, extra_headers, _ = self.get_host_info(parse_results.netloc)
1217
1218 url = urllib.parse.urlunparse((
1219 scheme,
1220 host,
1221 parse_results.path,
1222 parse_results.params,
1223 parse_results.query,
1224 parse_results.fragment))
1225
1226 request = urllib.request.Request(url, request_body)
1227 if extra_headers is not None:
1228 for (name, header) in extra_headers:
1229 request.add_header(name, header)
1230 request.add_header('Content-Type', 'text/xml')
1231 try:
1232 response = opener.open(request)
1233 except urllib.error.HTTPError as e:
1234 if e.code == 501:
1235 # We may have been redirected through a login process
1236 # but our POST turned into a GET. Retry.
1237 response = opener.open(request)
1238 else:
1239 raise
1240
1241 p, u = xmlrpc.client.getparser()
1242 while 1:
1243 data = response.read(1024)
1244 if not data:
1245 break
1246 p.feed(data)
1247 p.close()
1248 return u.close()
1249
1250 def close(self):
1251 pass