blob: ed8622c1f94d245f7f593f0f96864459ae7889ad [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001#
2# Copyright (C) 2008 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
Sarah Owenscecd1d82012-11-01 22:59:27 -070016from __future__ import print_function
Anthony King85b24ac2014-05-06 15:57:48 +010017import json
David Pursehouse86d973d2012-08-24 10:21:02 +090018import netrc
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -070019from optparse import SUPPRESS_HELP
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070020import os
21import re
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070022import shutil
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070023import socket
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070024import subprocess
25import sys
Dan Willemsen0745bb22015-08-17 13:41:45 -070026import tempfile
Shawn O. Pearcef6906872009-04-18 10:49:00 -070027import time
David Pursehouse59bbb582013-05-17 10:49:33 +090028
29from pyversion import is_python3
30if is_python3():
Dan Willemsen0745bb22015-08-17 13:41:45 -070031 import http.cookiejar as cookielib
32 import urllib.error
Chirayu Desai217ea7d2013-03-01 19:14:38 +053033 import urllib.parse
Dan Willemsen0745bb22015-08-17 13:41:45 -070034 import urllib.request
David Pursehouse59bbb582013-05-17 10:49:33 +090035 import xmlrpc.client
36else:
Dan Willemsen0745bb22015-08-17 13:41:45 -070037 import cookielib
Chirayu Desai217ea7d2013-03-01 19:14:38 +053038 import imp
Dan Willemsen0745bb22015-08-17 13:41:45 -070039 import urllib2
Chirayu Desai217ea7d2013-03-01 19:14:38 +053040 import urlparse
David Pursehouse59bbb582013-05-17 10:49:33 +090041 import xmlrpclib
Chirayu Desai217ea7d2013-03-01 19:14:38 +053042 urllib = imp.new_module('urllib')
Dan Willemsen0745bb22015-08-17 13:41:45 -070043 urllib.error = urllib2
Chirayu Desaidb2ad9d2013-06-11 13:42:25 +053044 urllib.parse = urlparse
Dan Willemsen0745bb22015-08-17 13:41:45 -070045 urllib.request = urllib2
Chirayu Desai217ea7d2013-03-01 19:14:38 +053046 xmlrpc = imp.new_module('xmlrpc')
47 xmlrpc.client = xmlrpclib
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070048
Roy Lee18afd7f2010-05-09 04:32:08 +080049try:
50 import threading as _threading
51except ImportError:
52 import dummy_threading as _threading
53
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -070054try:
55 import resource
56 def _rlimit_nofile():
57 return resource.getrlimit(resource.RLIMIT_NOFILE)
58except ImportError:
59 def _rlimit_nofile():
60 return (256, 256)
61
Dave Borowitz18857212012-10-23 17:02:59 -070062try:
63 import multiprocessing
64except ImportError:
65 multiprocessing = None
66
Dave Borowitze2152672012-10-31 12:24:38 -070067from git_command import GIT, git_require
Dan Willemsen0745bb22015-08-17 13:41:45 -070068from git_config import GetSchemeFromUrl, GetUrlCookieFile
David Pursehoused94aaef2012-09-07 09:52:04 +090069from git_refs import R_HEADS, HEAD
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070070from project import Project
71from project import RemoteSpec
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080072from command import Command, MirrorSafeCommand
Torne (Richard Coles)7bdbde72012-12-05 10:58:06 +000073from error import RepoChangedException, GitError, ManifestParseError
Shawn O. Pearce350cde42009-04-16 11:21:18 -070074from project import SyncBuffer
Shawn O. Pearce68194f42009-04-10 16:48:52 -070075from progress import Progress
Conley Owens094cdbe2014-01-30 15:09:59 -080076from wrapper import Wrapper
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070077
Dave Borowitz67700e92012-10-23 15:00:54 -070078_ONE_DAY_S = 24 * 60 * 60
79
Doug Andersonfc06ced2011-03-16 15:49:18 -070080class _FetchError(Exception):
81 """Internal error thrown in _FetchHelper() when we don't want stack trace."""
82 pass
83
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080084class Sync(Command, MirrorSafeCommand):
Roy Lee18afd7f2010-05-09 04:32:08 +080085 jobs = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070086 common = True
87 helpSummary = "Update working tree to the latest revision"
88 helpUsage = """
89%prog [<project>...]
90"""
91 helpDescription = """
92The '%prog' command synchronizes local project directories
93with the remote repositories specified in the manifest. If a local
94project does not yet exist, it will clone a new local directory from
95the remote repository and set up tracking branches as specified in
96the manifest. If the local project already exists, '%prog'
97will update the remote branches and rebase any new local changes
98on top of the new remote changes.
99
100'%prog' will synchronize all projects listed at the command
101line. Projects can be specified either by name, or by a relative
102or absolute path to the project's local directory. If no projects
103are specified, '%prog' will synchronize all projects listed in
104the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700105
106The -d/--detach option can be used to switch specified projects
107back to the manifest revision. This option is especially helpful
108if the project is currently on a topic branch, but the manifest
109revision is temporarily needed.
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700110
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700111The -s/--smart-sync option can be used to sync to a known good
112build as specified by the manifest-server element in the current
Victor Boivie08c880d2011-04-19 10:32:52 +0200113manifest. The -t/--smart-tag option is similar and allows you to
114specify a custom tag/label.
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700115
David Pursehousecf76b1b2012-09-14 10:31:42 +0900116The -u/--manifest-server-username and -p/--manifest-server-password
117options can be used to specify a username and password to authenticate
118with the manifest server when using the -s or -t option.
119
120If -u and -p are not specified when using the -s or -t option, '%prog'
121will attempt to read authentication credentials for the manifest server
122from the user's .netrc file.
123
124'%prog' will not use authentication credentials from -u/-p or .netrc
125if the manifest server specified in the manifest file already includes
126credentials.
127
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500128The -f/--force-broken option can be used to proceed with syncing
129other projects if a project sync fails.
130
Kevin Degiabaa7f32014-11-12 11:27:45 -0700131The --force-sync option can be used to overwrite existing git
132directories if they have previously been linked to a different
133object direcotry. WARNING: This may cause data to be lost since
134refs may be removed when overwriting.
135
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700136The --no-clone-bundle option disables any attempt to use
137$URL/clone.bundle to bootstrap a new Git repository from a
138resumeable bundle file on a content delivery network. This
139may be necessary if there are problems with the local Python
140HTTP client or proxy configuration, but the Git binary works.
141
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800142The --fetch-submodules option enables fetching Git submodules
143of a project from server.
144
David Pursehousef2fad612015-01-29 14:36:28 +0900145The -c/--current-branch option can be used to only fetch objects that
146are on the branch specified by a project's revision.
147
David Pursehouseb1553542014-09-04 21:28:09 +0900148The --optimized-fetch option can be used to only fetch projects that
149are fixed to a sha1 revision if the sha1 revision does not already
150exist locally.
151
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700152SSH Connections
153---------------
154
155If at least one project remote URL uses an SSH connection (ssh://,
156git+ssh://, or user@host:path syntax) repo will automatically
157enable the SSH ControlMaster option when connecting to that host.
158This feature permits other projects in the same '%prog' session to
159reuse the same SSH tunnel, saving connection setup overheads.
160
161To disable this behavior on UNIX platforms, set the GIT_SSH
162environment variable to 'ssh'. For example:
163
164 export GIT_SSH=ssh
165 %prog
166
167Compatibility
168~~~~~~~~~~~~~
169
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',
189 dest='force_broken', action='store_true',
190 help="continue sync even if a project fails to sync")
Kevin Degiabaa7f32014-11-12 11:27:45 -0700191 p.add_option('--force-sync',
192 dest='force_sync', action='store_true',
193 help="overwrite an existing git directory if it needs to "
194 "point to a different object directory. WARNING: this "
195 "may cause loss of data")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900196 p.add_option('-l', '--local-only',
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700197 dest='local_only', action='store_true',
198 help="only update working tree, don't fetch")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900199 p.add_option('-n', '--network-only',
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700200 dest='network_only', action='store_true',
201 help="fetch only, don't update working tree")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900202 p.add_option('-d', '--detach',
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700203 dest='detach_head', action='store_true',
204 help='detach projects back to manifest revision')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900205 p.add_option('-c', '--current-branch',
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700206 dest='current_branch_only', action='store_true',
207 help='fetch only current branch from server')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900208 p.add_option('-q', '--quiet',
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700209 dest='quiet', action='store_true',
210 help='be more quiet')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900211 p.add_option('-j', '--jobs',
Roy Lee18afd7f2010-05-09 04:32:08 +0800212 dest='jobs', action='store', type='int',
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700213 help="projects to fetch simultaneously (default %d)" % self.jobs)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500214 p.add_option('-m', '--manifest-name',
215 dest='manifest_name',
216 help='temporary manifest to use for this sync', metavar='NAME.xml')
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700217 p.add_option('--no-clone-bundle',
218 dest='no_clone_bundle', action='store_true',
219 help='disable use of /clone.bundle on HTTP/HTTPS')
Conley Owens8d070cf2012-11-06 13:14:31 -0800220 p.add_option('-u', '--manifest-server-username', action='store',
221 dest='manifest_server_username',
222 help='username to authenticate with the manifest server')
223 p.add_option('-p', '--manifest-server-password', action='store',
224 dest='manifest_server_password',
225 help='password to authenticate with the manifest server')
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800226 p.add_option('--fetch-submodules',
227 dest='fetch_submodules', action='store_true',
228 help='fetch submodules from server')
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700229 p.add_option('--no-tags',
230 dest='no_tags', action='store_true',
231 help="don't fetch tags")
David Pursehouseb1553542014-09-04 21:28:09 +0900232 p.add_option('--optimized-fetch',
233 dest='optimized_fetch', action='store_true',
234 help='only fetch projects fixed to sha1 if revision does not exist locally')
Nico Sallembien6623b212010-05-11 12:57:01 -0700235 if show_smart:
236 p.add_option('-s', '--smart-sync',
237 dest='smart_sync', action='store_true',
238 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200239 p.add_option('-t', '--smart-tag',
240 dest='smart_tag', action='store',
241 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700242
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700243 g = p.add_option_group('repo Version options')
244 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700245 dest='no_repo_verify', action='store_true',
246 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700247 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800248 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700249 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700250
David James89ece422014-01-09 18:51:58 -0800251 def _FetchProjectList(self, opt, projects, *args, **kwargs):
David Pursehousec1b86a22012-11-14 11:36:51 +0900252 """Main function of the fetch threads when jobs are > 1.
Roy Lee18afd7f2010-05-09 04:32:08 +0800253
David James8d201162013-10-11 17:03:19 -0700254 Delegates most of the work to _FetchHelper.
255
256 Args:
257 opt: Program options returned from optparse. See _Options().
258 projects: Projects to fetch.
David James89ece422014-01-09 18:51:58 -0800259 *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the
David James8d201162013-10-11 17:03:19 -0700260 _FetchHelper docstring for details.
261 """
262 for project in projects:
David James89ece422014-01-09 18:51:58 -0800263 success = self._FetchHelper(opt, project, *args, **kwargs)
David James8d201162013-10-11 17:03:19 -0700264 if not success and not opt.force_broken:
265 break
266
267 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
268 """Fetch git objects for a single project.
269
David Pursehousec1b86a22012-11-14 11:36:51 +0900270 Args:
271 opt: Program options returned from optparse. See _Options().
272 project: Project object for the project to fetch.
273 lock: Lock for accessing objects that are shared amongst multiple
274 _FetchHelper() threads.
275 fetched: set object that we will add project.gitdir to when we're done
276 (with our lock held).
277 pm: Instance of a Project object. We will call pm.update() (with our
278 lock held).
279 sem: We'll release() this semaphore when we exit so that another thread
280 can be started up.
281 err_event: We'll set this event in the case of an error (after printing
282 out info about the error).
David James8d201162013-10-11 17:03:19 -0700283
284 Returns:
285 Whether the fetch was successful.
David Pursehousec1b86a22012-11-14 11:36:51 +0900286 """
287 # We'll set to true once we've locked the lock.
288 did_lock = False
Doug Andersonfc06ced2011-03-16 15:49:18 -0700289
Chirayu Desaifef4ae72013-04-12 14:54:32 +0530290 if not opt.quiet:
291 print('Fetching project %s' % project.name)
292
David Pursehousec1b86a22012-11-14 11:36:51 +0900293 # Encapsulate everything in a try/except/finally so that:
294 # - We always set err_event in the case of an exception.
295 # - We always make sure we call sem.release().
296 # - We always make sure we unlock the lock if we locked it.
297 try:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700298 try:
David Pursehousec1b86a22012-11-14 11:36:51 +0900299 start = time.time()
300 success = project.Sync_NetworkHalf(
301 quiet=opt.quiet,
302 current_branch_only=opt.current_branch_only,
Kevin Degiabaa7f32014-11-12 11:27:45 -0700303 force_sync=opt.force_sync,
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700304 clone_bundle=not opt.no_clone_bundle,
David Pursehouseb1553542014-09-04 21:28:09 +0900305 no_tags=opt.no_tags, archive=self.manifest.IsArchive,
306 optimized_fetch=opt.optimized_fetch)
David Pursehousec1b86a22012-11-14 11:36:51 +0900307 self._fetch_times.Set(project, time.time() - start)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700308
David Pursehousec1b86a22012-11-14 11:36:51 +0900309 # Lock around all the rest of the code, since printing, updating a set
310 # and Progress.update() are not thread safe.
311 lock.acquire()
312 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700313
David Pursehousec1b86a22012-11-14 11:36:51 +0900314 if not success:
315 print('error: Cannot fetch %s' % project.name, file=sys.stderr)
316 if opt.force_broken:
317 print('warn: --force-broken, continuing to sync',
318 file=sys.stderr)
319 else:
320 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700321
David Pursehousec1b86a22012-11-14 11:36:51 +0900322 fetched.add(project.gitdir)
323 pm.update()
324 except _FetchError:
325 err_event.set()
Dan Sandlerc5cd4332015-07-31 09:37:53 -0400326 except Exception as e:
327 print('error: Cannot fetch %s (%s: %s)' \
328 % (project.name, type(e).__name__, str(e)), file=sys.stderr)
David Pursehousec1b86a22012-11-14 11:36:51 +0900329 err_event.set()
330 raise
331 finally:
332 if did_lock:
333 lock.release()
334 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800335
David James8d201162013-10-11 17:03:19 -0700336 return success
337
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700338 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700339 fetched = set()
David James89ece422014-01-09 18:51:58 -0800340 lock = _threading.Lock()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700341 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800342
David James89ece422014-01-09 18:51:58 -0800343 objdir_project_map = dict()
344 for project in projects:
345 objdir_project_map.setdefault(project.objdir, []).append(project)
David James8d201162013-10-11 17:03:19 -0700346
David James89ece422014-01-09 18:51:58 -0800347 threads = set()
348 sem = _threading.Semaphore(self.jobs)
349 err_event = _threading.Event()
350 for project_list in objdir_project_map.values():
351 # Check for any errors before running any more tasks.
352 # ...we'll let existing threads finish, though.
353 if err_event.isSet() and not opt.force_broken:
354 break
Doug Andersonfc06ced2011-03-16 15:49:18 -0700355
David James89ece422014-01-09 18:51:58 -0800356 sem.acquire()
357 kwargs = dict(opt=opt,
358 projects=project_list,
359 lock=lock,
360 fetched=fetched,
361 pm=pm,
362 sem=sem,
363 err_event=err_event)
364 if self.jobs > 1:
David James8d201162013-10-11 17:03:19 -0700365 t = _threading.Thread(target = self._FetchProjectList,
David James89ece422014-01-09 18:51:58 -0800366 kwargs = kwargs)
David 'Digit' Turnere2126652012-09-05 10:35:06 +0200367 # Ensure that Ctrl-C will not freeze the repo process.
368 t.daemon = True
Roy Lee18afd7f2010-05-09 04:32:08 +0800369 threads.add(t)
370 t.start()
David James89ece422014-01-09 18:51:58 -0800371 else:
372 self._FetchProjectList(**kwargs)
Roy Lee18afd7f2010-05-09 04:32:08 +0800373
David James89ece422014-01-09 18:51:58 -0800374 for t in threads:
375 t.join()
Roy Lee18afd7f2010-05-09 04:32:08 +0800376
David James89ece422014-01-09 18:51:58 -0800377 # If we saw an error, exit with code 1 so that other scripts can check.
378 if err_event.isSet():
379 print('\nerror: Exited sync due to fetch errors', file=sys.stderr)
380 sys.exit(1)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700381
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700382 pm.end()
Dave Borowitz67700e92012-10-23 15:00:54 -0700383 self._fetch_times.Save()
Dave Borowitz18857212012-10-23 17:02:59 -0700384
Julien Campergue335f5ef2013-10-16 11:02:35 +0200385 if not self.manifest.IsArchive:
386 self._GCProjects(projects)
387
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700388 return fetched
389
Dave Borowitz18857212012-10-23 17:02:59 -0700390 def _GCProjects(self, projects):
David James8d201162013-10-11 17:03:19 -0700391 gitdirs = {}
392 for project in projects:
393 gitdirs[project.gitdir] = project.bare_git
394
Dave Borowitze2152672012-10-31 12:24:38 -0700395 has_dash_c = git_require((1, 7, 2))
396 if multiprocessing and has_dash_c:
Dave Borowitz18857212012-10-23 17:02:59 -0700397 cpu_count = multiprocessing.cpu_count()
398 else:
399 cpu_count = 1
400 jobs = min(self.jobs, cpu_count)
401
402 if jobs < 2:
David James8d201162013-10-11 17:03:19 -0700403 for bare_git in gitdirs.values():
404 bare_git.gc('--auto')
Dave Borowitz18857212012-10-23 17:02:59 -0700405 return
406
407 config = {'pack.threads': cpu_count / jobs if cpu_count > jobs else 1}
408
409 threads = set()
410 sem = _threading.Semaphore(jobs)
411 err_event = _threading.Event()
412
David James8d201162013-10-11 17:03:19 -0700413 def GC(bare_git):
Dave Borowitz18857212012-10-23 17:02:59 -0700414 try:
415 try:
David James8d201162013-10-11 17:03:19 -0700416 bare_git.gc('--auto', config=config)
Dave Borowitz18857212012-10-23 17:02:59 -0700417 except GitError:
418 err_event.set()
419 except:
420 err_event.set()
421 raise
422 finally:
423 sem.release()
424
David James8d201162013-10-11 17:03:19 -0700425 for bare_git in gitdirs.values():
Dave Borowitz18857212012-10-23 17:02:59 -0700426 if err_event.isSet():
427 break
428 sem.acquire()
David James8d201162013-10-11 17:03:19 -0700429 t = _threading.Thread(target=GC, args=(bare_git,))
Dave Borowitz18857212012-10-23 17:02:59 -0700430 t.daemon = True
431 threads.add(t)
432 t.start()
433
434 for t in threads:
435 t.join()
436
437 if err_event.isSet():
Sarah Owenscecd1d82012-11-01 22:59:27 -0700438 print('\nerror: Exited sync due to gc errors', file=sys.stderr)
Dave Borowitz18857212012-10-23 17:02:59 -0700439 sys.exit(1)
440
Tim Kilbourn07669002013-03-08 15:02:49 -0800441 def _ReloadManifest(self, manifest_name=None):
442 if manifest_name:
443 # Override calls _Unload already
444 self.manifest.Override(manifest_name)
445 else:
446 self.manifest._Unload()
447
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700448 def UpdateProjectList(self):
449 new_project_paths = []
Colin Cross5acde752012-03-28 20:15:45 -0700450 for project in self.GetProjects(None, missing_ok=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700451 if project.relpath:
452 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700453 file_name = 'project.list'
454 file_path = os.path.join(self.manifest.repodir, file_name)
455 old_project_paths = []
456
457 if os.path.exists(file_path):
458 fd = open(file_path, 'r')
459 try:
460 old_project_paths = fd.read().split('\n')
461 finally:
462 fd.close()
463 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700464 if not path:
465 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700466 if path not in new_project_paths:
David Pursehouse8a68ff92012-09-24 12:15:13 +0900467 # If the path has already been deleted, we don't need to do it
Anthonyf3fdf822009-09-26 13:38:52 -0400468 if os.path.exists(self.manifest.topdir + '/' + path):
David James8d201162013-10-11 17:03:19 -0700469 gitdir = os.path.join(self.manifest.topdir, path, '.git')
David Pursehousec1b86a22012-11-14 11:36:51 +0900470 project = Project(
471 manifest = self.manifest,
472 name = path,
473 remote = RemoteSpec('origin'),
David James8d201162013-10-11 17:03:19 -0700474 gitdir = gitdir,
475 objdir = gitdir,
David Pursehousec1b86a22012-11-14 11:36:51 +0900476 worktree = os.path.join(self.manifest.topdir, path),
477 relpath = path,
478 revisionExpr = 'HEAD',
479 revisionId = None,
480 groups = None)
Anthonyf3fdf822009-09-26 13:38:52 -0400481
David Pursehousec1b86a22012-11-14 11:36:51 +0900482 if project.IsDirty():
David Pursehouse2f9e7e42013-03-05 17:26:46 +0900483 print('error: Cannot remove project "%s": uncommitted changes '
David Pursehousec1b86a22012-11-14 11:36:51 +0900484 'are present' % project.relpath, file=sys.stderr)
485 print(' commit changes, then run sync again',
486 file=sys.stderr)
487 return -1
488 else:
489 print('Deleting obsolete path %s' % project.worktree,
490 file=sys.stderr)
491 shutil.rmtree(project.worktree)
492 # Try deleting parent subdirs if they are empty
493 project_dir = os.path.dirname(project.worktree)
494 while project_dir != self.manifest.topdir:
495 try:
496 os.rmdir(project_dir)
497 except OSError:
498 break
499 project_dir = os.path.dirname(project_dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700500
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700501 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700502 fd = open(file_path, 'w')
503 try:
504 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700505 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700506 finally:
507 fd.close()
508 return 0
509
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700510 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800511 if opt.jobs:
512 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700513 if self.jobs > 1:
514 soft_limit, _ = _rlimit_nofile()
515 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
516
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700517 if opt.network_only and opt.detach_head:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700518 print('error: cannot combine -n and -d', file=sys.stderr)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700519 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700520 if opt.network_only and opt.local_only:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700521 print('error: cannot combine -n and -l', file=sys.stderr)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700522 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500523 if opt.manifest_name and opt.smart_sync:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700524 print('error: cannot combine -m and -s', file=sys.stderr)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500525 sys.exit(1)
526 if opt.manifest_name and opt.smart_tag:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700527 print('error: cannot combine -m and -t', file=sys.stderr)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500528 sys.exit(1)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900529 if opt.manifest_server_username or opt.manifest_server_password:
530 if not (opt.smart_sync or opt.smart_tag):
Sarah Owenscecd1d82012-11-01 22:59:27 -0700531 print('error: -u and -p may only be combined with -s or -t',
532 file=sys.stderr)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900533 sys.exit(1)
534 if None in [opt.manifest_server_username, opt.manifest_server_password]:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700535 print('error: both -u and -p must be given', file=sys.stderr)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900536 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500537
538 if opt.manifest_name:
539 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700540
Chirayu Desaia892b102013-06-11 14:18:46 +0530541 manifest_name = opt.manifest_name
David Pursehouse59b41742015-05-07 14:36:09 +0900542 smart_sync_manifest_name = "smart_sync_override.xml"
543 smart_sync_manifest_path = os.path.join(
544 self.manifest.manifestProject.worktree, smart_sync_manifest_name)
Chirayu Desaia892b102013-06-11 14:18:46 +0530545
Victor Boivie08c880d2011-04-19 10:32:52 +0200546 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700547 if not self.manifest.manifest_server:
David Pursehouse2f9e7e42013-03-05 17:26:46 +0900548 print('error: cannot smart sync: no manifest server defined in '
Sarah Owenscecd1d82012-11-01 22:59:27 -0700549 'manifest', file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700550 sys.exit(1)
David Pursehouse86d973d2012-08-24 10:21:02 +0900551
552 manifest_server = self.manifest.manifest_server
David Pursehousefb99c712013-09-25 11:09:34 +0900553 if not opt.quiet:
554 print('Using manifest server %s' % manifest_server)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900555
David Pursehouse86d973d2012-08-24 10:21:02 +0900556 if not '@' in manifest_server:
David Pursehousecf76b1b2012-09-14 10:31:42 +0900557 username = None
558 password = None
559 if opt.manifest_server_username and opt.manifest_server_password:
560 username = opt.manifest_server_username
561 password = opt.manifest_server_password
David Pursehouse86d973d2012-08-24 10:21:02 +0900562 else:
563 try:
David Pursehousecf76b1b2012-09-14 10:31:42 +0900564 info = netrc.netrc()
565 except IOError:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700566 print('.netrc file does not exist or could not be opened',
567 file=sys.stderr)
David Pursehouse86d973d2012-08-24 10:21:02 +0900568 else:
David Pursehousecf76b1b2012-09-14 10:31:42 +0900569 try:
Chirayu Desaidb2ad9d2013-06-11 13:42:25 +0530570 parse_result = urllib.parse.urlparse(manifest_server)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900571 if parse_result.hostname:
572 username, _account, password = \
573 info.authenticators(parse_result.hostname)
574 except TypeError:
575 # TypeError is raised when the given hostname is not present
576 # in the .netrc file.
Sarah Owenscecd1d82012-11-01 22:59:27 -0700577 print('No credentials found for %s in .netrc'
578 % parse_result.hostname, file=sys.stderr)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700579 except netrc.NetrcParseError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700580 print('Error parsing .netrc file: %s' % e, file=sys.stderr)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900581
582 if (username and password):
583 manifest_server = manifest_server.replace('://', '://%s:%s@' %
584 (username, password),
585 1)
David Pursehouse86d973d2012-08-24 10:21:02 +0900586
Dan Willemsen0745bb22015-08-17 13:41:45 -0700587 transport = PersistentTransport(manifest_server)
588 if manifest_server.startswith('persistent-'):
589 manifest_server = manifest_server[len('persistent-'):]
590
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700591 try:
Dan Willemsen0745bb22015-08-17 13:41:45 -0700592 server = xmlrpc.client.Server(manifest_server, transport=transport)
Victor Boivie08c880d2011-04-19 10:32:52 +0200593 if opt.smart_sync:
594 p = self.manifest.manifestProject
595 b = p.GetBranch(p.CurrentBranch)
596 branch = b.merge
597 if branch.startswith(R_HEADS):
598 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700599
Victor Boivie08c880d2011-04-19 10:32:52 +0200600 env = os.environ.copy()
Jeff Davidson5cf16602014-10-02 10:13:38 -0700601 if 'SYNC_TARGET' in env:
602 target = env['SYNC_TARGET']
603 [success, manifest_str] = server.GetApprovedManifest(branch, target)
604 elif 'TARGET_PRODUCT' in env and 'TARGET_BUILD_VARIANT' in env:
Victor Boivie08c880d2011-04-19 10:32:52 +0200605 target = '%s-%s' % (env['TARGET_PRODUCT'],
606 env['TARGET_BUILD_VARIANT'])
607 [success, manifest_str] = server.GetApprovedManifest(branch, target)
608 else:
609 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700610 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200611 assert(opt.smart_tag)
612 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700613
614 if success:
David Pursehouse59b41742015-05-07 14:36:09 +0900615 manifest_name = smart_sync_manifest_name
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700616 try:
David Pursehouse59b41742015-05-07 14:36:09 +0900617 f = open(smart_sync_manifest_path, 'w')
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700618 try:
619 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700620 finally:
621 f.close()
David Pursehouse727cc3e2015-05-07 14:16:49 +0900622 except IOError as e:
623 print('error: cannot write manifest to %s:\n%s'
David Pursehouse59b41742015-05-07 14:36:09 +0900624 % (smart_sync_manifest_path, e),
Sarah Owenscecd1d82012-11-01 22:59:27 -0700625 file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700626 sys.exit(1)
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100627 self._ReloadManifest(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700628 else:
David Pursehouse351fe2c2013-09-25 17:54:26 +0900629 print('error: manifest server RPC call failed: %s' %
630 manifest_str, file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700631 sys.exit(1)
Chirayu Desai217ea7d2013-03-01 19:14:38 +0530632 except (socket.error, IOError, xmlrpc.client.Fault) as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700633 print('error: cannot connect to manifest server %s:\n%s'
634 % (self.manifest.manifest_server, e), file=sys.stderr)
David Pursehousebd489c42012-08-23 10:21:26 +0900635 sys.exit(1)
Chirayu Desai217ea7d2013-03-01 19:14:38 +0530636 except xmlrpc.client.ProtocolError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700637 print('error: cannot connect to manifest server %s:\n%d %s'
638 % (self.manifest.manifest_server, e.errcode, e.errmsg),
639 file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700640 sys.exit(1)
David Pursehouse59b41742015-05-07 14:36:09 +0900641 else: # Not smart sync or smart tag mode
642 if os.path.isfile(smart_sync_manifest_path):
643 try:
644 os.remove(smart_sync_manifest_path)
645 except OSError as e:
646 print('error: failed to remove existing smart sync override manifest: %s' %
647 e, file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700648
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700649 rp = self.manifest.repoProject
650 rp.PreSync()
651
652 mp = self.manifest.manifestProject
653 mp.PreSync()
654
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800655 if opt.repo_upgraded:
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700656 _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800657
Nico Sallembien9bb18162009-12-07 15:38:01 -0800658 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700659 mp.Sync_NetworkHalf(quiet=opt.quiet,
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700660 current_branch_only=opt.current_branch_only,
David Pursehouseb1553542014-09-04 21:28:09 +0900661 no_tags=opt.no_tags,
662 optimized_fetch=opt.optimized_fetch)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800663
664 if mp.HasChanges:
665 syncbuf = SyncBuffer(mp.config)
666 mp.Sync_LocalHalf(syncbuf)
667 if not syncbuf.Finish():
668 sys.exit(1)
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100669 self._ReloadManifest(manifest_name)
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700670 if opt.jobs is None:
671 self.jobs = self.manifest.default.sync_j
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800672 all_projects = self.GetProjects(args,
673 missing_ok=True,
674 submodules_ok=opt.fetch_submodules)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700675
Dave Borowitz67700e92012-10-23 15:00:54 -0700676 self._fetch_times = _FetchTimes(self.manifest)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700677 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700678 to_fetch = []
679 now = time.time()
Dave Borowitz67700e92012-10-23 15:00:54 -0700680 if _ONE_DAY_S <= (now - rp.LastFetch):
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700681 to_fetch.append(rp)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900682 to_fetch.extend(all_projects)
Dave Borowitz67700e92012-10-23 15:00:54 -0700683 to_fetch.sort(key=self._fetch_times.Get, reverse=True)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700684
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800685 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700686 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700687 if opt.network_only:
688 # bail out now; the rest touches the working tree
689 return
690
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800691 # Iteratively fetch missing and/or nested unregistered submodules
692 previously_missing_set = set()
693 while True:
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100694 self._ReloadManifest(manifest_name)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800695 all_projects = self.GetProjects(args,
696 missing_ok=True,
697 submodules_ok=opt.fetch_submodules)
698 missing = []
699 for project in all_projects:
700 if project.gitdir not in fetched:
701 missing.append(project)
702 if not missing:
703 break
704 # Stop us from non-stopped fetching actually-missing repos: If set of
705 # missing repos has not been changed from last fetch, we break.
706 missing_set = set(p.name for p in missing)
707 if previously_missing_set == missing_set:
708 break
709 previously_missing_set = missing_set
710 fetched.update(self._Fetch(missing, opt))
711
Julien Campergue335f5ef2013-10-16 11:02:35 +0200712 if self.manifest.IsMirror or self.manifest.IsArchive:
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700713 # bail out now, we have no working tree
714 return
715
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700716 if self.UpdateProjectList():
717 sys.exit(1)
718
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700719 syncbuf = SyncBuffer(mp.config,
720 detach_head = opt.detach_head)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900721 pm = Progress('Syncing work tree', len(all_projects))
722 for project in all_projects:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700723 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800724 if project.worktree:
Kevin Degiabaa7f32014-11-12 11:27:45 -0700725 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700726 pm.end()
Sarah Owenscecd1d82012-11-01 22:59:27 -0700727 print(file=sys.stderr)
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700728 if not syncbuf.Finish():
729 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700730
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700731 # If there's a notice that's supposed to print at the end of the sync, print
732 # it now...
733 if self.manifest.notice:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700734 print(self.manifest.notice)
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700735
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700736def _PostRepoUpgrade(manifest, quiet=False):
Conley Owens094cdbe2014-01-30 15:09:59 -0800737 wrapper = Wrapper()
Conley Owensc9129d92012-10-01 16:12:28 -0700738 if wrapper.NeedSetupGnuPG():
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700739 wrapper.SetupGnuPG(quiet)
Conley Owensf2fe2d92014-01-29 13:53:43 -0800740 for project in manifest.projects:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700741 if project.Exists:
742 project.PostRepoUpgrade()
743
744def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
745 if rp.HasChanges:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700746 print('info: A new version of repo is available', file=sys.stderr)
747 print(file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700748 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700749 syncbuf = SyncBuffer(rp.config)
750 rp.Sync_LocalHalf(syncbuf)
751 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700752 sys.exit(1)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700753 print('info: Restarting repo with latest version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700754 raise RepoChangedException(['--repo-upgraded'])
755 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700756 print('warning: Skipped upgrade to unverified version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700757 else:
758 if verbose:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700759 print('repo version %s is current' % rp.work_git.describe(HEAD),
760 file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700761
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700762def _VerifyTag(project):
763 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
764 if not os.path.exists(gpg_dir):
Sarah Owenscecd1d82012-11-01 22:59:27 -0700765 print('warning: GnuPG was not available during last "repo init"\n'
766 'warning: Cannot automatically authenticate repo."""',
767 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700768 return True
769
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700770 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700771 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700772 except GitError:
773 cur = None
774
775 if not cur \
776 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700777 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700778 if rev.startswith(R_HEADS):
779 rev = rev[len(R_HEADS):]
780
Sarah Owenscecd1d82012-11-01 22:59:27 -0700781 print(file=sys.stderr)
782 print("warning: project '%s' branch '%s' is not signed"
783 % (project.name, rev), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700784 return False
785
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800786 env = os.environ.copy()
787 env['GIT_DIR'] = project.gitdir.encode()
788 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700789
790 cmd = [GIT, 'tag', '-v', cur]
791 proc = subprocess.Popen(cmd,
792 stdout = subprocess.PIPE,
793 stderr = subprocess.PIPE,
794 env = env)
795 out = proc.stdout.read()
796 proc.stdout.close()
797
798 err = proc.stderr.read()
799 proc.stderr.close()
800
801 if proc.wait() != 0:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700802 print(file=sys.stderr)
803 print(out, file=sys.stderr)
804 print(err, file=sys.stderr)
805 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700806 return False
807 return True
Dave Borowitz67700e92012-10-23 15:00:54 -0700808
809class _FetchTimes(object):
Dave Borowitzd9478582012-10-23 16:35:39 -0700810 _ALPHA = 0.5
811
Dave Borowitz67700e92012-10-23 15:00:54 -0700812 def __init__(self, manifest):
Anthony King85b24ac2014-05-06 15:57:48 +0100813 self._path = os.path.join(manifest.repodir, '.repo_fetchtimes.json')
Dave Borowitz67700e92012-10-23 15:00:54 -0700814 self._times = None
Dave Borowitzd9478582012-10-23 16:35:39 -0700815 self._seen = set()
Dave Borowitz67700e92012-10-23 15:00:54 -0700816
817 def Get(self, project):
818 self._Load()
819 return self._times.get(project.name, _ONE_DAY_S)
820
821 def Set(self, project, t):
Dave Borowitzd9478582012-10-23 16:35:39 -0700822 self._Load()
823 name = project.name
824 old = self._times.get(name, t)
825 self._seen.add(name)
826 a = self._ALPHA
827 self._times[name] = (a*t) + ((1-a) * old)
Dave Borowitz67700e92012-10-23 15:00:54 -0700828
829 def _Load(self):
830 if self._times is None:
831 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100832 f = open(self._path)
Dave Borowitz67700e92012-10-23 15:00:54 -0700833 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100834 self._times = json.load(f)
835 finally:
836 f.close()
837 except (IOError, ValueError):
838 try:
839 os.remove(self._path)
840 except OSError:
841 pass
842 self._times = {}
Dave Borowitz67700e92012-10-23 15:00:54 -0700843
844 def Save(self):
845 if self._times is None:
846 return
Dave Borowitzd9478582012-10-23 16:35:39 -0700847
848 to_delete = []
849 for name in self._times:
850 if name not in self._seen:
851 to_delete.append(name)
852 for name in to_delete:
853 del self._times[name]
854
Dave Borowitz67700e92012-10-23 15:00:54 -0700855 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100856 f = open(self._path, 'w')
Dave Borowitz67700e92012-10-23 15:00:54 -0700857 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100858 json.dump(self._times, f, indent=2)
859 finally:
860 f.close()
861 except (IOError, TypeError):
862 try:
863 os.remove(self._path)
864 except OSError:
865 pass
Dan Willemsen0745bb22015-08-17 13:41:45 -0700866
867# This is a replacement for xmlrpc.client.Transport using urllib2
868# and supporting persistent-http[s]. It cannot change hosts from
869# request to request like the normal transport, the real url
870# is passed during initialization.
871class PersistentTransport(xmlrpc.client.Transport):
872 def __init__(self, orig_host):
873 self.orig_host = orig_host
874
875 def request(self, host, handler, request_body, verbose=False):
876 with GetUrlCookieFile(self.orig_host, not verbose) as (cookiefile, proxy):
877 # Python doesn't understand cookies with the #HttpOnly_ prefix
878 # Since we're only using them for HTTP, copy the file temporarily,
879 # stripping those prefixes away.
880 tmpcookiefile = tempfile.NamedTemporaryFile()
881 try:
882 with open(cookiefile) as f:
883 for line in f:
884 if line.startswith("#HttpOnly_"):
885 line = line[len("#HttpOnly_"):]
886 tmpcookiefile.write(line)
887 tmpcookiefile.flush()
888
889 cookiejar = cookielib.MozillaCookieJar(tmpcookiefile.name)
890 cookiejar.load()
891 finally:
892 tmpcookiefile.close()
893
894 proxyhandler = urllib.request.ProxyHandler
895 if proxy:
896 proxyhandler = urllib.request.ProxyHandler({
897 "http": proxy,
898 "https": proxy })
899
900 opener = urllib.request.build_opener(
901 urllib.request.HTTPCookieProcessor(cookiejar),
902 proxyhandler)
903
904 url = urllib.parse.urljoin(self.orig_host, handler)
905 parse_results = urllib.parse.urlparse(url)
906
907 scheme = parse_results.scheme
908 if scheme == 'persistent-http':
909 scheme = 'http'
910 if scheme == 'persistent-https':
911 # If we're proxying through persistent-https, use http. The
912 # proxy itself will do the https.
913 if proxy:
914 scheme = 'http'
915 else:
916 scheme = 'https'
917
918 # Parse out any authentication information using the base class
919 host, extra_headers, _ = self.get_host_info(parse_results.netloc)
920
921 url = urllib.parse.urlunparse((
922 scheme,
923 host,
924 parse_results.path,
925 parse_results.params,
926 parse_results.query,
927 parse_results.fragment))
928
929 request = urllib.request.Request(url, request_body)
930 if extra_headers is not None:
931 for (name, header) in extra_headers:
932 request.add_header(name, header)
933 request.add_header('Content-Type', 'text/xml')
934 try:
935 response = opener.open(request)
936 except urllib.error.HTTPError as e:
937 if e.code == 501:
938 # We may have been redirected through a login process
939 # but our POST turned into a GET. Retry.
940 response = opener.open(request)
941 else:
942 raise
943
944 p, u = xmlrpc.client.getparser()
945 while 1:
946 data = response.read(1024)
947 if not data:
948 break
949 p.feed(data)
950 p.close()
951 return u.close()
952
953 def close(self):
954 pass
955