blob: 652a0c0d2b607cb519617e34cbc2f44272ecaa0c [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
Shawn O. Pearcef6906872009-04-18 10:49:00 -070026import time
David Pursehouse59bbb582013-05-17 10:49:33 +090027
28from pyversion import is_python3
29if is_python3():
Chirayu Desai217ea7d2013-03-01 19:14:38 +053030 import urllib.parse
David Pursehouse59bbb582013-05-17 10:49:33 +090031 import xmlrpc.client
32else:
Chirayu Desai217ea7d2013-03-01 19:14:38 +053033 import imp
34 import urlparse
David Pursehouse59bbb582013-05-17 10:49:33 +090035 import xmlrpclib
Chirayu Desai217ea7d2013-03-01 19:14:38 +053036 urllib = imp.new_module('urllib')
Chirayu Desaidb2ad9d2013-06-11 13:42:25 +053037 urllib.parse = urlparse
Chirayu Desai217ea7d2013-03-01 19:14:38 +053038 xmlrpc = imp.new_module('xmlrpc')
39 xmlrpc.client = xmlrpclib
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070040
Roy Lee18afd7f2010-05-09 04:32:08 +080041try:
42 import threading as _threading
43except ImportError:
44 import dummy_threading as _threading
45
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -070046try:
47 import resource
48 def _rlimit_nofile():
49 return resource.getrlimit(resource.RLIMIT_NOFILE)
50except ImportError:
51 def _rlimit_nofile():
52 return (256, 256)
53
Dave Borowitz18857212012-10-23 17:02:59 -070054try:
55 import multiprocessing
56except ImportError:
57 multiprocessing = None
58
Dave Borowitze2152672012-10-31 12:24:38 -070059from git_command import GIT, git_require
David Pursehoused94aaef2012-09-07 09:52:04 +090060from git_refs import R_HEADS, HEAD
Simran Basibdb52712015-08-10 13:23:23 -070061import gitc_utils
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070062from project import Project
63from project import RemoteSpec
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080064from command import Command, MirrorSafeCommand
Torne (Richard Coles)7bdbde72012-12-05 10:58:06 +000065from error import RepoChangedException, GitError, ManifestParseError
Shawn O. Pearce350cde42009-04-16 11:21:18 -070066from project import SyncBuffer
Shawn O. Pearce68194f42009-04-10 16:48:52 -070067from progress import Progress
Conley Owens094cdbe2014-01-30 15:09:59 -080068from wrapper import Wrapper
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070069
Dave Borowitz67700e92012-10-23 15:00:54 -070070_ONE_DAY_S = 24 * 60 * 60
71
Doug Andersonfc06ced2011-03-16 15:49:18 -070072class _FetchError(Exception):
73 """Internal error thrown in _FetchHelper() when we don't want stack trace."""
74 pass
75
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080076class Sync(Command, MirrorSafeCommand):
Roy Lee18afd7f2010-05-09 04:32:08 +080077 jobs = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070078 common = True
79 helpSummary = "Update working tree to the latest revision"
80 helpUsage = """
81%prog [<project>...]
82"""
83 helpDescription = """
84The '%prog' command synchronizes local project directories
85with the remote repositories specified in the manifest. If a local
86project does not yet exist, it will clone a new local directory from
87the remote repository and set up tracking branches as specified in
88the manifest. If the local project already exists, '%prog'
89will update the remote branches and rebase any new local changes
90on top of the new remote changes.
91
92'%prog' will synchronize all projects listed at the command
93line. Projects can be specified either by name, or by a relative
94or absolute path to the project's local directory. If no projects
95are specified, '%prog' will synchronize all projects listed in
96the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070097
98The -d/--detach option can be used to switch specified projects
99back to the manifest revision. This option is especially helpful
100if the project is currently on a topic branch, but the manifest
101revision is temporarily needed.
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700102
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700103The -s/--smart-sync option can be used to sync to a known good
104build as specified by the manifest-server element in the current
Victor Boivie08c880d2011-04-19 10:32:52 +0200105manifest. The -t/--smart-tag option is similar and allows you to
106specify a custom tag/label.
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700107
David Pursehousecf76b1b2012-09-14 10:31:42 +0900108The -u/--manifest-server-username and -p/--manifest-server-password
109options can be used to specify a username and password to authenticate
110with the manifest server when using the -s or -t option.
111
112If -u and -p are not specified when using the -s or -t option, '%prog'
113will attempt to read authentication credentials for the manifest server
114from the user's .netrc file.
115
116'%prog' will not use authentication credentials from -u/-p or .netrc
117if the manifest server specified in the manifest file already includes
118credentials.
119
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500120The -f/--force-broken option can be used to proceed with syncing
121other projects if a project sync fails.
122
Kevin Degiabaa7f32014-11-12 11:27:45 -0700123The --force-sync option can be used to overwrite existing git
124directories if they have previously been linked to a different
125object direcotry. WARNING: This may cause data to be lost since
126refs may be removed when overwriting.
127
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700128The --no-clone-bundle option disables any attempt to use
129$URL/clone.bundle to bootstrap a new Git repository from a
130resumeable bundle file on a content delivery network. This
131may be necessary if there are problems with the local Python
132HTTP client or proxy configuration, but the Git binary works.
133
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800134The --fetch-submodules option enables fetching Git submodules
135of a project from server.
136
David Pursehousef2fad612015-01-29 14:36:28 +0900137The -c/--current-branch option can be used to only fetch objects that
138are on the branch specified by a project's revision.
139
David Pursehouseb1553542014-09-04 21:28:09 +0900140The --optimized-fetch option can be used to only fetch projects that
141are fixed to a sha1 revision if the sha1 revision does not already
142exist locally.
143
Shawn O. Pearceeb7af872009-04-21 08:02:04 -0700144SSH Connections
145---------------
146
147If at least one project remote URL uses an SSH connection (ssh://,
148git+ssh://, or user@host:path syntax) repo will automatically
149enable the SSH ControlMaster option when connecting to that host.
150This feature permits other projects in the same '%prog' session to
151reuse the same SSH tunnel, saving connection setup overheads.
152
153To disable this behavior on UNIX platforms, set the GIT_SSH
154environment variable to 'ssh'. For example:
155
156 export GIT_SSH=ssh
157 %prog
158
159Compatibility
160~~~~~~~~~~~~~
161
162This feature is automatically disabled on Windows, due to the lack
163of UNIX domain socket support.
164
165This feature is not compatible with url.insteadof rewrites in the
166user's ~/.gitconfig. '%prog' is currently not able to perform the
167rewrite early enough to establish the ControlMaster tunnel.
168
169If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or
170later is required to fix a server side protocol bug.
171
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700172"""
173
Nico Sallembien6623b212010-05-11 12:57:01 -0700174 def _Options(self, p, show_smart=True):
Torne (Richard Coles)7bdbde72012-12-05 10:58:06 +0000175 try:
176 self.jobs = self.manifest.default.sync_j
177 except ManifestParseError:
178 self.jobs = 1
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700179
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500180 p.add_option('-f', '--force-broken',
181 dest='force_broken', action='store_true',
182 help="continue sync even if a project fails to sync")
Kevin Degiabaa7f32014-11-12 11:27:45 -0700183 p.add_option('--force-sync',
184 dest='force_sync', action='store_true',
185 help="overwrite an existing git directory if it needs to "
186 "point to a different object directory. WARNING: this "
187 "may cause loss of data")
Simran Basibdb52712015-08-10 13:23:23 -0700188 p.add_option('--force-gitc',
189 dest='force_gitc', action='store_true',
190 help="actually sync sources in the gitc client directory.")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900191 p.add_option('-l', '--local-only',
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700192 dest='local_only', action='store_true',
193 help="only update working tree, don't fetch")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900194 p.add_option('-n', '--network-only',
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700195 dest='network_only', action='store_true',
196 help="fetch only, don't update working tree")
David Pursehouse8f62fb72012-11-14 12:09:38 +0900197 p.add_option('-d', '--detach',
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700198 dest='detach_head', action='store_true',
199 help='detach projects back to manifest revision')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900200 p.add_option('-c', '--current-branch',
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700201 dest='current_branch_only', action='store_true',
202 help='fetch only current branch from server')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900203 p.add_option('-q', '--quiet',
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700204 dest='quiet', action='store_true',
205 help='be more quiet')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900206 p.add_option('-j', '--jobs',
Roy Lee18afd7f2010-05-09 04:32:08 +0800207 dest='jobs', action='store', type='int',
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700208 help="projects to fetch simultaneously (default %d)" % self.jobs)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500209 p.add_option('-m', '--manifest-name',
210 dest='manifest_name',
211 help='temporary manifest to use for this sync', metavar='NAME.xml')
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700212 p.add_option('--no-clone-bundle',
213 dest='no_clone_bundle', action='store_true',
214 help='disable use of /clone.bundle on HTTP/HTTPS')
Conley Owens8d070cf2012-11-06 13:14:31 -0800215 p.add_option('-u', '--manifest-server-username', action='store',
216 dest='manifest_server_username',
217 help='username to authenticate with the manifest server')
218 p.add_option('-p', '--manifest-server-password', action='store',
219 dest='manifest_server_password',
220 help='password to authenticate with the manifest server')
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800221 p.add_option('--fetch-submodules',
222 dest='fetch_submodules', action='store_true',
223 help='fetch submodules from server')
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700224 p.add_option('--no-tags',
225 dest='no_tags', action='store_true',
226 help="don't fetch tags")
David Pursehouseb1553542014-09-04 21:28:09 +0900227 p.add_option('--optimized-fetch',
228 dest='optimized_fetch', action='store_true',
229 help='only fetch projects fixed to sha1 if revision does not exist locally')
Nico Sallembien6623b212010-05-11 12:57:01 -0700230 if show_smart:
231 p.add_option('-s', '--smart-sync',
232 dest='smart_sync', action='store_true',
233 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200234 p.add_option('-t', '--smart-tag',
235 dest='smart_tag', action='store',
236 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700237
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700238 g = p.add_option_group('repo Version options')
239 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700240 dest='no_repo_verify', action='store_true',
241 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700242 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800243 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700244 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700245
David James89ece422014-01-09 18:51:58 -0800246 def _FetchProjectList(self, opt, projects, *args, **kwargs):
David Pursehousec1b86a22012-11-14 11:36:51 +0900247 """Main function of the fetch threads when jobs are > 1.
Roy Lee18afd7f2010-05-09 04:32:08 +0800248
David James8d201162013-10-11 17:03:19 -0700249 Delegates most of the work to _FetchHelper.
250
251 Args:
252 opt: Program options returned from optparse. See _Options().
253 projects: Projects to fetch.
David James89ece422014-01-09 18:51:58 -0800254 *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the
David James8d201162013-10-11 17:03:19 -0700255 _FetchHelper docstring for details.
256 """
257 for project in projects:
David James89ece422014-01-09 18:51:58 -0800258 success = self._FetchHelper(opt, project, *args, **kwargs)
David James8d201162013-10-11 17:03:19 -0700259 if not success and not opt.force_broken:
260 break
261
262 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
263 """Fetch git objects for a single project.
264
David Pursehousec1b86a22012-11-14 11:36:51 +0900265 Args:
266 opt: Program options returned from optparse. See _Options().
267 project: Project object for the project to fetch.
268 lock: Lock for accessing objects that are shared amongst multiple
269 _FetchHelper() threads.
270 fetched: set object that we will add project.gitdir to when we're done
271 (with our lock held).
272 pm: Instance of a Project object. We will call pm.update() (with our
273 lock held).
274 sem: We'll release() this semaphore when we exit so that another thread
275 can be started up.
276 err_event: We'll set this event in the case of an error (after printing
277 out info about the error).
David James8d201162013-10-11 17:03:19 -0700278
279 Returns:
280 Whether the fetch was successful.
David Pursehousec1b86a22012-11-14 11:36:51 +0900281 """
282 # We'll set to true once we've locked the lock.
283 did_lock = False
Doug Andersonfc06ced2011-03-16 15:49:18 -0700284
Chirayu Desaifef4ae72013-04-12 14:54:32 +0530285 if not opt.quiet:
286 print('Fetching project %s' % project.name)
287
David Pursehousec1b86a22012-11-14 11:36:51 +0900288 # Encapsulate everything in a try/except/finally so that:
289 # - We always set err_event in the case of an exception.
290 # - We always make sure we call sem.release().
291 # - We always make sure we unlock the lock if we locked it.
292 try:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700293 try:
David Pursehousec1b86a22012-11-14 11:36:51 +0900294 start = time.time()
295 success = project.Sync_NetworkHalf(
296 quiet=opt.quiet,
297 current_branch_only=opt.current_branch_only,
Kevin Degiabaa7f32014-11-12 11:27:45 -0700298 force_sync=opt.force_sync,
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700299 clone_bundle=not opt.no_clone_bundle,
David Pursehouseb1553542014-09-04 21:28:09 +0900300 no_tags=opt.no_tags, archive=self.manifest.IsArchive,
301 optimized_fetch=opt.optimized_fetch)
David Pursehousec1b86a22012-11-14 11:36:51 +0900302 self._fetch_times.Set(project, time.time() - start)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700303
David Pursehousec1b86a22012-11-14 11:36:51 +0900304 # Lock around all the rest of the code, since printing, updating a set
305 # and Progress.update() are not thread safe.
306 lock.acquire()
307 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700308
David Pursehousec1b86a22012-11-14 11:36:51 +0900309 if not success:
310 print('error: Cannot fetch %s' % project.name, file=sys.stderr)
311 if opt.force_broken:
312 print('warn: --force-broken, continuing to sync',
313 file=sys.stderr)
314 else:
315 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700316
David Pursehousec1b86a22012-11-14 11:36:51 +0900317 fetched.add(project.gitdir)
318 pm.update()
319 except _FetchError:
320 err_event.set()
Dan Sandlerc5cd4332015-07-31 09:37:53 -0400321 except Exception as e:
322 print('error: Cannot fetch %s (%s: %s)' \
323 % (project.name, type(e).__name__, str(e)), file=sys.stderr)
David Pursehousec1b86a22012-11-14 11:36:51 +0900324 err_event.set()
325 raise
326 finally:
327 if did_lock:
328 lock.release()
329 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800330
David James8d201162013-10-11 17:03:19 -0700331 return success
332
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700333 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700334 fetched = set()
David James89ece422014-01-09 18:51:58 -0800335 lock = _threading.Lock()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700336 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800337
David James89ece422014-01-09 18:51:58 -0800338 objdir_project_map = dict()
339 for project in projects:
340 objdir_project_map.setdefault(project.objdir, []).append(project)
David James8d201162013-10-11 17:03:19 -0700341
David James89ece422014-01-09 18:51:58 -0800342 threads = set()
343 sem = _threading.Semaphore(self.jobs)
344 err_event = _threading.Event()
345 for project_list in objdir_project_map.values():
346 # Check for any errors before running any more tasks.
347 # ...we'll let existing threads finish, though.
348 if err_event.isSet() and not opt.force_broken:
349 break
Doug Andersonfc06ced2011-03-16 15:49:18 -0700350
David James89ece422014-01-09 18:51:58 -0800351 sem.acquire()
352 kwargs = dict(opt=opt,
353 projects=project_list,
354 lock=lock,
355 fetched=fetched,
356 pm=pm,
357 sem=sem,
358 err_event=err_event)
359 if self.jobs > 1:
David James8d201162013-10-11 17:03:19 -0700360 t = _threading.Thread(target = self._FetchProjectList,
David James89ece422014-01-09 18:51:58 -0800361 kwargs = kwargs)
David 'Digit' Turnere2126652012-09-05 10:35:06 +0200362 # Ensure that Ctrl-C will not freeze the repo process.
363 t.daemon = True
Roy Lee18afd7f2010-05-09 04:32:08 +0800364 threads.add(t)
365 t.start()
David James89ece422014-01-09 18:51:58 -0800366 else:
367 self._FetchProjectList(**kwargs)
Roy Lee18afd7f2010-05-09 04:32:08 +0800368
David James89ece422014-01-09 18:51:58 -0800369 for t in threads:
370 t.join()
Roy Lee18afd7f2010-05-09 04:32:08 +0800371
David James89ece422014-01-09 18:51:58 -0800372 # If we saw an error, exit with code 1 so that other scripts can check.
373 if err_event.isSet():
374 print('\nerror: Exited sync due to fetch errors', file=sys.stderr)
375 sys.exit(1)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700376
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700377 pm.end()
Dave Borowitz67700e92012-10-23 15:00:54 -0700378 self._fetch_times.Save()
Dave Borowitz18857212012-10-23 17:02:59 -0700379
Julien Campergue335f5ef2013-10-16 11:02:35 +0200380 if not self.manifest.IsArchive:
381 self._GCProjects(projects)
382
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700383 return fetched
384
Dave Borowitz18857212012-10-23 17:02:59 -0700385 def _GCProjects(self, projects):
David James8d201162013-10-11 17:03:19 -0700386 gitdirs = {}
387 for project in projects:
388 gitdirs[project.gitdir] = project.bare_git
389
Dave Borowitze2152672012-10-31 12:24:38 -0700390 has_dash_c = git_require((1, 7, 2))
391 if multiprocessing and has_dash_c:
Dave Borowitz18857212012-10-23 17:02:59 -0700392 cpu_count = multiprocessing.cpu_count()
393 else:
394 cpu_count = 1
395 jobs = min(self.jobs, cpu_count)
396
397 if jobs < 2:
David James8d201162013-10-11 17:03:19 -0700398 for bare_git in gitdirs.values():
399 bare_git.gc('--auto')
Dave Borowitz18857212012-10-23 17:02:59 -0700400 return
401
402 config = {'pack.threads': cpu_count / jobs if cpu_count > jobs else 1}
403
404 threads = set()
405 sem = _threading.Semaphore(jobs)
406 err_event = _threading.Event()
407
David James8d201162013-10-11 17:03:19 -0700408 def GC(bare_git):
Dave Borowitz18857212012-10-23 17:02:59 -0700409 try:
410 try:
David James8d201162013-10-11 17:03:19 -0700411 bare_git.gc('--auto', config=config)
Dave Borowitz18857212012-10-23 17:02:59 -0700412 except GitError:
413 err_event.set()
414 except:
415 err_event.set()
416 raise
417 finally:
418 sem.release()
419
David James8d201162013-10-11 17:03:19 -0700420 for bare_git in gitdirs.values():
Dave Borowitz18857212012-10-23 17:02:59 -0700421 if err_event.isSet():
422 break
423 sem.acquire()
David James8d201162013-10-11 17:03:19 -0700424 t = _threading.Thread(target=GC, args=(bare_git,))
Dave Borowitz18857212012-10-23 17:02:59 -0700425 t.daemon = True
426 threads.add(t)
427 t.start()
428
429 for t in threads:
430 t.join()
431
432 if err_event.isSet():
Sarah Owenscecd1d82012-11-01 22:59:27 -0700433 print('\nerror: Exited sync due to gc errors', file=sys.stderr)
Dave Borowitz18857212012-10-23 17:02:59 -0700434 sys.exit(1)
435
Tim Kilbourn07669002013-03-08 15:02:49 -0800436 def _ReloadManifest(self, manifest_name=None):
437 if manifest_name:
438 # Override calls _Unload already
439 self.manifest.Override(manifest_name)
440 else:
441 self.manifest._Unload()
442
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700443 def UpdateProjectList(self):
444 new_project_paths = []
Colin Cross5acde752012-03-28 20:15:45 -0700445 for project in self.GetProjects(None, missing_ok=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700446 if project.relpath:
447 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700448 file_name = 'project.list'
449 file_path = os.path.join(self.manifest.repodir, file_name)
450 old_project_paths = []
451
452 if os.path.exists(file_path):
453 fd = open(file_path, 'r')
454 try:
455 old_project_paths = fd.read().split('\n')
456 finally:
457 fd.close()
458 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700459 if not path:
460 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700461 if path not in new_project_paths:
David Pursehouse8a68ff92012-09-24 12:15:13 +0900462 # If the path has already been deleted, we don't need to do it
Anthonyf3fdf822009-09-26 13:38:52 -0400463 if os.path.exists(self.manifest.topdir + '/' + path):
David James8d201162013-10-11 17:03:19 -0700464 gitdir = os.path.join(self.manifest.topdir, path, '.git')
David Pursehousec1b86a22012-11-14 11:36:51 +0900465 project = Project(
466 manifest = self.manifest,
467 name = path,
468 remote = RemoteSpec('origin'),
David James8d201162013-10-11 17:03:19 -0700469 gitdir = gitdir,
470 objdir = gitdir,
David Pursehousec1b86a22012-11-14 11:36:51 +0900471 worktree = os.path.join(self.manifest.topdir, path),
472 relpath = path,
473 revisionExpr = 'HEAD',
474 revisionId = None,
475 groups = None)
Anthonyf3fdf822009-09-26 13:38:52 -0400476
David Pursehousec1b86a22012-11-14 11:36:51 +0900477 if project.IsDirty():
David Pursehouse2f9e7e42013-03-05 17:26:46 +0900478 print('error: Cannot remove project "%s": uncommitted changes '
David Pursehousec1b86a22012-11-14 11:36:51 +0900479 'are present' % project.relpath, file=sys.stderr)
480 print(' commit changes, then run sync again',
481 file=sys.stderr)
482 return -1
483 else:
484 print('Deleting obsolete path %s' % project.worktree,
485 file=sys.stderr)
486 shutil.rmtree(project.worktree)
487 # Try deleting parent subdirs if they are empty
488 project_dir = os.path.dirname(project.worktree)
489 while project_dir != self.manifest.topdir:
490 try:
491 os.rmdir(project_dir)
492 except OSError:
493 break
494 project_dir = os.path.dirname(project_dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700495
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700496 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700497 fd = open(file_path, 'w')
498 try:
499 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700500 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700501 finally:
502 fd.close()
503 return 0
504
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700505 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800506 if opt.jobs:
507 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700508 if self.jobs > 1:
509 soft_limit, _ = _rlimit_nofile()
510 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
511
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700512 if opt.network_only and opt.detach_head:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700513 print('error: cannot combine -n and -d', file=sys.stderr)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700514 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700515 if opt.network_only and opt.local_only:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700516 print('error: cannot combine -n and -l', file=sys.stderr)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700517 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500518 if opt.manifest_name and opt.smart_sync:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700519 print('error: cannot combine -m and -s', file=sys.stderr)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500520 sys.exit(1)
521 if opt.manifest_name and opt.smart_tag:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700522 print('error: cannot combine -m and -t', file=sys.stderr)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500523 sys.exit(1)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900524 if opt.manifest_server_username or opt.manifest_server_password:
525 if not (opt.smart_sync or opt.smart_tag):
Sarah Owenscecd1d82012-11-01 22:59:27 -0700526 print('error: -u and -p may only be combined with -s or -t',
527 file=sys.stderr)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900528 sys.exit(1)
529 if None in [opt.manifest_server_username, opt.manifest_server_password]:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700530 print('error: both -u and -p must be given', file=sys.stderr)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900531 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500532
Simran Basibdb52712015-08-10 13:23:23 -0700533 cwd = os.getcwd()
534 if cwd.startswith(gitc_utils.GITC_MANIFEST_DIR) and not opt.force_gitc:
535 print('WARNING this will pull all the sources like a normal repo sync.\n'
536 '\nIf you want to update your GITC Client View please rerun this '
537 'command in \n%s%s.\nOr if you actually want to pull the sources, '
538 'rerun with --force-gitc.' %
539 (gitc_utils.GITC_FS_ROOT_DIR,
540 cwd.split(gitc_utils.GITC_MANIFEST_DIR)[1]))
541 sys.exit(1)
542
543 self._gitc_sync = False
544 if cwd.startswith(gitc_utils.GITC_FS_ROOT_DIR):
545 self._gitc_sync = True
546 self._client_name = cwd.split(gitc_utils.GITC_FS_ROOT_DIR)[1].split(
547 '/')[0]
548 self._client_dir = os.path.join(gitc_utils.GITC_MANIFEST_DIR,
549 self._client_name)
550 print('Updating GITC client: %s' % self._client_name)
551
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500552 if opt.manifest_name:
553 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700554
Chirayu Desaia892b102013-06-11 14:18:46 +0530555 manifest_name = opt.manifest_name
David Pursehouse59b41742015-05-07 14:36:09 +0900556 smart_sync_manifest_name = "smart_sync_override.xml"
557 smart_sync_manifest_path = os.path.join(
558 self.manifest.manifestProject.worktree, smart_sync_manifest_name)
Chirayu Desaia892b102013-06-11 14:18:46 +0530559
Victor Boivie08c880d2011-04-19 10:32:52 +0200560 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700561 if not self.manifest.manifest_server:
David Pursehouse2f9e7e42013-03-05 17:26:46 +0900562 print('error: cannot smart sync: no manifest server defined in '
Sarah Owenscecd1d82012-11-01 22:59:27 -0700563 'manifest', file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700564 sys.exit(1)
David Pursehouse86d973d2012-08-24 10:21:02 +0900565
566 manifest_server = self.manifest.manifest_server
David Pursehousefb99c712013-09-25 11:09:34 +0900567 if not opt.quiet:
568 print('Using manifest server %s' % manifest_server)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900569
David Pursehouse86d973d2012-08-24 10:21:02 +0900570 if not '@' in manifest_server:
David Pursehousecf76b1b2012-09-14 10:31:42 +0900571 username = None
572 password = None
573 if opt.manifest_server_username and opt.manifest_server_password:
574 username = opt.manifest_server_username
575 password = opt.manifest_server_password
David Pursehouse86d973d2012-08-24 10:21:02 +0900576 else:
577 try:
David Pursehousecf76b1b2012-09-14 10:31:42 +0900578 info = netrc.netrc()
579 except IOError:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700580 print('.netrc file does not exist or could not be opened',
581 file=sys.stderr)
David Pursehouse86d973d2012-08-24 10:21:02 +0900582 else:
David Pursehousecf76b1b2012-09-14 10:31:42 +0900583 try:
Chirayu Desaidb2ad9d2013-06-11 13:42:25 +0530584 parse_result = urllib.parse.urlparse(manifest_server)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900585 if parse_result.hostname:
586 username, _account, password = \
587 info.authenticators(parse_result.hostname)
588 except TypeError:
589 # TypeError is raised when the given hostname is not present
590 # in the .netrc file.
Sarah Owenscecd1d82012-11-01 22:59:27 -0700591 print('No credentials found for %s in .netrc'
592 % parse_result.hostname, file=sys.stderr)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700593 except netrc.NetrcParseError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700594 print('Error parsing .netrc file: %s' % e, file=sys.stderr)
David Pursehousecf76b1b2012-09-14 10:31:42 +0900595
596 if (username and password):
597 manifest_server = manifest_server.replace('://', '://%s:%s@' %
598 (username, password),
599 1)
David Pursehouse86d973d2012-08-24 10:21:02 +0900600
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700601 try:
Chirayu Desai217ea7d2013-03-01 19:14:38 +0530602 server = xmlrpc.client.Server(manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200603 if opt.smart_sync:
604 p = self.manifest.manifestProject
605 b = p.GetBranch(p.CurrentBranch)
606 branch = b.merge
607 if branch.startswith(R_HEADS):
608 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700609
Victor Boivie08c880d2011-04-19 10:32:52 +0200610 env = os.environ.copy()
Jeff Davidson5cf16602014-10-02 10:13:38 -0700611 if 'SYNC_TARGET' in env:
612 target = env['SYNC_TARGET']
613 [success, manifest_str] = server.GetApprovedManifest(branch, target)
614 elif 'TARGET_PRODUCT' in env and 'TARGET_BUILD_VARIANT' in env:
Victor Boivie08c880d2011-04-19 10:32:52 +0200615 target = '%s-%s' % (env['TARGET_PRODUCT'],
616 env['TARGET_BUILD_VARIANT'])
617 [success, manifest_str] = server.GetApprovedManifest(branch, target)
618 else:
619 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700620 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200621 assert(opt.smart_tag)
622 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700623
624 if success:
David Pursehouse59b41742015-05-07 14:36:09 +0900625 manifest_name = smart_sync_manifest_name
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700626 try:
David Pursehouse59b41742015-05-07 14:36:09 +0900627 f = open(smart_sync_manifest_path, 'w')
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700628 try:
629 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700630 finally:
631 f.close()
David Pursehouse727cc3e2015-05-07 14:16:49 +0900632 except IOError as e:
633 print('error: cannot write manifest to %s:\n%s'
David Pursehouse59b41742015-05-07 14:36:09 +0900634 % (smart_sync_manifest_path, e),
Sarah Owenscecd1d82012-11-01 22:59:27 -0700635 file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700636 sys.exit(1)
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100637 self._ReloadManifest(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700638 else:
David Pursehouse351fe2c2013-09-25 17:54:26 +0900639 print('error: manifest server RPC call failed: %s' %
640 manifest_str, file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700641 sys.exit(1)
Chirayu Desai217ea7d2013-03-01 19:14:38 +0530642 except (socket.error, IOError, xmlrpc.client.Fault) as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700643 print('error: cannot connect to manifest server %s:\n%s'
644 % (self.manifest.manifest_server, e), file=sys.stderr)
David Pursehousebd489c42012-08-23 10:21:26 +0900645 sys.exit(1)
Chirayu Desai217ea7d2013-03-01 19:14:38 +0530646 except xmlrpc.client.ProtocolError as e:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700647 print('error: cannot connect to manifest server %s:\n%d %s'
648 % (self.manifest.manifest_server, e.errcode, e.errmsg),
649 file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700650 sys.exit(1)
David Pursehouse59b41742015-05-07 14:36:09 +0900651 else: # Not smart sync or smart tag mode
652 if os.path.isfile(smart_sync_manifest_path):
653 try:
654 os.remove(smart_sync_manifest_path)
655 except OSError as e:
656 print('error: failed to remove existing smart sync override manifest: %s' %
657 e, file=sys.stderr)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700658
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700659 rp = self.manifest.repoProject
660 rp.PreSync()
661
662 mp = self.manifest.manifestProject
663 mp.PreSync()
664
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800665 if opt.repo_upgraded:
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700666 _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800667
Simran Basibdb52712015-08-10 13:23:23 -0700668 if self._gitc_sync:
669 gitc_utils.generate_gitc_manifest(self._client_dir, self.manifest)
670 print('GITC client successfully synced.')
671 return
672
673
Nico Sallembien9bb18162009-12-07 15:38:01 -0800674 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700675 mp.Sync_NetworkHalf(quiet=opt.quiet,
Mitchel Humpherys597868b2012-10-29 10:18:34 -0700676 current_branch_only=opt.current_branch_only,
David Pursehouseb1553542014-09-04 21:28:09 +0900677 no_tags=opt.no_tags,
678 optimized_fetch=opt.optimized_fetch)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800679
680 if mp.HasChanges:
681 syncbuf = SyncBuffer(mp.config)
682 mp.Sync_LocalHalf(syncbuf)
683 if not syncbuf.Finish():
684 sys.exit(1)
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100685 self._ReloadManifest(manifest_name)
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700686 if opt.jobs is None:
687 self.jobs = self.manifest.default.sync_j
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800688 all_projects = self.GetProjects(args,
689 missing_ok=True,
690 submodules_ok=opt.fetch_submodules)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700691
Dave Borowitz67700e92012-10-23 15:00:54 -0700692 self._fetch_times = _FetchTimes(self.manifest)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700693 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700694 to_fetch = []
695 now = time.time()
Dave Borowitz67700e92012-10-23 15:00:54 -0700696 if _ONE_DAY_S <= (now - rp.LastFetch):
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700697 to_fetch.append(rp)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900698 to_fetch.extend(all_projects)
Dave Borowitz67700e92012-10-23 15:00:54 -0700699 to_fetch.sort(key=self._fetch_times.Get, reverse=True)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700700
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800701 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700702 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700703 if opt.network_only:
704 # bail out now; the rest touches the working tree
705 return
706
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800707 # Iteratively fetch missing and/or nested unregistered submodules
708 previously_missing_set = set()
709 while True:
Victor Boivie53a6c5d2013-03-19 12:20:52 +0100710 self._ReloadManifest(manifest_name)
Che-Liang Chioub2bd91c2012-01-11 11:28:42 +0800711 all_projects = self.GetProjects(args,
712 missing_ok=True,
713 submodules_ok=opt.fetch_submodules)
714 missing = []
715 for project in all_projects:
716 if project.gitdir not in fetched:
717 missing.append(project)
718 if not missing:
719 break
720 # Stop us from non-stopped fetching actually-missing repos: If set of
721 # missing repos has not been changed from last fetch, we break.
722 missing_set = set(p.name for p in missing)
723 if previously_missing_set == missing_set:
724 break
725 previously_missing_set = missing_set
726 fetched.update(self._Fetch(missing, opt))
727
Julien Campergue335f5ef2013-10-16 11:02:35 +0200728 if self.manifest.IsMirror or self.manifest.IsArchive:
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700729 # bail out now, we have no working tree
730 return
731
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700732 if self.UpdateProjectList():
733 sys.exit(1)
734
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700735 syncbuf = SyncBuffer(mp.config,
736 detach_head = opt.detach_head)
David Pursehouse8a68ff92012-09-24 12:15:13 +0900737 pm = Progress('Syncing work tree', len(all_projects))
738 for project in all_projects:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700739 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800740 if project.worktree:
Kevin Degiabaa7f32014-11-12 11:27:45 -0700741 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700742 pm.end()
Sarah Owenscecd1d82012-11-01 22:59:27 -0700743 print(file=sys.stderr)
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700744 if not syncbuf.Finish():
745 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700746
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700747 # If there's a notice that's supposed to print at the end of the sync, print
748 # it now...
749 if self.manifest.notice:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700750 print(self.manifest.notice)
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700751
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700752def _PostRepoUpgrade(manifest, quiet=False):
Conley Owens094cdbe2014-01-30 15:09:59 -0800753 wrapper = Wrapper()
Conley Owensc9129d92012-10-01 16:12:28 -0700754 if wrapper.NeedSetupGnuPG():
Shawn O. Pearce80d2ceb2012-10-26 12:23:05 -0700755 wrapper.SetupGnuPG(quiet)
Conley Owensf2fe2d92014-01-29 13:53:43 -0800756 for project in manifest.projects:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700757 if project.Exists:
758 project.PostRepoUpgrade()
759
760def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
761 if rp.HasChanges:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700762 print('info: A new version of repo is available', file=sys.stderr)
763 print(file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700764 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700765 syncbuf = SyncBuffer(rp.config)
766 rp.Sync_LocalHalf(syncbuf)
767 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700768 sys.exit(1)
Sarah Owenscecd1d82012-11-01 22:59:27 -0700769 print('info: Restarting repo with latest version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700770 raise RepoChangedException(['--repo-upgraded'])
771 else:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700772 print('warning: Skipped upgrade to unverified version', file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700773 else:
774 if verbose:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700775 print('repo version %s is current' % rp.work_git.describe(HEAD),
776 file=sys.stderr)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700777
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700778def _VerifyTag(project):
779 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
780 if not os.path.exists(gpg_dir):
Sarah Owenscecd1d82012-11-01 22:59:27 -0700781 print('warning: GnuPG was not available during last "repo init"\n'
782 'warning: Cannot automatically authenticate repo."""',
783 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700784 return True
785
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700786 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700787 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700788 except GitError:
789 cur = None
790
791 if not cur \
792 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700793 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700794 if rev.startswith(R_HEADS):
795 rev = rev[len(R_HEADS):]
796
Sarah Owenscecd1d82012-11-01 22:59:27 -0700797 print(file=sys.stderr)
798 print("warning: project '%s' branch '%s' is not signed"
799 % (project.name, rev), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700800 return False
801
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800802 env = os.environ.copy()
803 env['GIT_DIR'] = project.gitdir.encode()
804 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700805
806 cmd = [GIT, 'tag', '-v', cur]
807 proc = subprocess.Popen(cmd,
808 stdout = subprocess.PIPE,
809 stderr = subprocess.PIPE,
810 env = env)
811 out = proc.stdout.read()
812 proc.stdout.close()
813
814 err = proc.stderr.read()
815 proc.stderr.close()
816
817 if proc.wait() != 0:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700818 print(file=sys.stderr)
819 print(out, file=sys.stderr)
820 print(err, file=sys.stderr)
821 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700822 return False
823 return True
Dave Borowitz67700e92012-10-23 15:00:54 -0700824
825class _FetchTimes(object):
Dave Borowitzd9478582012-10-23 16:35:39 -0700826 _ALPHA = 0.5
827
Dave Borowitz67700e92012-10-23 15:00:54 -0700828 def __init__(self, manifest):
Anthony King85b24ac2014-05-06 15:57:48 +0100829 self._path = os.path.join(manifest.repodir, '.repo_fetchtimes.json')
Dave Borowitz67700e92012-10-23 15:00:54 -0700830 self._times = None
Dave Borowitzd9478582012-10-23 16:35:39 -0700831 self._seen = set()
Dave Borowitz67700e92012-10-23 15:00:54 -0700832
833 def Get(self, project):
834 self._Load()
835 return self._times.get(project.name, _ONE_DAY_S)
836
837 def Set(self, project, t):
Dave Borowitzd9478582012-10-23 16:35:39 -0700838 self._Load()
839 name = project.name
840 old = self._times.get(name, t)
841 self._seen.add(name)
842 a = self._ALPHA
843 self._times[name] = (a*t) + ((1-a) * old)
Dave Borowitz67700e92012-10-23 15:00:54 -0700844
845 def _Load(self):
846 if self._times is None:
847 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100848 f = open(self._path)
Dave Borowitz67700e92012-10-23 15:00:54 -0700849 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100850 self._times = json.load(f)
851 finally:
852 f.close()
853 except (IOError, ValueError):
854 try:
855 os.remove(self._path)
856 except OSError:
857 pass
858 self._times = {}
Dave Borowitz67700e92012-10-23 15:00:54 -0700859
860 def Save(self):
861 if self._times is None:
862 return
Dave Borowitzd9478582012-10-23 16:35:39 -0700863
864 to_delete = []
865 for name in self._times:
866 if name not in self._seen:
867 to_delete.append(name)
868 for name in to_delete:
869 del self._times[name]
870
Dave Borowitz67700e92012-10-23 15:00:54 -0700871 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100872 f = open(self._path, 'w')
Dave Borowitz67700e92012-10-23 15:00:54 -0700873 try:
Anthony King85b24ac2014-05-06 15:57:48 +0100874 json.dump(self._times, f, indent=2)
875 finally:
876 f.close()
877 except (IOError, TypeError):
878 try:
879 os.remove(self._path)
880 except OSError:
881 pass