blob: c0f605a81b45710bebbc0b7723c7294563ce5d9d [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 Tenneti1fd7bc22021-02-04 14:39:38 -0800274 def _UpdateProjectsRevisionId(self, opt, args):
275 """Update revisionId of every project with the SHA from superproject.
276
277 This function updates each project's revisionId with SHA from superproject.
278 It writes the updated manifest into a file and reloads the manifest from it.
279
280 Args:
281 opt: Program options returned from optparse. See _Options().
282 args: Arguments to pass to GetProjects. See the GetProjects
283 docstring for details.
284
285 Returns:
286 Returns path to the overriding manifest file.
287 """
288 if not self.manifest.superproject:
289 print('error: superproject tag is not defined in manifest.xml',
290 file=sys.stderr)
291 sys.exit(1)
292 print('WARNING: --use-superproject is experimental and not '
293 'for general use', file=sys.stderr)
294
295 superproject_url = self.manifest.superproject['remote'].url
296 if not superproject_url:
297 print('error: superproject URL is not defined in manifest.xml',
298 file=sys.stderr)
299 sys.exit(1)
300
301 superproject = git_superproject.Superproject(self.manifest.repodir)
302 all_projects = self.GetProjects(args,
303 missing_ok=True,
304 submodules_ok=opt.fetch_submodules)
305 manifest_path = superproject.UpdateProjectsRevisionId(self.manifest,
306 all_projects,
307 url=superproject_url)
308 if not manifest_path:
309 print('error: Update of revsionId from superproject has failed',
310 file=sys.stderr)
311 sys.exit(1)
312 self._ReloadManifest(manifest_path)
313 return manifest_path
314
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500315 def _FetchProjectList(self, opt, projects, sem, *args, **kwargs):
Xin Li745be2e2019-06-03 11:24:30 -0700316 """Main function of the fetch threads.
Roy Lee18afd7f2010-05-09 04:32:08 +0800317
David James8d201162013-10-11 17:03:19 -0700318 Delegates most of the work to _FetchHelper.
319
320 Args:
321 opt: Program options returned from optparse. See _Options().
322 projects: Projects to fetch.
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500323 sem: We'll release() this semaphore when we exit so that another thread
324 can be started up.
David James89ece422014-01-09 18:51:58 -0800325 *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the
David James8d201162013-10-11 17:03:19 -0700326 _FetchHelper docstring for details.
327 """
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500328 try:
329 for project in projects:
330 success = self._FetchHelper(opt, project, *args, **kwargs)
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400331 if not success and opt.fail_fast:
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500332 break
333 finally:
334 sem.release()
David James8d201162013-10-11 17:03:19 -0700335
Xin Li745be2e2019-06-03 11:24:30 -0700336 def _FetchHelper(self, opt, project, lock, fetched, pm, err_event,
337 clone_filter):
David James8d201162013-10-11 17:03:19 -0700338 """Fetch git objects for a single project.
339
David Pursehousec1b86a22012-11-14 11:36:51 +0900340 Args:
341 opt: Program options returned from optparse. See _Options().
342 project: Project object for the project to fetch.
343 lock: Lock for accessing objects that are shared amongst multiple
344 _FetchHelper() threads.
345 fetched: set object that we will add project.gitdir to when we're done
346 (with our lock held).
347 pm: Instance of a Project object. We will call pm.update() (with our
348 lock held).
David Pursehousec1b86a22012-11-14 11:36:51 +0900349 err_event: We'll set this event in the case of an error (after printing
350 out info about the error).
Xin Li745be2e2019-06-03 11:24:30 -0700351 clone_filter: Filter for use in a partial clone.
David James8d201162013-10-11 17:03:19 -0700352
353 Returns:
354 Whether the fetch was successful.
David Pursehousec1b86a22012-11-14 11:36:51 +0900355 """
356 # We'll set to true once we've locked the lock.
357 did_lock = False
Doug Andersonfc06ced2011-03-16 15:49:18 -0700358
David Pursehousec1b86a22012-11-14 11:36:51 +0900359 # Encapsulate everything in a try/except/finally so that:
360 # - We always set err_event in the case of an exception.
David Pursehousec1b86a22012-11-14 11:36:51 +0900361 # - We always make sure we unlock the lock if we locked it.
David Rileye0684ad2017-04-05 00:02:59 -0700362 start = time.time()
363 success = False
David Pursehousec1b86a22012-11-14 11:36:51 +0900364 try:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700365 try:
David Pursehousec1b86a22012-11-14 11:36:51 +0900366 success = project.Sync_NetworkHalf(
David Pursehouseabdf7502020-02-12 14:58:39 +0900367 quiet=opt.quiet,
Mike Frysinger521d01b2020-02-17 01:51:49 -0500368 verbose=opt.verbose,
David Pursehouseabdf7502020-02-12 14:58:39 +0900369 current_branch_only=opt.current_branch_only,
370 force_sync=opt.force_sync,
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500371 clone_bundle=opt.clone_bundle,
372 tags=opt.tags, archive=self.manifest.IsArchive,
David Pursehouseabdf7502020-02-12 14:58:39 +0900373 optimized_fetch=opt.optimized_fetch,
George Engelbrecht9bc283e2020-04-02 12:36:09 -0600374 retry_fetches=opt.retry_fetches,
David Pursehouseabdf7502020-02-12 14:58:39 +0900375 prune=opt.prune,
376 clone_filter=clone_filter)
David Pursehousec1b86a22012-11-14 11:36:51 +0900377 self._fetch_times.Set(project, time.time() - start)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700378
David Pursehousec1b86a22012-11-14 11:36:51 +0900379 # Lock around all the rest of the code, since printing, updating a set
380 # and Progress.update() are not thread safe.
381 lock.acquire()
382 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700383
David Pursehousec1b86a22012-11-14 11:36:51 +0900384 if not success:
Hu Xiuyune9becc02015-11-25 15:52:26 +0800385 err_event.set()
Marc Herbertffb4b892017-04-04 22:03:53 -0700386 print('error: Cannot fetch %s from %s'
387 % (project.name, project.remote.url),
388 file=sys.stderr)
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400389 if opt.fail_fast:
David Pursehousec1b86a22012-11-14 11:36:51 +0900390 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700391
David Pursehousec1b86a22012-11-14 11:36:51 +0900392 fetched.add(project.gitdir)
Mike Frysinger3538dd22019-08-26 15:32:06 -0400393 pm.update(msg=project.name)
David Pursehousec1b86a22012-11-14 11:36:51 +0900394 except _FetchError:
Hu Xiuyune9becc02015-11-25 15:52:26 +0800395 pass
Dan Sandlerc5cd4332015-07-31 09:37:53 -0400396 except Exception as e:
David Pursehouse42339d72020-02-12 14:37:15 +0900397 print('error: Cannot fetch %s (%s: %s)'
David Pursehouseabdf7502020-02-12 14:58:39 +0900398 % (project.name, type(e).__name__, str(e)), file=sys.stderr)
David Pursehousec1b86a22012-11-14 11:36:51 +0900399 err_event.set()
400 raise
401 finally:
402 if did_lock:
403 lock.release()
David Rileye0684ad2017-04-05 00:02:59 -0700404 finish = time.time()
405 self.event_log.AddSync(project, event_log.TASK_SYNC_NETWORK,
406 start, finish, success)
Roy Lee18afd7f2010-05-09 04:32:08 +0800407
David James8d201162013-10-11 17:03:19 -0700408 return success
409
Mike Frysinger5a033082019-09-23 19:21:20 -0400410 def _Fetch(self, projects, opt, err_event):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700411 fetched = set()
David James89ece422014-01-09 18:51:58 -0800412 lock = _threading.Lock()
Tim Schumacher913327f2017-06-05 15:01:41 +0200413 pm = Progress('Fetching projects', len(projects),
Tim Schumacher7be072e2017-06-28 18:29:23 +0200414 always_print_percentage=opt.quiet)
Roy Lee18afd7f2010-05-09 04:32:08 +0800415
David James89ece422014-01-09 18:51:58 -0800416 objdir_project_map = dict()
417 for project in projects:
418 objdir_project_map.setdefault(project.objdir, []).append(project)
David James8d201162013-10-11 17:03:19 -0700419
David James89ece422014-01-09 18:51:58 -0800420 threads = set()
421 sem = _threading.Semaphore(self.jobs)
David James89ece422014-01-09 18:51:58 -0800422 for project_list in objdir_project_map.values():
423 # Check for any errors before running any more tasks.
424 # ...we'll let existing threads finish, though.
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400425 if err_event.isSet() and opt.fail_fast:
David James89ece422014-01-09 18:51:58 -0800426 break
Doug Andersonfc06ced2011-03-16 15:49:18 -0700427
David James89ece422014-01-09 18:51:58 -0800428 sem.acquire()
429 kwargs = dict(opt=opt,
430 projects=project_list,
Andrew Wheeler7f1ccfb2016-06-17 16:51:07 -0500431 sem=sem,
David James89ece422014-01-09 18:51:58 -0800432 lock=lock,
433 fetched=fetched,
434 pm=pm,
Xin Li745be2e2019-06-03 11:24:30 -0700435 err_event=err_event,
436 clone_filter=self.manifest.CloneFilter)
David James89ece422014-01-09 18:51:58 -0800437 if self.jobs > 1:
David Pursehousee5913ae2020-02-12 13:56:59 +0900438 t = _threading.Thread(target=self._FetchProjectList,
439 kwargs=kwargs)
David 'Digit' Turnere2126652012-09-05 10:35:06 +0200440 # Ensure that Ctrl-C will not freeze the repo process.
441 t.daemon = True
Roy Lee18afd7f2010-05-09 04:32:08 +0800442 threads.add(t)
443 t.start()
David James89ece422014-01-09 18:51:58 -0800444 else:
445 self._FetchProjectList(**kwargs)
Roy Lee18afd7f2010-05-09 04:32:08 +0800446
David James89ece422014-01-09 18:51:58 -0800447 for t in threads:
448 t.join()
Roy Lee18afd7f2010-05-09 04:32:08 +0800449
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700450 pm.end()
Dave Borowitz67700e92012-10-23 15:00:54 -0700451 self._fetch_times.Save()
Dave Borowitz18857212012-10-23 17:02:59 -0700452
Julien Campergue335f5ef2013-10-16 11:02:35 +0200453 if not self.manifest.IsArchive:
Mike Frysinger5a033082019-09-23 19:21:20 -0400454 self._GCProjects(projects, opt, err_event)
Julien Campergue335f5ef2013-10-16 11:02:35 +0200455
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700456 return fetched
457
Xin Li745be2e2019-06-03 11:24:30 -0700458 def _CheckoutWorker(self, opt, sem, project, *args, **kwargs):
459 """Main function of the fetch threads.
460
461 Delegates most of the work to _CheckoutOne.
462
463 Args:
464 opt: Program options returned from optparse. See _Options().
465 projects: Projects to fetch.
466 sem: We'll release() this semaphore when we exit so that another thread
467 can be started up.
468 *args, **kwargs: Remaining arguments to pass to _CheckoutOne. See the
469 _CheckoutOne docstring for details.
470 """
471 try:
Mike Frysingera34186e2019-08-07 18:07:31 -0400472 return self._CheckoutOne(opt, project, *args, **kwargs)
Xin Li745be2e2019-06-03 11:24:30 -0700473 finally:
474 sem.release()
475
Vadim Bendeburydff91942019-11-06 11:05:00 -0800476 def _CheckoutOne(self, opt, project, lock, pm, err_event, err_results):
Xin Li745be2e2019-06-03 11:24:30 -0700477 """Checkout work tree for one project
478
479 Args:
480 opt: Program options returned from optparse. See _Options().
481 project: Project object for the project to checkout.
482 lock: Lock for accessing objects that are shared amongst multiple
483 _CheckoutWorker() threads.
484 pm: Instance of a Project object. We will call pm.update() (with our
485 lock held).
486 err_event: We'll set this event in the case of an error (after printing
487 out info about the error).
Vadim Bendeburydff91942019-11-06 11:05:00 -0800488 err_results: A list of strings, paths to git repos where checkout
489 failed.
Xin Li745be2e2019-06-03 11:24:30 -0700490
491 Returns:
492 Whether the fetch was successful.
493 """
494 # We'll set to true once we've locked the lock.
495 did_lock = False
496
Xin Li745be2e2019-06-03 11:24:30 -0700497 # Encapsulate everything in a try/except/finally so that:
498 # - We always set err_event in the case of an exception.
499 # - We always make sure we unlock the lock if we locked it.
500 start = time.time()
501 syncbuf = SyncBuffer(self.manifest.manifestProject.config,
502 detach_head=opt.detach_head)
503 success = False
504 try:
505 try:
506 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
Xin Li745be2e2019-06-03 11:24:30 -0700507
508 # Lock around all the rest of the code, since printing, updating a set
509 # and Progress.update() are not thread safe.
510 lock.acquire()
Mike Frysinger3538dd22019-08-26 15:32:06 -0400511 success = syncbuf.Finish()
Xin Li745be2e2019-06-03 11:24:30 -0700512 did_lock = True
513
514 if not success:
515 err_event.set()
516 print('error: Cannot checkout %s' % (project.name),
517 file=sys.stderr)
518 raise _CheckoutError()
519
Mike Frysinger3538dd22019-08-26 15:32:06 -0400520 pm.update(msg=project.name)
Xin Li745be2e2019-06-03 11:24:30 -0700521 except _CheckoutError:
522 pass
523 except Exception as e:
524 print('error: Cannot checkout %s: %s: %s' %
525 (project.name, type(e).__name__, str(e)),
526 file=sys.stderr)
527 err_event.set()
528 raise
529 finally:
530 if did_lock:
Vadim Bendeburydff91942019-11-06 11:05:00 -0800531 if not success:
532 err_results.append(project.relpath)
Xin Li745be2e2019-06-03 11:24:30 -0700533 lock.release()
534 finish = time.time()
535 self.event_log.AddSync(project, event_log.TASK_SYNC_LOCAL,
536 start, finish, success)
537
538 return success
539
Mike Frysinger5a033082019-09-23 19:21:20 -0400540 def _Checkout(self, all_projects, opt, err_event, err_results):
Xin Li745be2e2019-06-03 11:24:30 -0700541 """Checkout projects listed in all_projects
542
543 Args:
544 all_projects: List of all projects that should be checked out.
545 opt: Program options returned from optparse. See _Options().
Mike Frysinger5a033082019-09-23 19:21:20 -0400546 err_event: We'll set this event in the case of an error (after printing
547 out info about the error).
548 err_results: A list of strings, paths to git repos where checkout
549 failed.
Xin Li745be2e2019-06-03 11:24:30 -0700550 """
551
552 # Perform checkouts in multiple threads when we are using partial clone.
553 # Without partial clone, all needed git objects are already downloaded,
554 # in this situation it's better to use only one process because the checkout
555 # would be mostly disk I/O; with partial clone, the objects are only
556 # downloaded when demanded (at checkout time), which is similar to the
557 # Sync_NetworkHalf case and parallelism would be helpful.
558 if self.manifest.CloneFilter:
559 syncjobs = self.jobs
560 else:
561 syncjobs = 1
562
563 lock = _threading.Lock()
Mike Frysinger3538dd22019-08-26 15:32:06 -0400564 pm = Progress('Checking out projects', len(all_projects))
Xin Li745be2e2019-06-03 11:24:30 -0700565
566 threads = set()
567 sem = _threading.Semaphore(syncjobs)
Xin Li745be2e2019-06-03 11:24:30 -0700568
569 for project in all_projects:
570 # Check for any errors before running any more tasks.
571 # ...we'll let existing threads finish, though.
Mike Frysingerd9e5cf02019-08-26 03:12:55 -0400572 if err_event.isSet() and opt.fail_fast:
Xin Li745be2e2019-06-03 11:24:30 -0700573 break
574
575 sem.acquire()
576 if project.worktree:
577 kwargs = dict(opt=opt,
578 sem=sem,
579 project=project,
580 lock=lock,
581 pm=pm,
Vadim Bendeburydff91942019-11-06 11:05:00 -0800582 err_event=err_event,
583 err_results=err_results)
Xin Li745be2e2019-06-03 11:24:30 -0700584 if syncjobs > 1:
585 t = _threading.Thread(target=self._CheckoutWorker,
586 kwargs=kwargs)
587 # Ensure that Ctrl-C will not freeze the repo process.
588 t.daemon = True
589 threads.add(t)
590 t.start()
591 else:
592 self._CheckoutWorker(**kwargs)
593
594 for t in threads:
595 t.join()
596
597 pm.end()
Xin Li745be2e2019-06-03 11:24:30 -0700598
Mike Frysinger5a033082019-09-23 19:21:20 -0400599 def _GCProjects(self, projects, opt, err_event):
Gabe Black2ff30292014-10-09 17:54:35 -0700600 gc_gitdirs = {}
David James8d201162013-10-11 17:03:19 -0700601 for project in projects:
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500602 # Make sure pruning never kicks in with shared projects.
Mike Frysinger979d5bd2020-02-09 02:28:34 -0500603 if (not project.use_git_worktrees and
David Pursehouseaa611a22020-02-20 10:47:26 +0900604 len(project.manifest.GetProjectsWithName(project.name)) > 1):
Anders Björklund2a2da802021-01-18 10:32:36 +0100605 if not opt.quiet:
606 print('%s: Shared project %s found, disabling pruning.' %
607 (project.relpath, project.name))
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500608 if git_require((2, 7, 0)):
Mike Frysingerf81c72e2020-02-19 15:50:00 -0500609 project.EnableRepositoryExtension('preciousObjects')
Mike Frysinger5f2b0452020-02-11 03:23:24 -0500610 else:
611 # This isn't perfect, but it's the best we can do with old git.
612 print('%s: WARNING: shared projects are unreliable when using old '
613 'versions of git; please upgrade to git-2.7.0+.'
614 % (project.relpath,),
615 file=sys.stderr)
616 project.config.SetString('gc.pruneExpire', 'never')
Gabe Black2ff30292014-10-09 17:54:35 -0700617 gc_gitdirs[project.gitdir] = project.bare_git
David James8d201162013-10-11 17:03:19 -0700618
Mike Frysinger6f1c6262020-02-04 00:09:23 -0500619 if multiprocessing:
Dave Borowitz18857212012-10-23 17:02:59 -0700620 cpu_count = multiprocessing.cpu_count()
621 else:
622 cpu_count = 1
623 jobs = min(self.jobs, cpu_count)
624
625 if jobs < 2:
Gabe Black2ff30292014-10-09 17:54:35 -0700626 for bare_git in gc_gitdirs.values():
David James8d201162013-10-11 17:03:19 -0700627 bare_git.gc('--auto')
Dave Borowitz18857212012-10-23 17:02:59 -0700628 return
629
Mike Frysinger0c0e9342019-06-13 12:42:39 -0400630 config = {'pack.threads': cpu_count // jobs if cpu_count > jobs else 1}
Dave Borowitz18857212012-10-23 17:02:59 -0700631
632 threads = set()
633 sem = _threading.Semaphore(jobs)
Dave Borowitz18857212012-10-23 17:02:59 -0700634
David James8d201162013-10-11 17:03:19 -0700635 def GC(bare_git):
Dave Borowitz18857212012-10-23 17:02:59 -0700636 try:
637 try:
David James8d201162013-10-11 17:03:19 -0700638 bare_git.gc('--auto', config=config)
Dave Borowitz18857212012-10-23 17:02:59 -0700639 except GitError:
640 err_event.set()
David Pursehouse145e35b2020-02-12 15:40:47 +0900641 except Exception:
Dave Borowitz18857212012-10-23 17:02:59 -0700642 err_event.set()
643 raise
644 finally:
645 sem.release()
646
Gabe Black2ff30292014-10-09 17:54:35 -0700647 for bare_git in gc_gitdirs.values():
Mike Frysinger5a033082019-09-23 19:21:20 -0400648 if err_event.isSet() and opt.fail_fast:
Dave Borowitz18857212012-10-23 17:02:59 -0700649 break
650 sem.acquire()
David James8d201162013-10-11 17:03:19 -0700651 t = _threading.Thread(target=GC, args=(bare_git,))
Dave Borowitz18857212012-10-23 17:02:59 -0700652 t.daemon = True
653 threads.add(t)
654 t.start()
655
656 for t in threads:
657 t.join()
658
Tim Kilbourn07669002013-03-08 15:02:49 -0800659 def _ReloadManifest(self, manifest_name=None):
660 if manifest_name:
661 # Override calls _Unload already
662 self.manifest.Override(manifest_name)
663 else:
664 self.manifest._Unload()
665
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -0500666 def UpdateProjectList(self, opt):
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700667 new_project_paths = []
Colin Cross5acde752012-03-28 20:15:45 -0700668 for project in self.GetProjects(None, missing_ok=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700669 if project.relpath:
670 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700671 file_name = 'project.list'
672 file_path = os.path.join(self.manifest.repodir, file_name)
673 old_project_paths = []
674
675 if os.path.exists(file_path):
Mike Frysinger3164d402019-11-11 05:40:22 -0500676 with open(file_path, 'r') as fd:
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700677 old_project_paths = fd.read().split('\n')
Kuang-che Wu0d9b16d2019-04-06 00:49:47 +0800678 # In reversed order, so subfolders are deleted before parent folder.
679 for path in sorted(old_project_paths, reverse=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700680 if not path:
681 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700682 if path not in new_project_paths:
David Pursehouse8a68ff92012-09-24 12:15:13 +0900683 # If the path has already been deleted, we don't need to do it
Dan Willemsen43507912016-09-01 16:26:02 -0700684 gitdir = os.path.join(self.manifest.topdir, path, '.git')
685 if os.path.exists(gitdir):
David Pursehousec1b86a22012-11-14 11:36:51 +0900686 project = Project(
David Pursehouseabdf7502020-02-12 14:58:39 +0900687 manifest=self.manifest,
688 name=path,
689 remote=RemoteSpec('origin'),
690 gitdir=gitdir,
691 objdir=gitdir,
Mike Frysingerc0d18662020-02-19 19:19:18 -0500692 use_git_worktrees=os.path.isfile(gitdir),
David Pursehouseabdf7502020-02-12 14:58:39 +0900693 worktree=os.path.join(self.manifest.topdir, path),
694 relpath=path,
695 revisionExpr='HEAD',
696 revisionId=None,
697 groups=None)
Mike Frysingerc0d18662020-02-19 19:19:18 -0500698 if not project.DeleteWorktree(
David Pursehouseaa611a22020-02-20 10:47:26 +0900699 quiet=opt.quiet,
700 force=opt.force_remove_dirty):
Mike Frysingera850ca22019-08-07 17:19:24 -0400701 return 1
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700702
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700703 new_project_paths.sort()
Mike Frysinger3164d402019-11-11 05:40:22 -0500704 with open(file_path, 'w') as fd:
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700705 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700706 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700707 return 0
708
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400709 def _SmartSyncSetup(self, opt, smart_sync_manifest_path):
710 if not self.manifest.manifest_server:
711 print('error: cannot smart sync: no manifest server defined in '
712 'manifest', file=sys.stderr)
713 sys.exit(1)
714
715 manifest_server = self.manifest.manifest_server
716 if not opt.quiet:
717 print('Using manifest server %s' % manifest_server)
718
David Pursehouseeeff3532020-02-12 11:24:10 +0900719 if '@' not in manifest_server:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400720 username = None
721 password = None
722 if opt.manifest_server_username and opt.manifest_server_password:
723 username = opt.manifest_server_username
724 password = opt.manifest_server_password
725 else:
726 try:
727 info = netrc.netrc()
728 except IOError:
729 # .netrc file does not exist or could not be opened
730 pass
731 else:
732 try:
733 parse_result = urllib.parse.urlparse(manifest_server)
734 if parse_result.hostname:
735 auth = info.authenticators(parse_result.hostname)
736 if auth:
737 username, _account, password = auth
738 else:
739 print('No credentials found for %s in .netrc'
740 % parse_result.hostname, file=sys.stderr)
741 except netrc.NetrcParseError as e:
742 print('Error parsing .netrc file: %s' % e, file=sys.stderr)
743
744 if (username and password):
745 manifest_server = manifest_server.replace('://', '://%s:%s@' %
746 (username, password),
747 1)
748
749 transport = PersistentTransport(manifest_server)
750 if manifest_server.startswith('persistent-'):
751 manifest_server = manifest_server[len('persistent-'):]
752
753 try:
754 server = xmlrpc.client.Server(manifest_server, transport=transport)
755 if opt.smart_sync:
756 p = self.manifest.manifestProject
757 b = p.GetBranch(p.CurrentBranch)
758 branch = b.merge
759 if branch.startswith(R_HEADS):
760 branch = branch[len(R_HEADS):]
761
Mike Frysinger56ce3462019-12-04 19:30:48 -0500762 if 'SYNC_TARGET' in os.environ:
Mike Frysingere20da3e2020-03-07 01:53:53 -0500763 target = os.environ['SYNC_TARGET']
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400764 [success, manifest_str] = server.GetApprovedManifest(branch, target)
Mike Frysinger56ce3462019-12-04 19:30:48 -0500765 elif ('TARGET_PRODUCT' in os.environ and
766 'TARGET_BUILD_VARIANT' in os.environ):
Mike Frysingere20da3e2020-03-07 01:53:53 -0500767 target = '%s-%s' % (os.environ['TARGET_PRODUCT'],
768 os.environ['TARGET_BUILD_VARIANT'])
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400769 [success, manifest_str] = server.GetApprovedManifest(branch, target)
770 else:
771 [success, manifest_str] = server.GetApprovedManifest(branch)
772 else:
773 assert(opt.smart_tag)
774 [success, manifest_str] = server.GetManifest(opt.smart_tag)
775
776 if success:
777 manifest_name = os.path.basename(smart_sync_manifest_path)
778 try:
Mike Frysinger3164d402019-11-11 05:40:22 -0500779 with open(smart_sync_manifest_path, 'w') as f:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400780 f.write(manifest_str)
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400781 except IOError as e:
782 print('error: cannot write manifest to %s:\n%s'
783 % (smart_sync_manifest_path, e),
784 file=sys.stderr)
785 sys.exit(1)
786 self._ReloadManifest(manifest_name)
787 else:
788 print('error: manifest server RPC call failed: %s' %
789 manifest_str, file=sys.stderr)
790 sys.exit(1)
791 except (socket.error, IOError, xmlrpc.client.Fault) as e:
792 print('error: cannot connect to manifest server %s:\n%s'
793 % (self.manifest.manifest_server, e), file=sys.stderr)
794 sys.exit(1)
795 except xmlrpc.client.ProtocolError as e:
796 print('error: cannot connect to manifest server %s:\n%d %s'
797 % (self.manifest.manifest_server, e.errcode, e.errmsg),
798 file=sys.stderr)
799 sys.exit(1)
800
801 return manifest_name
802
Mike Frysingerfb527e32019-08-27 02:34:32 -0400803 def _UpdateManifestProject(self, opt, mp, manifest_name):
804 """Fetch & update the local manifest project."""
805 if not opt.local_only:
806 start = time.time()
Mike Frysinger521d01b2020-02-17 01:51:49 -0500807 success = mp.Sync_NetworkHalf(quiet=opt.quiet, verbose=opt.verbose,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400808 current_branch_only=opt.current_branch_only,
Erwan Yvindc5c4d12019-06-18 13:49:12 +0200809 force_sync=opt.force_sync,
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500810 tags=opt.tags,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400811 optimized_fetch=opt.optimized_fetch,
George Engelbrecht9bc283e2020-04-02 12:36:09 -0600812 retry_fetches=opt.retry_fetches,
Mike Frysingerfb527e32019-08-27 02:34:32 -0400813 submodules=self.manifest.HasSubmodules,
814 clone_filter=self.manifest.CloneFilter)
815 finish = time.time()
816 self.event_log.AddSync(mp, event_log.TASK_SYNC_NETWORK,
817 start, finish, success)
818
819 if mp.HasChanges:
820 syncbuf = SyncBuffer(mp.config)
821 start = time.time()
822 mp.Sync_LocalHalf(syncbuf, submodules=self.manifest.HasSubmodules)
823 clean = syncbuf.Finish()
824 self.event_log.AddSync(mp, event_log.TASK_SYNC_LOCAL,
825 start, time.time(), clean)
826 if not clean:
827 sys.exit(1)
828 self._ReloadManifest(opt.manifest_name)
829 if opt.jobs is None:
830 self.jobs = self.manifest.default.sync_j
831
Mike Frysingerae6cb082019-08-27 01:10:59 -0400832 def ValidateOptions(self, opt, args):
833 if opt.force_broken:
834 print('warning: -f/--force-broken is now the default behavior, and the '
835 'options are deprecated', file=sys.stderr)
836 if opt.network_only and opt.detach_head:
837 self.OptionParser.error('cannot combine -n and -d')
838 if opt.network_only and opt.local_only:
839 self.OptionParser.error('cannot combine -n and -l')
840 if opt.manifest_name and opt.smart_sync:
841 self.OptionParser.error('cannot combine -m and -s')
842 if opt.manifest_name and opt.smart_tag:
843 self.OptionParser.error('cannot combine -m and -t')
844 if opt.manifest_server_username or opt.manifest_server_password:
845 if not (opt.smart_sync or opt.smart_tag):
846 self.OptionParser.error('-u and -p may only be combined with -s or -t')
847 if None in [opt.manifest_server_username, opt.manifest_server_password]:
848 self.OptionParser.error('both -u and -p must be given')
849
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700850 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800851 if opt.jobs:
852 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700853 if self.jobs > 1:
854 soft_limit, _ = _rlimit_nofile()
Mike Frysinger0c0e9342019-06-13 12:42:39 -0400855 self.jobs = min(self.jobs, (soft_limit - 5) // 3)
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700856
Mike Frysinger521d01b2020-02-17 01:51:49 -0500857 opt.quiet = opt.output_mode is False
858 opt.verbose = opt.output_mode is True
859
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500860 if opt.manifest_name:
861 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700862
Chirayu Desaia892b102013-06-11 14:18:46 +0530863 manifest_name = opt.manifest_name
David Pursehouse59b41742015-05-07 14:36:09 +0900864 smart_sync_manifest_path = os.path.join(
David Pursehouseabdf7502020-02-12 14:58:39 +0900865 self.manifest.manifestProject.worktree, 'smart_sync_override.xml')
Chirayu Desaia892b102013-06-11 14:18:46 +0530866
Xin Lid79a4bc2020-05-20 16:03:45 -0700867 if opt.clone_bundle is None:
868 opt.clone_bundle = self.manifest.CloneBundle
869
Victor Boivie08c880d2011-04-19 10:32:52 +0200870 if opt.smart_sync or opt.smart_tag:
Mike Frysinger01d6c3c2019-08-27 01:56:43 -0400871 manifest_name = self._SmartSyncSetup(opt, smart_sync_manifest_path)
872 else:
David Pursehouse59b41742015-05-07 14:36:09 +0900873 if os.path.isfile(smart_sync_manifest_path):
874 try:
Renaud Paquay010fed72016-11-11 14:25:29 -0800875 platform_utils.remove(smart_sync_manifest_path)
David Pursehouse59b41742015-05-07 14:36:09 +0900876 except OSError as e:
877 print('error: failed to remove existing smart sync override manifest: %s' %
878 e, file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700879
Mike Frysinger5a033082019-09-23 19:21:20 -0400880 err_event = _threading.Event()
881
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700882 rp = self.manifest.repoProject
883 rp.PreSync()
Mike Frysinger23c900f2020-02-29 02:52:44 -0500884 cb = rp.CurrentBranch
885 if cb:
886 base = rp.GetBranch(cb).merge
887 if not base or not base.startswith('refs/heads/'):
888 print('warning: repo is not tracking a remote branch, so it will not '
Mike Frysinger58ac1672020-03-14 14:35:26 -0400889 'receive updates; run `repo init --repo-rev=stable` to fix.',
Mike Frysinger23c900f2020-02-29 02:52:44 -0500890 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700891
892 mp = self.manifest.manifestProject
893 mp.PreSync()
894
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800895 if opt.repo_upgraded:
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700896 _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800897
Fredrik de Grootcc960972019-11-22 09:04:31 +0100898 if not opt.mp_update:
899 print('Skipping update of local manifest project.')
900 else:
901 self._UpdateManifestProject(opt, mp, manifest_name)
Simran Basib9a1b732015-08-20 12:19:28 -0700902
Raman Tenneti1fd7bc22021-02-04 14:39:38 -0800903 if opt.use_superproject:
904 manifest_name = self._UpdateProjectsRevisionId(opt, args)
905
Simran Basib9a1b732015-08-20 12:19:28 -0700906 if self.gitc_manifest:
907 gitc_manifest_projects = self.GetProjects(args,
Simran Basib9a1b732015-08-20 12:19:28 -0700908 missing_ok=True)
909 gitc_projects = []
910 opened_projects = []
911 for project in gitc_manifest_projects:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700912 if project.relpath in self.gitc_manifest.paths and \
913 self.gitc_manifest.paths[project.relpath].old_revision:
914 opened_projects.append(project.relpath)
Simran Basib9a1b732015-08-20 12:19:28 -0700915 else:
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700916 gitc_projects.append(project.relpath)
Simran Basib9a1b732015-08-20 12:19:28 -0700917
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700918 if not args:
919 gitc_projects = None
920
921 if gitc_projects != [] and not opt.local_only:
Simran Basib9a1b732015-08-20 12:19:28 -0700922 print('Updating GITC client: %s' % self.gitc_manifest.gitc_client_name)
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700923 manifest = GitcManifest(self.repodir, self.gitc_manifest.gitc_client_name)
924 if manifest_name:
925 manifest.Override(manifest_name)
926 else:
927 manifest.Override(self.manifest.manifestFile)
928 gitc_utils.generate_gitc_manifest(self.gitc_manifest,
929 manifest,
Simran Basib9a1b732015-08-20 12:19:28 -0700930 gitc_projects)
931 print('GITC client successfully synced.')
932
933 # The opened projects need to be synced as normal, therefore we
934 # generate a new args list to represent the opened projects.
Dan Willemsen5ea32d12015-09-08 13:27:20 -0700935 # TODO: make this more reliable -- if there's a project name/path overlap,
936 # this may choose the wrong project.
David Pursehouse3bcd3052017-07-10 22:42:22 +0900937 args = [os.path.relpath(self.manifest.paths[path].worktree, os.getcwd())
938 for path in opened_projects]
Simran Basib9a1b732015-08-20 12:19:28 -0700939 if not args:
940 return
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800941 all_projects = self.GetProjects(args,
942 missing_ok=True,
943 submodules_ok=opt.fetch_submodules)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700944
Mike Frysinger5a033082019-09-23 19:21:20 -0400945 err_network_sync = False
946 err_update_projects = False
947 err_checkout = False
948
Dave Borowitz67700e92012-10-23 15:00:54 -0700949 self._fetch_times = _FetchTimes(self.manifest)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700950 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700951 to_fetch = []
952 now = time.time()
Dave Borowitz67700e92012-10-23 15:00:54 -0700953 if _ONE_DAY_S <= (now - rp.LastFetch):
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700954 to_fetch.append(rp)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900955 to_fetch.extend(all_projects)
Dave Borowitz67700e92012-10-23 15:00:54 -0700956 to_fetch.sort(key=self._fetch_times.Get, reverse=True)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700957
Mike Frysinger5a033082019-09-23 19:21:20 -0400958 fetched = self._Fetch(to_fetch, opt, err_event)
959
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500960 _PostRepoFetch(rp, opt.repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700961 if opt.network_only:
962 # bail out now; the rest touches the working tree
Mike Frysinger5a033082019-09-23 19:21:20 -0400963 if err_event.isSet():
964 print('\nerror: Exited sync due to fetch errors.\n', file=sys.stderr)
965 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700966 return
967
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800968 # Iteratively fetch missing and/or nested unregistered submodules
969 previously_missing_set = set()
970 while True:
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100971 self._ReloadManifest(manifest_name)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800972 all_projects = self.GetProjects(args,
973 missing_ok=True,
974 submodules_ok=opt.fetch_submodules)
975 missing = []
976 for project in all_projects:
977 if project.gitdir not in fetched:
978 missing.append(project)
979 if not missing:
980 break
981 # Stop us from non-stopped fetching actually-missing repos: If set of
982 # missing repos has not been changed from last fetch, we break.
983 missing_set = set(p.name for p in missing)
984 if previously_missing_set == missing_set:
985 break
986 previously_missing_set = missing_set
Mike Frysinger5a033082019-09-23 19:21:20 -0400987 fetched.update(self._Fetch(missing, opt, err_event))
988
989 # If we saw an error, exit with code 1 so that other scripts can check.
990 if err_event.isSet():
991 err_network_sync = True
992 if opt.fail_fast:
993 print('\nerror: Exited sync due to fetch errors.\n'
994 'Local checkouts *not* updated. Resolve network issues & '
995 'retry.\n'
996 '`repo sync -l` will update some local checkouts.',
997 file=sys.stderr)
998 sys.exit(1)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800999
Julien Campergue335f5ef2013-10-16 11:02:35 +02001000 if self.manifest.IsMirror or self.manifest.IsArchive:
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -07001001 # bail out now, we have no working tree
1002 return
1003
Oleksii Okolielovd3c0f592018-12-17 19:23:44 -05001004 if self.UpdateProjectList(opt):
Mike Frysinger5a033082019-09-23 19:21:20 -04001005 err_event.set()
1006 err_update_projects = True
1007 if opt.fail_fast:
1008 print('\nerror: Local checkouts *not* updated.', file=sys.stderr)
1009 sys.exit(1)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -07001010
Mike Frysinger5a033082019-09-23 19:21:20 -04001011 err_results = []
1012 self._Checkout(all_projects, opt, err_event, err_results)
1013 if err_event.isSet():
1014 err_checkout = True
1015 # NB: We don't exit here because this is the last step.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001016
Doug Anderson2b8db3c2010-11-01 15:08:06 -07001017 # If there's a notice that's supposed to print at the end of the sync, print
1018 # it now...
1019 if self.manifest.notice:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001020 print(self.manifest.notice)
Doug Anderson2b8db3c2010-11-01 15:08:06 -07001021
Mike Frysinger5a033082019-09-23 19:21:20 -04001022 # If we saw an error, exit with code 1 so that other scripts can check.
1023 if err_event.isSet():
1024 print('\nerror: Unable to fully sync the tree.', file=sys.stderr)
1025 if err_network_sync:
1026 print('error: Downloading network changes failed.', file=sys.stderr)
1027 if err_update_projects:
1028 print('error: Updating local project lists failed.', file=sys.stderr)
1029 if err_checkout:
1030 print('error: Checking out local projects failed.', file=sys.stderr)
1031 if err_results:
1032 print('Failing repos:\n%s' % '\n'.join(err_results), file=sys.stderr)
1033 print('Try re-running with "-j1 --fail-fast" to exit at the first error.',
1034 file=sys.stderr)
1035 sys.exit(1)
1036
Mike Frysingere19d9e12020-02-12 11:23:32 -05001037 if not opt.quiet:
1038 print('repo sync has finished successfully.')
1039
David Pursehouse819827a2020-02-12 15:20:19 +09001040
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -07001041def _PostRepoUpgrade(manifest, quiet=False):
Conley Owens094cdbe2014-01-30 15:09:59 -08001042 wrapper = Wrapper()
Conley Owensc9129d92012-10-01 16:12:28 -07001043 if wrapper.NeedSetupGnuPG():
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -07001044 wrapper.SetupGnuPG(quiet)
Conley Owensf2fe2d92014-01-29 13:53:43 -08001045 for project in manifest.projects:
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001046 if project.Exists:
1047 project.PostRepoUpgrade()
1048
David Pursehouse819827a2020-02-12 15:20:19 +09001049
Mike Frysingerc58ec4d2020-02-17 14:36:08 -05001050def _PostRepoFetch(rp, repo_verify=True, verbose=False):
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001051 if rp.HasChanges:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001052 print('info: A new version of repo is available', file=sys.stderr)
1053 print(file=sys.stderr)
Mike Frysingerc58ec4d2020-02-17 14:36:08 -05001054 if not repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -07001055 syncbuf = SyncBuffer(rp.config)
1056 rp.Sync_LocalHalf(syncbuf)
1057 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001058 sys.exit(1)
Sarah Owenscecd1d82012-11-01 22:59:27 -07001059 print('info: Restarting repo with latest version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001060 raise RepoChangedException(['--repo-upgraded'])
1061 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001062 print('warning: Skipped upgrade to unverified version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001063 else:
1064 if verbose:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001065 print('repo version %s is current' % rp.work_git.describe(HEAD),
1066 file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -07001067
David Pursehouse819827a2020-02-12 15:20:19 +09001068
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001069def _VerifyTag(project):
1070 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
1071 if not os.path.exists(gpg_dir):
Sarah Owenscecd1d82012-11-01 22:59:27 -07001072 print('warning: GnuPG was not available during last "repo init"\n'
1073 'warning: Cannot automatically authenticate repo."""',
1074 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001075 return True
1076
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001077 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -07001078 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001079 except GitError:
1080 cur = None
1081
1082 if not cur \
1083 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -07001084 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001085 if rev.startswith(R_HEADS):
1086 rev = rev[len(R_HEADS):]
1087
Sarah Owenscecd1d82012-11-01 22:59:27 -07001088 print(file=sys.stderr)
1089 print("warning: project '%s' branch '%s' is not signed"
1090 % (project.name, rev), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001091 return False
1092
Shawn O. Pearcef18cb762010-12-07 11:41:05 -08001093 env = os.environ.copy()
Mike Frysinger56ce3462019-12-04 19:30:48 -05001094 env['GIT_DIR'] = project.gitdir
1095 env['GNUPGHOME'] = gpg_dir
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001096
1097 cmd = [GIT, 'tag', '-v', cur]
1098 proc = subprocess.Popen(cmd,
David Pursehousee5913ae2020-02-12 13:56:59 +09001099 stdout=subprocess.PIPE,
1100 stderr=subprocess.PIPE,
1101 env=env)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001102 out = proc.stdout.read()
1103 proc.stdout.close()
1104
1105 err = proc.stderr.read()
1106 proc.stderr.close()
1107
1108 if proc.wait() != 0:
Sarah Owenscecd1d82012-11-01 22:59:27 -07001109 print(file=sys.stderr)
1110 print(out, file=sys.stderr)
1111 print(err, file=sys.stderr)
1112 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001113 return False
1114 return True
Dave Borowitz67700e92012-10-23 15:00:54 -07001115
David Rileye0684ad2017-04-05 00:02:59 -07001116
Dave Borowitz67700e92012-10-23 15:00:54 -07001117class _FetchTimes(object):
Dave Borowitzd9478582012-10-23 16:35:39 -07001118 _ALPHA = 0.5
1119
Dave Borowitz67700e92012-10-23 15:00:54 -07001120 def __init__(self, manifest):
Anthony King85b24ac2014-05-06 15:57:48 +01001121 self._path = os.path.join(manifest.repodir, '.repo_fetchtimes.json')
Dave Borowitz67700e92012-10-23 15:00:54 -07001122 self._times = None
Dave Borowitzd9478582012-10-23 16:35:39 -07001123 self._seen = set()
Dave Borowitz67700e92012-10-23 15:00:54 -07001124
1125 def Get(self, project):
1126 self._Load()
1127 return self._times.get(project.name, _ONE_DAY_S)
1128
1129 def Set(self, project, t):
Dave Borowitzd9478582012-10-23 16:35:39 -07001130 self._Load()
1131 name = project.name
1132 old = self._times.get(name, t)
1133 self._seen.add(name)
1134 a = self._ALPHA
David Pursehouse54a4e602020-02-12 14:31:05 +09001135 self._times[name] = (a * t) + ((1 - a) * old)
Dave Borowitz67700e92012-10-23 15:00:54 -07001136
1137 def _Load(self):
1138 if self._times is None:
1139 try:
Mike Frysinger3164d402019-11-11 05:40:22 -05001140 with open(self._path) as f:
Anthony King85b24ac2014-05-06 15:57:48 +01001141 self._times = json.load(f)
Anthony King85b24ac2014-05-06 15:57:48 +01001142 except (IOError, ValueError):
1143 try:
Renaud Paquay010fed72016-11-11 14:25:29 -08001144 platform_utils.remove(self._path)
Anthony King85b24ac2014-05-06 15:57:48 +01001145 except OSError:
1146 pass
1147 self._times = {}
Dave Borowitz67700e92012-10-23 15:00:54 -07001148
1149 def Save(self):
1150 if self._times is None:
1151 return
Dave Borowitzd9478582012-10-23 16:35:39 -07001152
1153 to_delete = []
1154 for name in self._times:
1155 if name not in self._seen:
1156 to_delete.append(name)
1157 for name in to_delete:
1158 del self._times[name]
1159
Dave Borowitz67700e92012-10-23 15:00:54 -07001160 try:
Mike Frysinger3164d402019-11-11 05:40:22 -05001161 with open(self._path, 'w') as f:
Anthony King85b24ac2014-05-06 15:57:48 +01001162 json.dump(self._times, f, indent=2)
Anthony King85b24ac2014-05-06 15:57:48 +01001163 except (IOError, TypeError):
1164 try:
Renaud Paquay010fed72016-11-11 14:25:29 -08001165 platform_utils.remove(self._path)
Anthony King85b24ac2014-05-06 15:57:48 +01001166 except OSError:
1167 pass
Dan Willemsen0745bb22015-08-17 13:41:45 -07001168
1169# This is a replacement for xmlrpc.client.Transport using urllib2
1170# and supporting persistent-http[s]. It cannot change hosts from
1171# request to request like the normal transport, the real url
1172# is passed during initialization.
David Pursehouse819827a2020-02-12 15:20:19 +09001173
1174
Dan Willemsen0745bb22015-08-17 13:41:45 -07001175class PersistentTransport(xmlrpc.client.Transport):
1176 def __init__(self, orig_host):
1177 self.orig_host = orig_host
1178
1179 def request(self, host, handler, request_body, verbose=False):
1180 with GetUrlCookieFile(self.orig_host, not verbose) as (cookiefile, proxy):
1181 # Python doesn't understand cookies with the #HttpOnly_ prefix
1182 # Since we're only using them for HTTP, copy the file temporarily,
1183 # stripping those prefixes away.
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001184 if cookiefile:
Collin Fijalkoviche1191b32020-02-18 10:57:32 -08001185 tmpcookiefile = tempfile.NamedTemporaryFile(mode='w')
David Pursehouse4c5f74e2015-10-02 11:10:10 +09001186 tmpcookiefile.write("# HTTP Cookie File")
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001187 try:
1188 with open(cookiefile) as f:
1189 for line in f:
1190 if line.startswith("#HttpOnly_"):
1191 line = line[len("#HttpOnly_"):]
1192 tmpcookiefile.write(line)
1193 tmpcookiefile.flush()
Dan Willemsen0745bb22015-08-17 13:41:45 -07001194
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001195 cookiejar = cookielib.MozillaCookieJar(tmpcookiefile.name)
David Pursehouseb1ad2192015-09-30 10:35:43 +09001196 try:
1197 cookiejar.load()
1198 except cookielib.LoadError:
1199 cookiejar = cookielib.CookieJar()
Dan Willemsen3010e5b2015-08-20 10:09:20 -07001200 finally:
1201 tmpcookiefile.close()
1202 else:
1203 cookiejar = cookielib.CookieJar()
Dan Willemsen0745bb22015-08-17 13:41:45 -07001204
1205 proxyhandler = urllib.request.ProxyHandler
1206 if proxy:
1207 proxyhandler = urllib.request.ProxyHandler({
1208 "http": proxy,
David Pursehouse54a4e602020-02-12 14:31:05 +09001209 "https": proxy})
Dan Willemsen0745bb22015-08-17 13:41:45 -07001210
1211 opener = urllib.request.build_opener(
1212 urllib.request.HTTPCookieProcessor(cookiejar),
1213 proxyhandler)
1214
1215 url = urllib.parse.urljoin(self.orig_host, handler)
1216 parse_results = urllib.parse.urlparse(url)
1217
1218 scheme = parse_results.scheme
1219 if scheme == 'persistent-http':
1220 scheme = 'http'
1221 if scheme == 'persistent-https':
1222 # If we're proxying through persistent-https, use http. The
1223 # proxy itself will do the https.
1224 if proxy:
1225 scheme = 'http'
1226 else:
1227 scheme = 'https'
1228
1229 # Parse out any authentication information using the base class
1230 host, extra_headers, _ = self.get_host_info(parse_results.netloc)
1231
1232 url = urllib.parse.urlunparse((
1233 scheme,
1234 host,
1235 parse_results.path,
1236 parse_results.params,
1237 parse_results.query,
1238 parse_results.fragment))
1239
1240 request = urllib.request.Request(url, request_body)
1241 if extra_headers is not None:
1242 for (name, header) in extra_headers:
1243 request.add_header(name, header)
1244 request.add_header('Content-Type', 'text/xml')
1245 try:
1246 response = opener.open(request)
1247 except urllib.error.HTTPError as e:
1248 if e.code == 501:
1249 # We may have been redirected through a login process
1250 # but our POST turned into a GET. Retry.
1251 response = opener.open(request)
1252 else:
1253 raise
1254
1255 p, u = xmlrpc.client.getparser()
1256 while 1:
1257 data = response.read(1024)
1258 if not data:
1259 break
1260 p.feed(data)
1261 p.close()
1262 return u.close()
1263
1264 def close(self):
1265 pass