blob: eda95f9613dff71033e9497355acc7bd02a0ff2a [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."""
71 pass
72
David Pursehouse819827a2020-02-12 15:20:19 +090073
Xin Li745be2e2019-06-03 11:24:30 -070074class _CheckoutError(Exception):
75 """Internal error thrown in _CheckoutOne() when we don't want stack trace."""
76
David Pursehouse819827a2020-02-12 15:20:19 +090077
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080078class Sync(Command, MirrorSafeCommand):
Roy Lee18afd7f2010-05-09 04:32:08 +080079 jobs = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070080 common = True
81 helpSummary = "Update working tree to the latest revision"
82 helpUsage = """
83%prog [<project>...]
84"""
85 helpDescription = """
86The '%prog' command synchronizes local project directories
87with the remote repositories specified in the manifest. If a local
88project does not yet exist, it will clone a new local directory from
89the remote repository and set up tracking branches as specified in
90the manifest. If the local project already exists, '%prog'
91will update the remote branches and rebase any new local changes
92on top of the new remote changes.
93
94'%prog' will synchronize all projects listed at the command
95line. Projects can be specified either by name, or by a relative
96or absolute path to the project's local directory. If no projects
97are specified, '%prog' will synchronize all projects listed in
98the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070099
100The -d/--detach option can be used to switch specified projects
101back to the manifest revision. This option is especially helpful
102if the project is currently on a topic branch, but the manifest
103revision is temporarily needed.
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700104
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700105The -s/--smart-sync option can be used to sync to a known good
106build as specified by the manifest-server element in the current
Victor Boivie08c880d2011-04-19 10:32:52 +0200107manifest. The -t/--smart-tag option is similar and allows you to
108specify a custom tag/label.
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700109
David Pursehousecf76b1b2012-09-14 10:31:42 +0900110The -u/--manifest-server-username and -p/--manifest-server-password
111options can be used to specify a username and password to authenticate
112with the manifest server when using the -s or -t option.
113
114If -u and -p are not specified when using the -s or -t option, '%prog'
115will attempt to read authentication credentials for the manifest server
116from the user's .netrc file.
117
118'%prog' will not use authentication credentials from -u/-p or .netrc
119if the manifest server specified in the manifest file already includes
120credentials.
121
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400122By default, all projects will be synced. The --fail-fast option can be used
Mike Frysinger7ae210a2020-05-24 14:56:52 -0400123to halt syncing as soon as possible when the first project fails to sync.
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500124
Kevin Degiabaa7f32014-11-12 11:27:45 -0700125The --force-sync option can be used to overwrite existing git
126directories if they have previously been linked to a different
Roger Shimizuac29ac32020-06-06 02:33:40 +0900127object directory. WARNING: This may cause data to be lost since
Kevin Degiabaa7f32014-11-12 11:27:45 -0700128refs may be removed when overwriting.
129
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500130The --force-remove-dirty option can be used to remove previously used
131projects with uncommitted changes. WARNING: This may cause data to be
132lost since uncommitted changes may be removed with projects that no longer
133exist in the manifest.
134
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700135The --no-clone-bundle option disables any attempt to use
136$URL/clone.bundle to bootstrap a new Git repository from a
137resumeable bundle file on a content delivery network. This
138may be necessary if there are problems with the local Python
139HTTP client or proxy configuration, but the Git binary works.
140
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800141The --fetch-submodules option enables fetching Git submodules
142of a project from server.
143
David Pursehousef2fad612015-01-29 14:36:28 +0900144The -c/--current-branch option can be used to only fetch objects that
145are on the branch specified by a project's revision.
146
David Pursehouseb1553542014-09-04 21:28:09 +0900147The --optimized-fetch option can be used to only fetch projects that
148are fixed to a sha1 revision if the sha1 revision does not already
149exist locally.
150
David Pursehouse74cfd272015-10-14 10:50:15 +0900151The --prune option can be used to remove any refs that no longer
152exist on the remote.
153
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400154# SSH Connections
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700155
156If at least one project remote URL uses an SSH connection (ssh://,
157git+ssh://, or user@host:path syntax) repo will automatically
158enable the SSH ControlMaster option when connecting to that host.
159This feature permits other projects in the same '%prog' session to
160reuse the same SSH tunnel, saving connection setup overheads.
161
162To disable this behavior on UNIX platforms, set the GIT_SSH
163environment variable to 'ssh'. For example:
164
165 export GIT_SSH=ssh
166 %prog
167
Mike Frysingerb8f7bb02018-10-10 01:05:11 -0400168# Compatibility
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700169
170This feature is automatically disabled on Windows, due to the lack
171of UNIX domain socket support.
172
173This feature is not compatible with url.insteadof rewrites in the
174user's ~/.gitconfig. '%prog' is currently not able to perform the
175rewrite early enough to establish the ControlMaster tunnel.
176
177If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or
178later is required to fix a server side protocol bug.
179
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700180"""
181
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:
184 self.jobs = self.manifest.default.sync_j
185 except ManifestParseError:
186 self.jobs = 1
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700187
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500188 p.add_option('-f', '--force-broken',
Stefan Müller-Klieser46702ed2019-08-30 10:20:15 +0200189 dest='force_broken', action='store_true',
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400190 help='obsolete option (to be deleted in the future)')
191 p.add_option('--fail-fast',
192 dest='fail_fast', action='store_true',
193 help='stop syncing after first error is hit')
Kevin Degiabaa7f32014-11-12 11:27:45 -0700194 p.add_option('--force-sync',
195 dest='force_sync', action='store_true',
196 help="overwrite an existing git directory if it needs to "
197 "point to a different object directory. WARNING: this "
198 "may cause loss of data")
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500199 p.add_option('--force-remove-dirty',
200 dest='force_remove_dirty', action='store_true',
201 help="force remove projects with uncommitted modifications if "
202 "projects no longer exist in the manifest. "
203 "WARNING: this may cause loss of data")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900204 p.add_option('-l', '--local-only',
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700205 dest='local_only', action='store_true',
206 help="only update working tree, don't fetch")
David Pursehouse54a4e602020-02-12 14:31:05 +0900207 p.add_option('--no-manifest-update', '--nmu',
Fredrik de Grootcc960972019-11-22 09:04:31 +0100208 dest='mp_update', action='store_false', default='true',
209 help='use the existing manifest checkout as-is. '
210 '(do not update to the latest revision)')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900211 p.add_option('-n', '--network-only',
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700212 dest='network_only', action='store_true',
213 help="fetch only, don't update working tree")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900214 p.add_option('-d', '--detach',
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700215 dest='detach_head', action='store_true',
216 help='detach projects back to manifest revision')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900217 p.add_option('-c', '--current-branch',
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700218 dest='current_branch_only', action='store_true',
219 help='fetch only current branch from server')
Mike Frysinger521d01b2020-02-17 01:51:49 -0500220 p.add_option('-v', '--verbose',
221 dest='output_mode', action='store_true',
222 help='show all sync output')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900223 p.add_option('-q', '--quiet',
Mike Frysinger521d01b2020-02-17 01:51:49 -0500224 dest='output_mode', action='store_false',
225 help='only show errors')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900226 p.add_option('-j', '--jobs',
Roy Lee18afd7f2010-05-09 04:32:08 +0800227 dest='jobs', action='store', type='int',
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700228 help="projects to fetch simultaneously (default %d)" % self.jobs)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500229 p.add_option('-m', '--manifest-name',
230 dest='manifest_name',
231 help='temporary manifest to use for this sync', metavar='NAME.xml')
Xin Lid79a4bc2020-05-20 16:03:45 -0700232 p.add_option('--clone-bundle', action='store_true',
233 help='enable use of /clone.bundle on HTTP/HTTPS')
234 p.add_option('--no-clone-bundle', dest='clone_bundle', action='store_false',
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700235 help='disable use of /clone.bundle on HTTP/HTTPS')
Conley Owens8d070cf2012-11-06 13:14:31 -0800236 p.add_option('-u', '--manifest-server-username', action='store',
237 dest='manifest_server_username',
238 help='username to authenticate with the manifest server')
239 p.add_option('-p', '--manifest-server-password', action='store',
240 dest='manifest_server_password',
241 help='password to authenticate with the manifest server')
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800242 p.add_option('--fetch-submodules',
243 dest='fetch_submodules', action='store_true',
244 help='fetch submodules from server')
Raman Tenneti6a872c92021-01-14 19:17:50 -0800245 p.add_option('--use-superproject', action='store_true',
246 help='use the manifest superproject to sync projects')
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700247 p.add_option('--no-tags',
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500248 dest='tags', default=True, action='store_false',
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700249 help="don't fetch tags")
David Pursehouseb1553542014-09-04 21:28:09 +0900250 p.add_option('--optimized-fetch',
251 dest='optimized_fetch', action='store_true',
252 help='only fetch projects fixed to sha1 if revision does not exist locally')
George Engelbrecht9bc283e2020-04-02 12:36:09 -0600253 p.add_option('--retry-fetches',
254 default=0, action='store', type='int',
255 help='number of times to retry fetches on transient errors')
David Pursehouse74cfd272015-10-14 10:50:15 +0900256 p.add_option('--prune', dest='prune', action='store_true',
257 help='delete refs that no longer exist on the remote')
Nico Sallembien6623b212010-05-11 12:57:01 -0700258 if show_smart:
259 p.add_option('-s', '--smart-sync',
260 dest='smart_sync', action='store_true',
David Pursehouse79fba682016-04-13 18:03:00 +0900261 help='smart sync using manifest from the latest known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200262 p.add_option('-t', '--smart-tag',
263 dest='smart_tag', action='store',
264 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700265
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700266 g = p.add_option_group('repo Version options')
267 g.add_option('--no-repo-verify',
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500268 dest='repo_verify', default=True, action='store_false',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700269 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700270 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800271 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700272 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700273
Raman Tenneti8d43dea2021-02-07 16:30:27 -0800274 def _GetBranch(self):
275 """Returns the branch name for getting the approved manifest."""
276 p = self.manifest.manifestProject
277 b = p.GetBranch(p.CurrentBranch)
278 branch = b.merge
279 if branch.startswith(R_HEADS):
280 branch = branch[len(R_HEADS):]
281 return branch
282
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800283 def _UpdateProjectsRevisionId(self, opt, args):
284 """Update revisionId of every project with the SHA from superproject.
285
286 This function updates each project's revisionId with SHA from superproject.
287 It writes the updated manifest into a file and reloads the manifest from it.
288
289 Args:
290 opt: Program options returned from optparse. See _Options().
291 args: Arguments to pass to GetProjects. See the GetProjects
292 docstring for details.
293
294 Returns:
295 Returns path to the overriding manifest file.
296 """
Raman Tenneti21dce3d2021-02-09 00:26:31 -0800297 superproject = git_superproject.Superproject(self.manifest,
298 self.repodir)
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800299 all_projects = self.GetProjects(args,
300 missing_ok=True,
301 submodules_ok=opt.fetch_submodules)
Raman Tenneti21dce3d2021-02-09 00:26:31 -0800302 manifest_path = superproject.UpdateProjectsRevisionId(all_projects)
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800303 if not manifest_path:
304 print('error: Update of revsionId from superproject has failed',
305 file=sys.stderr)
306 sys.exit(1)
307 self._ReloadManifest(manifest_path)
308 return manifest_path
309
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500310 def _FetchProjectList(self, opt, projects, sem, *args, **kwargs):
Xin Li745be2e2019-06-03 11:24:30 -0700311 """Main function of the fetch threads.
Roy Lee18afd7f2010-05-09 04:32:08 +0800312
David James8d201162013-10-11 17:03:19 -0700313 Delegates most of the work to _FetchHelper.
314
315 Args:
316 opt: Program options returned from optparse. See _Options().
317 projects: Projects to fetch.
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500318 sem: We'll release() this semaphore when we exit so that another thread
319 can be started up.
David James89ece422014-01-09 18:51:58 -0800320 *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the
David James8d201162013-10-11 17:03:19 -0700321 _FetchHelper docstring for details.
322 """
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500323 try:
324 for project in projects:
325 success = self._FetchHelper(opt, project, *args, **kwargs)
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400326 if not success and opt.fail_fast:
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500327 break
328 finally:
329 sem.release()
David James8d201162013-10-11 17:03:19 -0700330
Xin Li745be2e2019-06-03 11:24:30 -0700331 def _FetchHelper(self, opt, project, lock, fetched, pm, err_event,
332 clone_filter):
David James8d201162013-10-11 17:03:19 -0700333 """Fetch git objects for a single project.
334
David Pursehousec1b86a22012-11-14 11:36:51 +0900335 Args:
336 opt: Program options returned from optparse. See _Options().
337 project: Project object for the project to fetch.
338 lock: Lock for accessing objects that are shared amongst multiple
339 _FetchHelper() threads.
340 fetched: set object that we will add project.gitdir to when we're done
341 (with our lock held).
342 pm: Instance of a Project object. We will call pm.update() (with our
343 lock held).
David Pursehousec1b86a22012-11-14 11:36:51 +0900344 err_event: We'll set this event in the case of an error (after printing
345 out info about the error).
Xin Li745be2e2019-06-03 11:24:30 -0700346 clone_filter: Filter for use in a partial clone.
David James8d201162013-10-11 17:03:19 -0700347
348 Returns:
349 Whether the fetch was successful.
David Pursehousec1b86a22012-11-14 11:36:51 +0900350 """
351 # We'll set to true once we've locked the lock.
352 did_lock = False
Doug Andersonfc06ced2011-03-16 15:49:18 -0700353
David Pursehousec1b86a22012-11-14 11:36:51 +0900354 # Encapsulate everything in a try/except/finally so that:
355 # - We always set err_event in the case of an exception.
David Pursehousec1b86a22012-11-14 11:36:51 +0900356 # - We always make sure we unlock the lock if we locked it.
David Rileye0684ad2017-04-05 00:02:59 -0700357 start = time.time()
358 success = False
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)
Mike Frysinger3538dd22019-08-26 15:32:06 -0400388 pm.update(msg=project.name)
David Pursehousec1b86a22012-11-14 11:36:51 +0900389 except _FetchError:
Hu Xiuyune9becc02015-11-25 15:52:26 +0800390 pass
Dan Sandlerc5cd4332015-07-31 09:37:53 -0400391 except Exception as e:
David Pursehouse42339d72020-02-12 14:37:15 +0900392 print('error: Cannot fetch %s (%s: %s)'
David Pursehouseabdf7502020-02-12 14:58:39 +0900393 % (project.name, type(e).__name__, str(e)), file=sys.stderr)
David Pursehousec1b86a22012-11-14 11:36:51 +0900394 err_event.set()
395 raise
396 finally:
397 if did_lock:
398 lock.release()
David Rileye0684ad2017-04-05 00:02:59 -0700399 finish = time.time()
400 self.event_log.AddSync(project, event_log.TASK_SYNC_NETWORK,
401 start, finish, success)
Roy Lee18afd7f2010-05-09 04:32:08 +0800402
David James8d201162013-10-11 17:03:19 -0700403 return success
404
Mike Frysinger5a033082019-09-23 19:21:20 -0400405 def _Fetch(self, projects, opt, err_event):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700406 fetched = set()
David James89ece422014-01-09 18:51:58 -0800407 lock = _threading.Lock()
Tim Schumacher913327f2017-06-05 15:01:41 +0200408 pm = Progress('Fetching projects', len(projects),
Tim Schumacher7be072e2017-06-28 18:29:23 +0200409 always_print_percentage=opt.quiet)
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 Frysingerd9e5cf02019-08-26 03:12:55 -0400420 if err_event.isSet() 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
499 try:
500 try:
501 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
Xin Li745be2e2019-06-03 11:24:30 -0700502
503 # Lock around all the rest of the code, since printing, updating a set
504 # and Progress.update() are not thread safe.
505 lock.acquire()
Mike Frysinger3538dd22019-08-26 15:32:06 -0400506 success = syncbuf.Finish()
Xin Li745be2e2019-06-03 11:24:30 -0700507 did_lock = True
508
509 if not success:
510 err_event.set()
511 print('error: Cannot checkout %s' % (project.name),
512 file=sys.stderr)
513 raise _CheckoutError()
514
Mike Frysinger3538dd22019-08-26 15:32:06 -0400515 pm.update(msg=project.name)
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:
525 if did_lock:
Vadim Bendeburydff91942019-11-06 11:05:00 -0800526 if not success:
527 err_results.append(project.relpath)
Xin Li745be2e2019-06-03 11:24:30 -0700528 lock.release()
529 finish = time.time()
530 self.event_log.AddSync(project, event_log.TASK_SYNC_LOCAL,
531 start, finish, success)
532
533 return success
534
Mike Frysinger5a033082019-09-23 19:21:20 -0400535 def _Checkout(self, all_projects, opt, err_event, err_results):
Xin Li745be2e2019-06-03 11:24:30 -0700536 """Checkout projects listed in all_projects
537
538 Args:
539 all_projects: List of all projects that should be checked out.
540 opt: Program options returned from optparse. See _Options().
Mike Frysinger5a033082019-09-23 19:21:20 -0400541 err_event: We'll set this event in the case of an error (after printing
542 out info about the error).
543 err_results: A list of strings, paths to git repos where checkout
544 failed.
Xin Li745be2e2019-06-03 11:24:30 -0700545 """
546
547 # Perform checkouts in multiple threads when we are using partial clone.
548 # Without partial clone, all needed git objects are already downloaded,
549 # in this situation it's better to use only one process because the checkout
550 # would be mostly disk I/O; with partial clone, the objects are only
551 # downloaded when demanded (at checkout time), which is similar to the
552 # Sync_NetworkHalf case and parallelism would be helpful.
553 if self.manifest.CloneFilter:
554 syncjobs = self.jobs
555 else:
556 syncjobs = 1
557
558 lock = _threading.Lock()
Mike Frysinger3538dd22019-08-26 15:32:06 -0400559 pm = Progress('Checking out projects', len(all_projects))
Xin Li745be2e2019-06-03 11:24:30 -0700560
561 threads = set()
562 sem = _threading.Semaphore(syncjobs)
Xin Li745be2e2019-06-03 11:24:30 -0700563
564 for project in all_projects:
565 # Check for any errors before running any more tasks.
566 # ...we'll let existing threads finish, though.
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400567 if err_event.isSet() and opt.fail_fast:
Xin Li745be2e2019-06-03 11:24:30 -0700568 break
569
570 sem.acquire()
571 if project.worktree:
572 kwargs = dict(opt=opt,
573 sem=sem,
574 project=project,
575 lock=lock,
576 pm=pm,
Vadim Bendeburydff91942019-11-06 11:05:00 -0800577 err_event=err_event,
578 err_results=err_results)
Xin Li745be2e2019-06-03 11:24:30 -0700579 if syncjobs > 1:
580 t = _threading.Thread(target=self._CheckoutWorker,
581 kwargs=kwargs)
582 # Ensure that Ctrl-C will not freeze the repo process.
583 t.daemon = True
584 threads.add(t)
585 t.start()
586 else:
587 self._CheckoutWorker(**kwargs)
588
589 for t in threads:
590 t.join()
591
592 pm.end()
Xin Li745be2e2019-06-03 11:24:30 -0700593
Mike Frysinger5a033082019-09-23 19:21:20 -0400594 def _GCProjects(self, projects, opt, err_event):
Gabe Black2ff30292014-10-09 17:54:35 -0700595 gc_gitdirs = {}
David James8d201162013-10-11 17:03:19 -0700596 for project in projects:
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500597 # Make sure pruning never kicks in with shared projects.
Mike Frysinger979d5bd2020-02-09 02:28:34 -0500598 if (not project.use_git_worktrees and
David Pursehouseaa611a22020-02-20 10:47:26 +0900599 len(project.manifest.GetProjectsWithName(project.name)) > 1):
Anders Björklund2a2da802021-01-18 10:32:36 +0100600 if not opt.quiet:
601 print('%s: Shared project %s found, disabling pruning.' %
602 (project.relpath, project.name))
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500603 if git_require((2, 7, 0)):
Mike Frysingerf81c72e2020-02-19 15:50:00 -0500604 project.EnableRepositoryExtension('preciousObjects')
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500605 else:
606 # This isn't perfect, but it's the best we can do with old git.
607 print('%s: WARNING: shared projects are unreliable when using old '
608 'versions of git; please upgrade to git-2.7.0+.'
609 % (project.relpath,),
610 file=sys.stderr)
611 project.config.SetString('gc.pruneExpire', 'never')
Gabe Black2ff30292014-10-09 17:54:35 -0700612 gc_gitdirs[project.gitdir] = project.bare_git
David James8d201162013-10-11 17:03:19 -0700613
Mike Frysinger6f1c6262020-02-04 00:09:23 -0500614 if multiprocessing:
Dave Borowitz18857212012-10-23 17:02:59 -0700615 cpu_count = multiprocessing.cpu_count()
616 else:
617 cpu_count = 1
618 jobs = min(self.jobs, cpu_count)
619
620 if jobs < 2:
Gabe Black2ff30292014-10-09 17:54:35 -0700621 for bare_git in gc_gitdirs.values():
David James8d201162013-10-11 17:03:19 -0700622 bare_git.gc('--auto')
Dave Borowitz18857212012-10-23 17:02:59 -0700623 return
624
Mike Frysinger0c0e9342019-06-13 12:42:39 -0400625 config = {'pack.threads': cpu_count // jobs if cpu_count > jobs else 1}
Dave Borowitz18857212012-10-23 17:02:59 -0700626
627 threads = set()
628 sem = _threading.Semaphore(jobs)
Dave Borowitz18857212012-10-23 17:02:59 -0700629
David James8d201162013-10-11 17:03:19 -0700630 def GC(bare_git):
Dave Borowitz18857212012-10-23 17:02:59 -0700631 try:
632 try:
David James8d201162013-10-11 17:03:19 -0700633 bare_git.gc('--auto', config=config)
Dave Borowitz18857212012-10-23 17:02:59 -0700634 except GitError:
635 err_event.set()
David Pursehouse145e35b2020-02-12 15:40:47 +0900636 except Exception:
Dave Borowitz18857212012-10-23 17:02:59 -0700637 err_event.set()
638 raise
639 finally:
640 sem.release()
641
Gabe Black2ff30292014-10-09 17:54:35 -0700642 for bare_git in gc_gitdirs.values():
Mike Frysinger5a033082019-09-23 19:21:20 -0400643 if err_event.isSet() and opt.fail_fast:
Dave Borowitz18857212012-10-23 17:02:59 -0700644 break
645 sem.acquire()
David James8d201162013-10-11 17:03:19 -0700646 t = _threading.Thread(target=GC, args=(bare_git,))
Dave Borowitz18857212012-10-23 17:02:59 -0700647 t.daemon = True
648 threads.add(t)
649 t.start()
650
651 for t in threads:
652 t.join()
653
Tim Kilbourn07669002013-03-08 15:02:49 -0800654 def _ReloadManifest(self, manifest_name=None):
655 if manifest_name:
656 # Override calls _Unload already
657 self.manifest.Override(manifest_name)
658 else:
659 self.manifest._Unload()
660
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500661 def UpdateProjectList(self, opt):
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700662 new_project_paths = []
Colin Cross5acde752012-03-28 20:15:45 -0700663 for project in self.GetProjects(None, missing_ok=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700664 if project.relpath:
665 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700666 file_name = 'project.list'
Mike Frysingere3315bb2021-02-09 23:45:28 -0500667 file_path = os.path.join(self.repodir, file_name)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700668 old_project_paths = []
669
670 if os.path.exists(file_path):
Mike Frysinger3164d402019-11-11 05:40:22 -0500671 with open(file_path, 'r') as fd:
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700672 old_project_paths = fd.read().split('\n')
Kuang-che Wu0d9b16d2019-04-06 00:49:47 +0800673 # In reversed order, so subfolders are deleted before parent folder.
674 for path in sorted(old_project_paths, reverse=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700675 if not path:
676 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700677 if path not in new_project_paths:
David Pursehouse8a68ff92012-09-24 12:15:13 +0900678 # If the path has already been deleted, we don't need to do it
Dan Willemsen43507912016-09-01 16:26:02 -0700679 gitdir = os.path.join(self.manifest.topdir, path, '.git')
680 if os.path.exists(gitdir):
David Pursehousec1b86a22012-11-14 11:36:51 +0900681 project = Project(
David Pursehouseabdf7502020-02-12 14:58:39 +0900682 manifest=self.manifest,
683 name=path,
684 remote=RemoteSpec('origin'),
685 gitdir=gitdir,
686 objdir=gitdir,
Mike Frysingerc0d18662020-02-19 19:19:18 -0500687 use_git_worktrees=os.path.isfile(gitdir),
David Pursehouseabdf7502020-02-12 14:58:39 +0900688 worktree=os.path.join(self.manifest.topdir, path),
689 relpath=path,
690 revisionExpr='HEAD',
691 revisionId=None,
692 groups=None)
Mike Frysingerc0d18662020-02-19 19:19:18 -0500693 if not project.DeleteWorktree(
David Pursehouseaa611a22020-02-20 10:47:26 +0900694 quiet=opt.quiet,
695 force=opt.force_remove_dirty):
Mike Frysingera850ca22019-08-07 17:19:24 -0400696 return 1
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700697
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700698 new_project_paths.sort()
Mike Frysinger3164d402019-11-11 05:40:22 -0500699 with open(file_path, 'w') as fd:
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700700 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700701 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700702 return 0
703
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400704 def _SmartSyncSetup(self, opt, smart_sync_manifest_path):
705 if not self.manifest.manifest_server:
706 print('error: cannot smart sync: no manifest server defined in '
707 'manifest', file=sys.stderr)
708 sys.exit(1)
709
710 manifest_server = self.manifest.manifest_server
711 if not opt.quiet:
712 print('Using manifest server %s' % manifest_server)
713
David Pursehouseeeff3532020-02-12 11:24:10 +0900714 if '@' not in manifest_server:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400715 username = None
716 password = None
717 if opt.manifest_server_username and opt.manifest_server_password:
718 username = opt.manifest_server_username
719 password = opt.manifest_server_password
720 else:
721 try:
722 info = netrc.netrc()
723 except IOError:
724 # .netrc file does not exist or could not be opened
725 pass
726 else:
727 try:
728 parse_result = urllib.parse.urlparse(manifest_server)
729 if parse_result.hostname:
730 auth = info.authenticators(parse_result.hostname)
731 if auth:
732 username, _account, password = auth
733 else:
734 print('No credentials found for %s in .netrc'
735 % parse_result.hostname, file=sys.stderr)
736 except netrc.NetrcParseError as e:
737 print('Error parsing .netrc file: %s' % e, file=sys.stderr)
738
739 if (username and password):
740 manifest_server = manifest_server.replace('://', '://%s:%s@' %
741 (username, password),
742 1)
743
744 transport = PersistentTransport(manifest_server)
745 if manifest_server.startswith('persistent-'):
746 manifest_server = manifest_server[len('persistent-'):]
747
748 try:
749 server = xmlrpc.client.Server(manifest_server, transport=transport)
750 if opt.smart_sync:
Raman Tenneti8d43dea2021-02-07 16:30:27 -0800751 branch = self._GetBranch()
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400752
Mike Frysinger56ce3462019-12-04 19:30:48 -0500753 if 'SYNC_TARGET' in os.environ:
Mike Frysingere20da3e2020-03-07 01:53:53 -0500754 target = os.environ['SYNC_TARGET']
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400755 [success, manifest_str] = server.GetApprovedManifest(branch, target)
Mike Frysinger56ce3462019-12-04 19:30:48 -0500756 elif ('TARGET_PRODUCT' in os.environ and
757 'TARGET_BUILD_VARIANT' in os.environ):
Mike Frysingere20da3e2020-03-07 01:53:53 -0500758 target = '%s-%s' % (os.environ['TARGET_PRODUCT'],
759 os.environ['TARGET_BUILD_VARIANT'])
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400760 [success, manifest_str] = server.GetApprovedManifest(branch, target)
761 else:
762 [success, manifest_str] = server.GetApprovedManifest(branch)
763 else:
764 assert(opt.smart_tag)
765 [success, manifest_str] = server.GetManifest(opt.smart_tag)
766
767 if success:
768 manifest_name = os.path.basename(smart_sync_manifest_path)
769 try:
Mike Frysinger3164d402019-11-11 05:40:22 -0500770 with open(smart_sync_manifest_path, 'w') as f:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400771 f.write(manifest_str)
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400772 except IOError as e:
773 print('error: cannot write manifest to %s:\n%s'
774 % (smart_sync_manifest_path, e),
775 file=sys.stderr)
776 sys.exit(1)
777 self._ReloadManifest(manifest_name)
778 else:
779 print('error: manifest server RPC call failed: %s' %
780 manifest_str, file=sys.stderr)
781 sys.exit(1)
782 except (socket.error, IOError, xmlrpc.client.Fault) as e:
783 print('error: cannot connect to manifest server %s:\n%s'
784 % (self.manifest.manifest_server, e), file=sys.stderr)
785 sys.exit(1)
786 except xmlrpc.client.ProtocolError as e:
787 print('error: cannot connect to manifest server %s:\n%d %s'
788 % (self.manifest.manifest_server, e.errcode, e.errmsg),
789 file=sys.stderr)
790 sys.exit(1)
791
792 return manifest_name
793
Mike Frysingerfb527e32019-08-27 02:34:32 -0400794 def _UpdateManifestProject(self, opt, mp, manifest_name):
795 """Fetch & update the local manifest project."""
796 if not opt.local_only:
797 start = time.time()
Mike Frysinger521d01b2020-02-17 01:51:49 -0500798 success = mp.Sync_NetworkHalf(quiet=opt.quiet, verbose=opt.verbose,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400799 current_branch_only=opt.current_branch_only,
Erwan Yvindc5c4d12019-06-18 13:49:12 +0200800 force_sync=opt.force_sync,
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500801 tags=opt.tags,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400802 optimized_fetch=opt.optimized_fetch,
George Engelbrecht9bc283e2020-04-02 12:36:09 -0600803 retry_fetches=opt.retry_fetches,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400804 submodules=self.manifest.HasSubmodules,
805 clone_filter=self.manifest.CloneFilter)
806 finish = time.time()
807 self.event_log.AddSync(mp, event_log.TASK_SYNC_NETWORK,
808 start, finish, success)
809
810 if mp.HasChanges:
811 syncbuf = SyncBuffer(mp.config)
812 start = time.time()
813 mp.Sync_LocalHalf(syncbuf, submodules=self.manifest.HasSubmodules)
814 clean = syncbuf.Finish()
815 self.event_log.AddSync(mp, event_log.TASK_SYNC_LOCAL,
816 start, time.time(), clean)
817 if not clean:
818 sys.exit(1)
819 self._ReloadManifest(opt.manifest_name)
820 if opt.jobs is None:
821 self.jobs = self.manifest.default.sync_j
822
Mike Frysingerae6cb082019-08-27 01:10:59 -0400823 def ValidateOptions(self, opt, args):
824 if opt.force_broken:
825 print('warning: -f/--force-broken is now the default behavior, and the '
826 'options are deprecated', file=sys.stderr)
827 if opt.network_only and opt.detach_head:
828 self.OptionParser.error('cannot combine -n and -d')
829 if opt.network_only and opt.local_only:
830 self.OptionParser.error('cannot combine -n and -l')
831 if opt.manifest_name and opt.smart_sync:
832 self.OptionParser.error('cannot combine -m and -s')
833 if opt.manifest_name and opt.smart_tag:
834 self.OptionParser.error('cannot combine -m and -t')
835 if opt.manifest_server_username or opt.manifest_server_password:
836 if not (opt.smart_sync or opt.smart_tag):
837 self.OptionParser.error('-u and -p may only be combined with -s or -t')
838 if None in [opt.manifest_server_username, opt.manifest_server_password]:
839 self.OptionParser.error('both -u and -p must be given')
840
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700841 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800842 if opt.jobs:
843 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700844 if self.jobs > 1:
845 soft_limit, _ = _rlimit_nofile()
Mike Frysinger0c0e9342019-06-13 12:42:39 -0400846 self.jobs = min(self.jobs, (soft_limit - 5) // 3)
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700847
Mike Frysinger521d01b2020-02-17 01:51:49 -0500848 opt.quiet = opt.output_mode is False
849 opt.verbose = opt.output_mode is True
850
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500851 if opt.manifest_name:
852 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700853
Chirayu Desaia892b102013-06-11 14:18:46 +0530854 manifest_name = opt.manifest_name
David Pursehouse59b41742015-05-07 14:36:09 +0900855 smart_sync_manifest_path = os.path.join(
David Pursehouseabdf7502020-02-12 14:58:39 +0900856 self.manifest.manifestProject.worktree, 'smart_sync_override.xml')
Chirayu Desaia892b102013-06-11 14:18:46 +0530857
Xin Lid79a4bc2020-05-20 16:03:45 -0700858 if opt.clone_bundle is None:
859 opt.clone_bundle = self.manifest.CloneBundle
860
Victor Boivie08c880d2011-04-19 10:32:52 +0200861 if opt.smart_sync or opt.smart_tag:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400862 manifest_name = self._SmartSyncSetup(opt, smart_sync_manifest_path)
863 else:
David Pursehouse59b41742015-05-07 14:36:09 +0900864 if os.path.isfile(smart_sync_manifest_path):
865 try:
Renaud Paquay010fed72016-11-11 14:25:29 -0800866 platform_utils.remove(smart_sync_manifest_path)
David Pursehouse59b41742015-05-07 14:36:09 +0900867 except OSError as e:
868 print('error: failed to remove existing smart sync override manifest: %s' %
869 e, file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700870
Mike Frysinger5a033082019-09-23 19:21:20 -0400871 err_event = _threading.Event()
872
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700873 rp = self.manifest.repoProject
874 rp.PreSync()
Mike Frysinger23c900f2020-02-29 02:52:44 -0500875 cb = rp.CurrentBranch
876 if cb:
877 base = rp.GetBranch(cb).merge
878 if not base or not base.startswith('refs/heads/'):
879 print('warning: repo is not tracking a remote branch, so it will not '
Mike Frysinger58ac1672020-03-14 14:35:26 -0400880 'receive updates; run `repo init --repo-rev=stable` to fix.',
Mike Frysinger23c900f2020-02-29 02:52:44 -0500881 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700882
883 mp = self.manifest.manifestProject
884 mp.PreSync()
885
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800886 if opt.repo_upgraded:
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700887 _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800888
Fredrik de Grootcc960972019-11-22 09:04:31 +0100889 if not opt.mp_update:
890 print('Skipping update of local manifest project.')
891 else:
892 self._UpdateManifestProject(opt, mp, manifest_name)
Simran Basib9a1b732015-08-20 12:19:28 -0700893
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800894 if opt.use_superproject:
895 manifest_name = self._UpdateProjectsRevisionId(opt, args)
896
Simran Basib9a1b732015-08-20 12:19:28 -0700897 if self.gitc_manifest:
898 gitc_manifest_projects = self.GetProjects(args,
Simran Basib9a1b732015-08-20 12:19:28 -0700899 missing_ok=True)
900 gitc_projects = []
901 opened_projects = []
902 for project in gitc_manifest_projects:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700903 if project.relpath in self.gitc_manifest.paths and \
904 self.gitc_manifest.paths[project.relpath].old_revision:
905 opened_projects.append(project.relpath)
Simran Basib9a1b732015-08-20 12:19:28 -0700906 else:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700907 gitc_projects.append(project.relpath)
Simran Basib9a1b732015-08-20 12:19:28 -0700908
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700909 if not args:
910 gitc_projects = None
911
912 if gitc_projects != [] and not opt.local_only:
Simran Basib9a1b732015-08-20 12:19:28 -0700913 print('Updating GITC client: %s' % self.gitc_manifest.gitc_client_name)
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700914 manifest = GitcManifest(self.repodir, self.gitc_manifest.gitc_client_name)
915 if manifest_name:
916 manifest.Override(manifest_name)
917 else:
918 manifest.Override(self.manifest.manifestFile)
919 gitc_utils.generate_gitc_manifest(self.gitc_manifest,
920 manifest,
Simran Basib9a1b732015-08-20 12:19:28 -0700921 gitc_projects)
922 print('GITC client successfully synced.')
923
924 # The opened projects need to be synced as normal, therefore we
925 # generate a new args list to represent the opened projects.
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700926 # TODO: make this more reliable -- if there's a project name/path overlap,
927 # this may choose the wrong project.
David Pursehouse3bcd3052017-07-10 22:42:22 +0900928 args = [os.path.relpath(self.manifest.paths[path].worktree, os.getcwd())
929 for path in opened_projects]
Simran Basib9a1b732015-08-20 12:19:28 -0700930 if not args:
931 return
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800932 all_projects = self.GetProjects(args,
933 missing_ok=True,
934 submodules_ok=opt.fetch_submodules)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700935
Mike Frysinger5a033082019-09-23 19:21:20 -0400936 err_network_sync = False
937 err_update_projects = False
938 err_checkout = False
939
Dave Borowitz67700e92012-10-23 15:00:54 -0700940 self._fetch_times = _FetchTimes(self.manifest)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700941 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700942 to_fetch = []
943 now = time.time()
Dave Borowitz67700e92012-10-23 15:00:54 -0700944 if _ONE_DAY_S <= (now - rp.LastFetch):
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700945 to_fetch.append(rp)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900946 to_fetch.extend(all_projects)
Dave Borowitz67700e92012-10-23 15:00:54 -0700947 to_fetch.sort(key=self._fetch_times.Get, reverse=True)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700948
Mike Frysinger5a033082019-09-23 19:21:20 -0400949 fetched = self._Fetch(to_fetch, opt, err_event)
950
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500951 _PostRepoFetch(rp, opt.repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700952 if opt.network_only:
953 # bail out now; the rest touches the working tree
Mike Frysinger5a033082019-09-23 19:21:20 -0400954 if err_event.isSet():
955 print('\nerror: Exited sync due to fetch errors.\n', file=sys.stderr)
956 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700957 return
958
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800959 # Iteratively fetch missing and/or nested unregistered submodules
960 previously_missing_set = set()
961 while True:
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100962 self._ReloadManifest(manifest_name)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800963 all_projects = self.GetProjects(args,
964 missing_ok=True,
965 submodules_ok=opt.fetch_submodules)
966 missing = []
967 for project in all_projects:
968 if project.gitdir not in fetched:
969 missing.append(project)
970 if not missing:
971 break
972 # Stop us from non-stopped fetching actually-missing repos: If set of
973 # missing repos has not been changed from last fetch, we break.
974 missing_set = set(p.name for p in missing)
975 if previously_missing_set == missing_set:
976 break
977 previously_missing_set = missing_set
Mike Frysinger5a033082019-09-23 19:21:20 -0400978 fetched.update(self._Fetch(missing, opt, err_event))
979
980 # If we saw an error, exit with code 1 so that other scripts can check.
981 if err_event.isSet():
982 err_network_sync = True
983 if opt.fail_fast:
984 print('\nerror: Exited sync due to fetch errors.\n'
985 'Local checkouts *not* updated. Resolve network issues & '
986 'retry.\n'
987 '`repo sync -l` will update some local checkouts.',
988 file=sys.stderr)
989 sys.exit(1)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800990
Julien Campergue335f5ef2013-10-16 11:02:35 +0200991 if self.manifest.IsMirror or self.manifest.IsArchive:
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700992 # bail out now, we have no working tree
993 return
994
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500995 if self.UpdateProjectList(opt):
Mike Frysinger5a033082019-09-23 19:21:20 -0400996 err_event.set()
997 err_update_projects = True
998 if opt.fail_fast:
999 print('\nerror: Local checkouts *not* updated.', file=sys.stderr)
1000 sys.exit(1)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -07001001
Mike Frysinger5a033082019-09-23 19:21:20 -04001002 err_results = []
1003 self._Checkout(all_projects, opt, err_event, err_results)
1004 if err_event.isSet():
1005 err_checkout = True
1006 # NB: We don't exit here because this is the last step.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001007
Doug Anderson2b8db3c2010-11-01 15:08:06 -07001008 # If there's a notice that's supposed to print at the end of the sync, print
1009 # it now...
1010 if self.manifest.notice:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001011 print(self.manifest.notice)
Doug Anderson2b8db3c2010-11-01 15:08:06 -07001012
Mike Frysinger5a033082019-09-23 19:21:20 -04001013 # If we saw an error, exit with code 1 so that other scripts can check.
1014 if err_event.isSet():
1015 print('\nerror: Unable to fully sync the tree.', file=sys.stderr)
1016 if err_network_sync:
1017 print('error: Downloading network changes failed.', file=sys.stderr)
1018 if err_update_projects:
1019 print('error: Updating local project lists failed.', file=sys.stderr)
1020 if err_checkout:
1021 print('error: Checking out local projects failed.', file=sys.stderr)
1022 if err_results:
1023 print('Failing repos:\n%s' % '\n'.join(err_results), file=sys.stderr)
1024 print('Try re-running with "-j1 --fail-fast" to exit at the first error.',
1025 file=sys.stderr)
1026 sys.exit(1)
1027
Mike Frysingere19d9e12020-02-12 11:23:32 -05001028 if not opt.quiet:
1029 print('repo sync has finished successfully.')
1030
David Pursehouse819827a2020-02-12 15:20:19 +09001031
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -07001032def _PostRepoUpgrade(manifest, quiet=False):
Conley Owens094cdbe2014-01-30 15:09:59 -08001033 wrapper = Wrapper()
Conley Owensc9129d92012-10-01 16:12:28 -07001034 if wrapper.NeedSetupGnuPG():
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -07001035 wrapper.SetupGnuPG(quiet)
Conley Owensf2fe2d92014-01-29 13:53:43 -08001036 for project in manifest.projects:
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001037 if project.Exists:
1038 project.PostRepoUpgrade()
1039
David Pursehouse819827a2020-02-12 15:20:19 +09001040
Mike Frysingerc58ec4d2020-02-17 14:36:08 -05001041def _PostRepoFetch(rp, repo_verify=True, verbose=False):
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001042 if rp.HasChanges:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001043 print('info: A new version of repo is available', file=sys.stderr)
1044 print(file=sys.stderr)
Mike Frysingerc58ec4d2020-02-17 14:36:08 -05001045 if not repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -07001046 syncbuf = SyncBuffer(rp.config)
1047 rp.Sync_LocalHalf(syncbuf)
1048 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001049 sys.exit(1)
Sarah Owenscecd1d82012-11-01 22:59:27 -07001050 print('info: Restarting repo with latest version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001051 raise RepoChangedException(['--repo-upgraded'])
1052 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001053 print('warning: Skipped upgrade to unverified version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001054 else:
1055 if verbose:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001056 print('repo version %s is current' % rp.work_git.describe(HEAD),
1057 file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001058
David Pursehouse819827a2020-02-12 15:20:19 +09001059
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001060def _VerifyTag(project):
1061 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
1062 if not os.path.exists(gpg_dir):
Sarah Owenscecd1d82012-11-01 22:59:27 -07001063 print('warning: GnuPG was not available during last "repo init"\n'
1064 'warning: Cannot automatically authenticate repo."""',
1065 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001066 return True
1067
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001068 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -07001069 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001070 except GitError:
1071 cur = None
1072
1073 if not cur \
1074 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -07001075 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001076 if rev.startswith(R_HEADS):
1077 rev = rev[len(R_HEADS):]
1078
Sarah Owenscecd1d82012-11-01 22:59:27 -07001079 print(file=sys.stderr)
1080 print("warning: project '%s' branch '%s' is not signed"
1081 % (project.name, rev), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001082 return False
1083
Shawn O. Pearcef18cb762010-12-07 11:41:05 -08001084 env = os.environ.copy()
Mike Frysinger56ce3462019-12-04 19:30:48 -05001085 env['GIT_DIR'] = project.gitdir
1086 env['GNUPGHOME'] = gpg_dir
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001087
1088 cmd = [GIT, 'tag', '-v', cur]
1089 proc = subprocess.Popen(cmd,
David Pursehousee5913ae2020-02-12 13:56:59 +09001090 stdout=subprocess.PIPE,
1091 stderr=subprocess.PIPE,
1092 env=env)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001093 out = proc.stdout.read()
1094 proc.stdout.close()
1095
1096 err = proc.stderr.read()
1097 proc.stderr.close()
1098
1099 if proc.wait() != 0:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001100 print(file=sys.stderr)
1101 print(out, file=sys.stderr)
1102 print(err, file=sys.stderr)
1103 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001104 return False
1105 return True
Dave Borowitz67700e92012-10-23 15:00:54 -07001106
David Rileye0684ad2017-04-05 00:02:59 -07001107
Dave Borowitz67700e92012-10-23 15:00:54 -07001108class _FetchTimes(object):
Dave Borowitzd9478582012-10-23 16:35:39 -07001109 _ALPHA = 0.5
1110
Dave Borowitz67700e92012-10-23 15:00:54 -07001111 def __init__(self, manifest):
Anthony King85b24ac2014-05-06 15:57:48 +01001112 self._path = os.path.join(manifest.repodir, '.repo_fetchtimes.json')
Dave Borowitz67700e92012-10-23 15:00:54 -07001113 self._times = None
Dave Borowitzd9478582012-10-23 16:35:39 -07001114 self._seen = set()
Dave Borowitz67700e92012-10-23 15:00:54 -07001115
1116 def Get(self, project):
1117 self._Load()
1118 return self._times.get(project.name, _ONE_DAY_S)
1119
1120 def Set(self, project, t):
Dave Borowitzd9478582012-10-23 16:35:39 -07001121 self._Load()
1122 name = project.name
1123 old = self._times.get(name, t)
1124 self._seen.add(name)
1125 a = self._ALPHA
David Pursehouse54a4e602020-02-12 14:31:05 +09001126 self._times[name] = (a * t) + ((1 - a) * old)
Dave Borowitz67700e92012-10-23 15:00:54 -07001127
1128 def _Load(self):
1129 if self._times is None:
1130 try:
Mike Frysinger3164d402019-11-11 05:40:22 -05001131 with open(self._path) as f:
Anthony King85b24ac2014-05-06 15:57:48 +01001132 self._times = json.load(f)
Anthony King85b24ac2014-05-06 15:57:48 +01001133 except (IOError, ValueError):
1134 try:
Renaud Paquay010fed72016-11-11 14:25:29 -08001135 platform_utils.remove(self._path)
Anthony King85b24ac2014-05-06 15:57:48 +01001136 except OSError:
1137 pass
1138 self._times = {}
Dave Borowitz67700e92012-10-23 15:00:54 -07001139
1140 def Save(self):
1141 if self._times is None:
1142 return
Dave Borowitzd9478582012-10-23 16:35:39 -07001143
1144 to_delete = []
1145 for name in self._times:
1146 if name not in self._seen:
1147 to_delete.append(name)
1148 for name in to_delete:
1149 del self._times[name]
1150
Dave Borowitz67700e92012-10-23 15:00:54 -07001151 try:
Mike Frysinger3164d402019-11-11 05:40:22 -05001152 with open(self._path, 'w') as f:
Anthony King85b24ac2014-05-06 15:57:48 +01001153 json.dump(self._times, f, indent=2)
Anthony King85b24ac2014-05-06 15:57:48 +01001154 except (IOError, TypeError):
1155 try:
Renaud Paquay010fed72016-11-11 14:25:29 -08001156 platform_utils.remove(self._path)
Anthony King85b24ac2014-05-06 15:57:48 +01001157 except OSError:
1158 pass
Dan Willemsen0745bb22015-08-17 13:41:45 -07001159
1160# This is a replacement for xmlrpc.client.Transport using urllib2
1161# and supporting persistent-http[s]. It cannot change hosts from
1162# request to request like the normal transport, the real url
1163# is passed during initialization.
David Pursehouse819827a2020-02-12 15:20:19 +09001164
1165
Dan Willemsen0745bb22015-08-17 13:41:45 -07001166class PersistentTransport(xmlrpc.client.Transport):
1167 def __init__(self, orig_host):
1168 self.orig_host = orig_host
1169
1170 def request(self, host, handler, request_body, verbose=False):
1171 with GetUrlCookieFile(self.orig_host, not verbose) as (cookiefile, proxy):
1172 # Python doesn't understand cookies with the #HttpOnly_ prefix
1173 # Since we're only using them for HTTP, copy the file temporarily,
1174 # stripping those prefixes away.
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001175 if cookiefile:
Collin Fijalkoviche1191b32020-02-18 10:57:32 -08001176 tmpcookiefile = tempfile.NamedTemporaryFile(mode='w')
David Pursehouse4c5f74e2015-10-02 11:10:10 +09001177 tmpcookiefile.write("# HTTP Cookie File")
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001178 try:
1179 with open(cookiefile) as f:
1180 for line in f:
1181 if line.startswith("#HttpOnly_"):
1182 line = line[len("#HttpOnly_"):]
1183 tmpcookiefile.write(line)
1184 tmpcookiefile.flush()
Dan Willemsen0745bb22015-08-17 13:41:45 -07001185
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001186 cookiejar = cookielib.MozillaCookieJar(tmpcookiefile.name)
David Pursehouseb1ad2192015-09-30 10:35:43 +09001187 try:
1188 cookiejar.load()
1189 except cookielib.LoadError:
1190 cookiejar = cookielib.CookieJar()
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001191 finally:
1192 tmpcookiefile.close()
1193 else:
1194 cookiejar = cookielib.CookieJar()
Dan Willemsen0745bb22015-08-17 13:41:45 -07001195
1196 proxyhandler = urllib.request.ProxyHandler
1197 if proxy:
1198 proxyhandler = urllib.request.ProxyHandler({
1199 "http": proxy,
David Pursehouse54a4e602020-02-12 14:31:05 +09001200 "https": proxy})
Dan Willemsen0745bb22015-08-17 13:41:45 -07001201
1202 opener = urllib.request.build_opener(
1203 urllib.request.HTTPCookieProcessor(cookiejar),
1204 proxyhandler)
1205
1206 url = urllib.parse.urljoin(self.orig_host, handler)
1207 parse_results = urllib.parse.urlparse(url)
1208
1209 scheme = parse_results.scheme
1210 if scheme == 'persistent-http':
1211 scheme = 'http'
1212 if scheme == 'persistent-https':
1213 # If we're proxying through persistent-https, use http. The
1214 # proxy itself will do the https.
1215 if proxy:
1216 scheme = 'http'
1217 else:
1218 scheme = 'https'
1219
1220 # Parse out any authentication information using the base class
1221 host, extra_headers, _ = self.get_host_info(parse_results.netloc)
1222
1223 url = urllib.parse.urlunparse((
1224 scheme,
1225 host,
1226 parse_results.path,
1227 parse_results.params,
1228 parse_results.query,
1229 parse_results.fragment))
1230
1231 request = urllib.request.Request(url, request_body)
1232 if extra_headers is not None:
1233 for (name, header) in extra_headers:
1234 request.add_header(name, header)
1235 request.add_header('Content-Type', 'text/xml')
1236 try:
1237 response = opener.open(request)
1238 except urllib.error.HTTPError as e:
1239 if e.code == 501:
1240 # We may have been redirected through a login process
1241 # but our POST turned into a GET. Retry.
1242 response = opener.open(request)
1243 else:
1244 raise
1245
1246 p, u = xmlrpc.client.getparser()
1247 while 1:
1248 data = response.read(1024)
1249 if not data:
1250 break
1251 p.feed(data)
1252 p.close()
1253 return u.close()
1254
1255 def close(self):
1256 pass