blob: 244a560ba8fe5b2aec92c4084b05d036c64111aa [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
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -070016from optparse import SUPPRESS_HELP
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070017import os
18import re
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070019import shutil
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070020import socket
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070021import subprocess
22import sys
Shawn O. Pearcef6906872009-04-18 10:49:00 -070023import time
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070024import xmlrpclib
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070025
Roy Lee18afd7f2010-05-09 04:32:08 +080026try:
27 import threading as _threading
28except ImportError:
29 import dummy_threading as _threading
30
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -070031try:
32 import resource
33 def _rlimit_nofile():
34 return resource.getrlimit(resource.RLIMIT_NOFILE)
35except ImportError:
36 def _rlimit_nofile():
37 return (256, 256)
38
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070039from git_command import GIT
Nico Sallembien5732e472010-04-26 11:17:29 -070040from git_refs import R_HEADS
Shawn O. Pearcee756c412009-04-13 11:51:15 -070041from project import HEAD
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070042from project import Project
43from project import RemoteSpec
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080044from command import Command, MirrorSafeCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070045from error import RepoChangedException, GitError
46from project import R_HEADS
Shawn O. Pearce350cde42009-04-16 11:21:18 -070047from project import SyncBuffer
Shawn O. Pearce68194f42009-04-10 16:48:52 -070048from progress import Progress
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070049
Doug Andersonfc06ced2011-03-16 15:49:18 -070050class _FetchError(Exception):
51 """Internal error thrown in _FetchHelper() when we don't want stack trace."""
52 pass
53
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080054class Sync(Command, MirrorSafeCommand):
Roy Lee18afd7f2010-05-09 04:32:08 +080055 jobs = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070056 common = True
57 helpSummary = "Update working tree to the latest revision"
58 helpUsage = """
59%prog [<project>...]
60"""
61 helpDescription = """
62The '%prog' command synchronizes local project directories
63with the remote repositories specified in the manifest. If a local
64project does not yet exist, it will clone a new local directory from
65the remote repository and set up tracking branches as specified in
66the manifest. If the local project already exists, '%prog'
67will update the remote branches and rebase any new local changes
68on top of the new remote changes.
69
70'%prog' will synchronize all projects listed at the command
71line. Projects can be specified either by name, or by a relative
72or absolute path to the project's local directory. If no projects
73are specified, '%prog' will synchronize all projects listed in
74the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070075
76The -d/--detach option can be used to switch specified projects
77back to the manifest revision. This option is especially helpful
78if the project is currently on a topic branch, but the manifest
79revision is temporarily needed.
Shawn O. Pearceeb7af872009-04-21 08:02:04 -070080
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070081The -s/--smart-sync option can be used to sync to a known good
82build as specified by the manifest-server element in the current
Victor Boivie08c880d2011-04-19 10:32:52 +020083manifest. The -t/--smart-tag option is similar and allows you to
84specify a custom tag/label.
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070085
Andrei Warkentin5df6de02010-07-02 17:58:31 -050086The -f/--force-broken option can be used to proceed with syncing
87other projects if a project sync fails.
88
Shawn O. Pearceeb7af872009-04-21 08:02:04 -070089SSH Connections
90---------------
91
92If at least one project remote URL uses an SSH connection (ssh://,
93git+ssh://, or user@host:path syntax) repo will automatically
94enable the SSH ControlMaster option when connecting to that host.
95This feature permits other projects in the same '%prog' session to
96reuse the same SSH tunnel, saving connection setup overheads.
97
98To disable this behavior on UNIX platforms, set the GIT_SSH
99environment variable to 'ssh'. For example:
100
101 export GIT_SSH=ssh
102 %prog
103
104Compatibility
105~~~~~~~~~~~~~
106
107This feature is automatically disabled on Windows, due to the lack
108of UNIX domain socket support.
109
110This feature is not compatible with url.insteadof rewrites in the
111user's ~/.gitconfig. '%prog' is currently not able to perform the
112rewrite early enough to establish the ControlMaster tunnel.
113
114If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or
115later is required to fix a server side protocol bug.
116
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700117"""
118
Nico Sallembien6623b212010-05-11 12:57:01 -0700119 def _Options(self, p, show_smart=True):
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700120 self.jobs = self.manifest.default.sync_j
121
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500122 p.add_option('-f', '--force-broken',
123 dest='force_broken', action='store_true',
124 help="continue sync even if a project fails to sync")
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700125 p.add_option('-l','--local-only',
126 dest='local_only', action='store_true',
127 help="only update working tree, don't fetch")
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700128 p.add_option('-n','--network-only',
129 dest='network_only', action='store_true',
130 help="fetch only, don't update working tree")
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700131 p.add_option('-d','--detach',
132 dest='detach_head', action='store_true',
133 help='detach projects back to manifest revision')
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700134 p.add_option('-q','--quiet',
135 dest='quiet', action='store_true',
136 help='be more quiet')
Roy Lee18afd7f2010-05-09 04:32:08 +0800137 p.add_option('-j','--jobs',
138 dest='jobs', action='store', type='int',
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700139 help="projects to fetch simultaneously (default %d)" % self.jobs)
Nico Sallembien6623b212010-05-11 12:57:01 -0700140 if show_smart:
141 p.add_option('-s', '--smart-sync',
142 dest='smart_sync', action='store_true',
143 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200144 p.add_option('-t', '--smart-tag',
145 dest='smart_tag', action='store',
146 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700147
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700148 g = p.add_option_group('repo Version options')
149 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700150 dest='no_repo_verify', action='store_true',
151 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700152 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800153 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700154 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700155
Doug Andersonfc06ced2011-03-16 15:49:18 -0700156 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
157 """Main function of the fetch threads when jobs are > 1.
Roy Lee18afd7f2010-05-09 04:32:08 +0800158
Doug Andersonfc06ced2011-03-16 15:49:18 -0700159 Args:
160 opt: Program options returned from optparse. See _Options().
161 project: Project object for the project to fetch.
162 lock: Lock for accessing objects that are shared amongst multiple
163 _FetchHelper() threads.
164 fetched: set object that we will add project.gitdir to when we're done
165 (with our lock held).
166 pm: Instance of a Project object. We will call pm.update() (with our
167 lock held).
168 sem: We'll release() this semaphore when we exit so that another thread
169 can be started up.
170 err_event: We'll set this event in the case of an error (after printing
171 out info about the error).
172 """
173 # We'll set to true once we've locked the lock.
174 did_lock = False
175
176 # Encapsulate everything in a try/except/finally so that:
177 # - We always set err_event in the case of an exception.
178 # - We always make sure we call sem.release().
179 # - We always make sure we unlock the lock if we locked it.
180 try:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700181 try:
182 success = project.Sync_NetworkHalf(quiet=opt.quiet)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700183
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700184 # Lock around all the rest of the code, since printing, updating a set
185 # and Progress.update() are not thread safe.
186 lock.acquire()
187 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700188
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700189 if not success:
190 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
191 if opt.force_broken:
192 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
193 else:
194 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700195
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700196 fetched.add(project.gitdir)
197 pm.update()
198 except BaseException, e:
199 # Notify the _Fetch() function about all errors.
200 err_event.set()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700201
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700202 # If we got our own _FetchError, we don't want a stack trace.
203 # However, if we got something else (something in Sync_NetworkHalf?),
204 # we'd like one (so re-raise after we've set err_event).
205 if not isinstance(e, _FetchError):
206 raise
Doug Andersonfc06ced2011-03-16 15:49:18 -0700207 finally:
208 if did_lock:
209 lock.release()
210 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800211
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700212 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700213 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700214 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800215
216 if self.jobs == 1:
217 for project in projects:
218 pm.update()
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700219 if project.Sync_NetworkHalf(quiet=opt.quiet):
Roy Lee18afd7f2010-05-09 04:32:08 +0800220 fetched.add(project.gitdir)
221 else:
222 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500223 if opt.force_broken:
224 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
225 else:
226 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800227 else:
228 threads = set()
229 lock = _threading.Lock()
230 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700231 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800232 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700233 # Check for any errors before starting any new threads.
234 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400235 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700236 break
237
Roy Lee18afd7f2010-05-09 04:32:08 +0800238 sem.acquire()
239 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700240 args = (opt,
241 project,
242 lock,
243 fetched,
244 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700245 sem,
246 err_event))
Roy Lee18afd7f2010-05-09 04:32:08 +0800247 threads.add(t)
248 t.start()
249
250 for t in threads:
251 t.join()
252
Doug Andersonfc06ced2011-03-16 15:49:18 -0700253 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400254 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700255 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
256 sys.exit(1)
257
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700258 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700259 for project in projects:
260 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700261 return fetched
262
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700263 def UpdateProjectList(self):
264 new_project_paths = []
265 for project in self.manifest.projects.values():
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700266 if project.relpath:
267 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700268 file_name = 'project.list'
269 file_path = os.path.join(self.manifest.repodir, file_name)
270 old_project_paths = []
271
272 if os.path.exists(file_path):
273 fd = open(file_path, 'r')
274 try:
275 old_project_paths = fd.read().split('\n')
276 finally:
277 fd.close()
278 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700279 if not path:
280 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700281 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400282 """If the path has already been deleted, we don't need to do it
283 """
284 if os.path.exists(self.manifest.topdir + '/' + path):
285 project = Project(
286 manifest = self.manifest,
287 name = path,
288 remote = RemoteSpec('origin'),
289 gitdir = os.path.join(self.manifest.topdir,
290 path, '.git'),
291 worktree = os.path.join(self.manifest.topdir, path),
292 relpath = path,
293 revisionExpr = 'HEAD',
294 revisionId = None)
295
296 if project.IsDirty():
297 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700298uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400299 print >>sys.stderr, ' commit changes, then run sync again'
300 return -1
301 else:
302 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
303 shutil.rmtree(project.worktree)
304 # Try deleting parent subdirs if they are empty
305 dir = os.path.dirname(project.worktree)
306 while dir != self.manifest.topdir:
307 try:
308 os.rmdir(dir)
309 except OSError:
310 break
311 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700312
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700313 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700314 fd = open(file_path, 'w')
315 try:
316 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700317 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700318 finally:
319 fd.close()
320 return 0
321
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700322 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800323 if opt.jobs:
324 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700325 if self.jobs > 1:
326 soft_limit, _ = _rlimit_nofile()
327 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
328
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700329 if opt.network_only and opt.detach_head:
330 print >>sys.stderr, 'error: cannot combine -n and -d'
331 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700332 if opt.network_only and opt.local_only:
333 print >>sys.stderr, 'error: cannot combine -n and -l'
334 sys.exit(1)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700335
Victor Boivie08c880d2011-04-19 10:32:52 +0200336 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700337 if not self.manifest.manifest_server:
338 print >>sys.stderr, \
339 'error: cannot smart sync: no manifest server defined in manifest'
340 sys.exit(1)
341 try:
342 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200343 if opt.smart_sync:
344 p = self.manifest.manifestProject
345 b = p.GetBranch(p.CurrentBranch)
346 branch = b.merge
347 if branch.startswith(R_HEADS):
348 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700349
Victor Boivie08c880d2011-04-19 10:32:52 +0200350 env = os.environ.copy()
351 if (env.has_key('TARGET_PRODUCT') and
352 env.has_key('TARGET_BUILD_VARIANT')):
353 target = '%s-%s' % (env['TARGET_PRODUCT'],
354 env['TARGET_BUILD_VARIANT'])
355 [success, manifest_str] = server.GetApprovedManifest(branch, target)
356 else:
357 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700358 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200359 assert(opt.smart_tag)
360 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700361
362 if success:
363 manifest_name = "smart_sync_override.xml"
364 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
365 manifest_name)
366 try:
367 f = open(manifest_path, 'w')
368 try:
369 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700370 finally:
371 f.close()
372 except IOError:
373 print >>sys.stderr, 'error: cannot write manifest to %s' % \
374 manifest_path
375 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700376 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700377 else:
378 print >>sys.stderr, 'error: %s' % manifest_str
379 sys.exit(1)
380 except socket.error:
381 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
382 self.manifest.manifest_server)
383 sys.exit(1)
384
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700385 rp = self.manifest.repoProject
386 rp.PreSync()
387
388 mp = self.manifest.manifestProject
389 mp.PreSync()
390
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800391 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700392 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800393
Nico Sallembien9bb18162009-12-07 15:38:01 -0800394 if not opt.local_only:
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700395 mp.Sync_NetworkHalf(quiet=opt.quiet)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800396
397 if mp.HasChanges:
398 syncbuf = SyncBuffer(mp.config)
399 mp.Sync_LocalHalf(syncbuf)
400 if not syncbuf.Finish():
401 sys.exit(1)
402 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700403 if opt.jobs is None:
404 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700405 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700406
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700407 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700408 to_fetch = []
409 now = time.time()
410 if (24 * 60 * 60) <= (now - rp.LastFetch):
411 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700412 to_fetch.extend(all)
413
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700414 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700415 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700416 if opt.network_only:
417 # bail out now; the rest touches the working tree
418 return
419
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700420 self.manifest._Unload()
421 all = self.GetProjects(args, missing_ok=True)
422 missing = []
423 for project in all:
424 if project.gitdir not in fetched:
425 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700426 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700427
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700428 if self.manifest.IsMirror:
429 # bail out now, we have no working tree
430 return
431
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700432 if self.UpdateProjectList():
433 sys.exit(1)
434
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700435 syncbuf = SyncBuffer(mp.config,
436 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700437 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700438 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700439 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800440 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700441 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700442 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700443 print >>sys.stderr
444 if not syncbuf.Finish():
445 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700446
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700447 # If there's a notice that's supposed to print at the end of the sync, print
448 # it now...
449 if self.manifest.notice:
450 print self.manifest.notice
451
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700452def _PostRepoUpgrade(manifest):
453 for project in manifest.projects.values():
454 if project.Exists:
455 project.PostRepoUpgrade()
456
457def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
458 if rp.HasChanges:
459 print >>sys.stderr, 'info: A new version of repo is available'
460 print >>sys.stderr, ''
461 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700462 syncbuf = SyncBuffer(rp.config)
463 rp.Sync_LocalHalf(syncbuf)
464 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700465 sys.exit(1)
466 print >>sys.stderr, 'info: Restarting repo with latest version'
467 raise RepoChangedException(['--repo-upgraded'])
468 else:
469 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
470 else:
471 if verbose:
472 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
473
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700474def _VerifyTag(project):
475 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
476 if not os.path.exists(gpg_dir):
477 print >>sys.stderr,\
478"""warning: GnuPG was not available during last "repo init"
479warning: Cannot automatically authenticate repo."""
480 return True
481
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700482 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700483 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700484 except GitError:
485 cur = None
486
487 if not cur \
488 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700489 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700490 if rev.startswith(R_HEADS):
491 rev = rev[len(R_HEADS):]
492
493 print >>sys.stderr
494 print >>sys.stderr,\
495 "warning: project '%s' branch '%s' is not signed" \
496 % (project.name, rev)
497 return False
498
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800499 env = os.environ.copy()
500 env['GIT_DIR'] = project.gitdir.encode()
501 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700502
503 cmd = [GIT, 'tag', '-v', cur]
504 proc = subprocess.Popen(cmd,
505 stdout = subprocess.PIPE,
506 stderr = subprocess.PIPE,
507 env = env)
508 out = proc.stdout.read()
509 proc.stdout.close()
510
511 err = proc.stderr.read()
512 proc.stderr.close()
513
514 if proc.wait() != 0:
515 print >>sys.stderr
516 print >>sys.stderr, out
517 print >>sys.stderr, err
518 print >>sys.stderr
519 return False
520 return True