blob: 93010c51e4b70859de0f73293281058ab1c5ec83 [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):
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500120 p.add_option('-f', '--force-broken',
121 dest='force_broken', action='store_true',
122 help="continue sync even if a project fails to sync")
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700123 p.add_option('-l','--local-only',
124 dest='local_only', action='store_true',
125 help="only update working tree, don't fetch")
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700126 p.add_option('-n','--network-only',
127 dest='network_only', action='store_true',
128 help="fetch only, don't update working tree")
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700129 p.add_option('-d','--detach',
130 dest='detach_head', action='store_true',
131 help='detach projects back to manifest revision')
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700132 p.add_option('-q','--quiet',
133 dest='quiet', action='store_true',
134 help='be more quiet')
Roy Lee18afd7f2010-05-09 04:32:08 +0800135 p.add_option('-j','--jobs',
136 dest='jobs', action='store', type='int',
137 help="number of projects to fetch simultaneously")
Nico Sallembien6623b212010-05-11 12:57:01 -0700138 if show_smart:
139 p.add_option('-s', '--smart-sync',
140 dest='smart_sync', action='store_true',
141 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200142 p.add_option('-t', '--smart-tag',
143 dest='smart_tag', action='store',
144 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700145
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700146 g = p.add_option_group('repo Version options')
147 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700148 dest='no_repo_verify', action='store_true',
149 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700150 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800151 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700152 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700153
Doug Andersonfc06ced2011-03-16 15:49:18 -0700154 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
155 """Main function of the fetch threads when jobs are > 1.
156
157 Args:
158 opt: Program options returned from optparse. See _Options().
159 project: Project object for the project to fetch.
160 lock: Lock for accessing objects that are shared amongst multiple
161 _FetchHelper() threads.
162 fetched: set object that we will add project.gitdir to when we're done
163 (with our lock held).
164 pm: Instance of a Project object. We will call pm.update() (with our
165 lock held).
166 sem: We'll release() this semaphore when we exit so that another thread
167 can be started up.
168 err_event: We'll set this event in the case of an error (after printing
169 out info about the error).
170 """
171 # We'll set to true once we've locked the lock.
172 did_lock = False
173
174 # Encapsulate everything in a try/except/finally so that:
175 # - We always set err_event in the case of an exception.
176 # - We always make sure we call sem.release().
177 # - We always make sure we unlock the lock if we locked it.
178 try:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700179 try:
180 success = project.Sync_NetworkHalf(quiet=opt.quiet)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700181
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700182 # Lock around all the rest of the code, since printing, updating a set
183 # and Progress.update() are not thread safe.
184 lock.acquire()
185 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700186
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700187 if not success:
188 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
189 if opt.force_broken:
190 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
191 else:
192 raise _FetchError()
Roy Lee18afd7f2010-05-09 04:32:08 +0800193
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700194 fetched.add(project.gitdir)
195 pm.update()
196 except BaseException, e:
197 # Notify the _Fetch() function about all errors.
198 err_event.set()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700199
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700200 # If we got our own _FetchError, we don't want a stack trace.
201 # However, if we got something else (something in Sync_NetworkHalf?),
202 # we'd like one (so re-raise after we've set err_event).
203 if not isinstance(e, _FetchError):
204 raise
Doug Andersonfc06ced2011-03-16 15:49:18 -0700205 finally:
206 if did_lock:
207 lock.release()
208 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800209
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700210 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700211 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700212 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800213
214 if self.jobs == 1:
215 for project in projects:
216 pm.update()
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700217 if project.Sync_NetworkHalf(quiet=opt.quiet):
Roy Lee18afd7f2010-05-09 04:32:08 +0800218 fetched.add(project.gitdir)
219 else:
220 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500221 if opt.force_broken:
222 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
223 else:
224 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800225 else:
226 threads = set()
227 lock = _threading.Lock()
228 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700229 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800230 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700231 # Check for any errors before starting any new threads.
232 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400233 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700234 break
235
Roy Lee18afd7f2010-05-09 04:32:08 +0800236 sem.acquire()
237 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700238 args = (opt,
239 project,
240 lock,
241 fetched,
242 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700243 sem,
244 err_event))
Roy Lee18afd7f2010-05-09 04:32:08 +0800245 threads.add(t)
246 t.start()
247
248 for t in threads:
249 t.join()
250
Doug Andersonfc06ced2011-03-16 15:49:18 -0700251 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400252 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700253 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
254 sys.exit(1)
255
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700256 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700257 for project in projects:
258 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700259 return fetched
260
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700261 def UpdateProjectList(self):
262 new_project_paths = []
263 for project in self.manifest.projects.values():
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700264 if project.relpath:
265 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700266 file_name = 'project.list'
267 file_path = os.path.join(self.manifest.repodir, file_name)
268 old_project_paths = []
269
270 if os.path.exists(file_path):
271 fd = open(file_path, 'r')
272 try:
273 old_project_paths = fd.read().split('\n')
274 finally:
275 fd.close()
276 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700277 if not path:
278 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700279 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400280 """If the path has already been deleted, we don't need to do it
281 """
282 if os.path.exists(self.manifest.topdir + '/' + path):
283 project = Project(
284 manifest = self.manifest,
285 name = path,
286 remote = RemoteSpec('origin'),
287 gitdir = os.path.join(self.manifest.topdir,
288 path, '.git'),
289 worktree = os.path.join(self.manifest.topdir, path),
290 relpath = path,
291 revisionExpr = 'HEAD',
292 revisionId = None)
293
294 if project.IsDirty():
295 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700296uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400297 print >>sys.stderr, ' commit changes, then run sync again'
298 return -1
299 else:
300 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
301 shutil.rmtree(project.worktree)
302 # Try deleting parent subdirs if they are empty
303 dir = os.path.dirname(project.worktree)
304 while dir != self.manifest.topdir:
305 try:
306 os.rmdir(dir)
307 except OSError:
308 break
309 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700310
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700311 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700312 fd = open(file_path, 'w')
313 try:
314 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700315 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700316 finally:
317 fd.close()
318 return 0
319
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700320 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800321 if opt.jobs:
322 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700323 if self.jobs > 1:
324 soft_limit, _ = _rlimit_nofile()
325 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
326
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700327 if opt.network_only and opt.detach_head:
328 print >>sys.stderr, 'error: cannot combine -n and -d'
329 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700330 if opt.network_only and opt.local_only:
331 print >>sys.stderr, 'error: cannot combine -n and -l'
332 sys.exit(1)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700333
Victor Boivie08c880d2011-04-19 10:32:52 +0200334 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700335 if not self.manifest.manifest_server:
336 print >>sys.stderr, \
337 'error: cannot smart sync: no manifest server defined in manifest'
338 sys.exit(1)
339 try:
340 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200341 if opt.smart_sync:
342 p = self.manifest.manifestProject
343 b = p.GetBranch(p.CurrentBranch)
344 branch = b.merge
345 if branch.startswith(R_HEADS):
346 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700347
Victor Boivie08c880d2011-04-19 10:32:52 +0200348 env = os.environ.copy()
349 if (env.has_key('TARGET_PRODUCT') and
350 env.has_key('TARGET_BUILD_VARIANT')):
351 target = '%s-%s' % (env['TARGET_PRODUCT'],
352 env['TARGET_BUILD_VARIANT'])
353 [success, manifest_str] = server.GetApprovedManifest(branch, target)
354 else:
355 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700356 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200357 assert(opt.smart_tag)
358 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700359
360 if success:
361 manifest_name = "smart_sync_override.xml"
362 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
363 manifest_name)
364 try:
365 f = open(manifest_path, 'w')
366 try:
367 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700368 finally:
369 f.close()
370 except IOError:
371 print >>sys.stderr, 'error: cannot write manifest to %s' % \
372 manifest_path
373 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700374 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700375 else:
376 print >>sys.stderr, 'error: %s' % manifest_str
377 sys.exit(1)
378 except socket.error:
379 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
380 self.manifest.manifest_server)
381 sys.exit(1)
382
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700383 rp = self.manifest.repoProject
384 rp.PreSync()
385
386 mp = self.manifest.manifestProject
387 mp.PreSync()
388
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800389 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700390 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800391
Nico Sallembien9bb18162009-12-07 15:38:01 -0800392 if not opt.local_only:
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700393 mp.Sync_NetworkHalf(quiet=opt.quiet)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800394
395 if mp.HasChanges:
396 syncbuf = SyncBuffer(mp.config)
397 mp.Sync_LocalHalf(syncbuf)
398 if not syncbuf.Finish():
399 sys.exit(1)
400 self.manifest._Unload()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700401 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700402
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700403 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700404 to_fetch = []
405 now = time.time()
406 if (24 * 60 * 60) <= (now - rp.LastFetch):
407 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700408 to_fetch.extend(all)
409
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700410 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700411 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700412 if opt.network_only:
413 # bail out now; the rest touches the working tree
414 return
415
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700416 self.manifest._Unload()
417 all = self.GetProjects(args, missing_ok=True)
418 missing = []
419 for project in all:
420 if project.gitdir not in fetched:
421 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700422 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700423
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700424 if self.manifest.IsMirror:
425 # bail out now, we have no working tree
426 return
427
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700428 if self.UpdateProjectList():
429 sys.exit(1)
430
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700431 syncbuf = SyncBuffer(mp.config,
432 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700433 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700434 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700435 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800436 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700437 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700438 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700439 print >>sys.stderr
440 if not syncbuf.Finish():
441 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700442
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700443 # If there's a notice that's supposed to print at the end of the sync, print
444 # it now...
445 if self.manifest.notice:
446 print self.manifest.notice
447
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700448def _PostRepoUpgrade(manifest):
449 for project in manifest.projects.values():
450 if project.Exists:
451 project.PostRepoUpgrade()
452
453def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
454 if rp.HasChanges:
455 print >>sys.stderr, 'info: A new version of repo is available'
456 print >>sys.stderr, ''
457 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700458 syncbuf = SyncBuffer(rp.config)
459 rp.Sync_LocalHalf(syncbuf)
460 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700461 sys.exit(1)
462 print >>sys.stderr, 'info: Restarting repo with latest version'
463 raise RepoChangedException(['--repo-upgraded'])
464 else:
465 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
466 else:
467 if verbose:
468 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
469
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700470def _VerifyTag(project):
471 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
472 if not os.path.exists(gpg_dir):
473 print >>sys.stderr,\
474"""warning: GnuPG was not available during last "repo init"
475warning: Cannot automatically authenticate repo."""
476 return True
477
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700478 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700479 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700480 except GitError:
481 cur = None
482
483 if not cur \
484 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700485 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700486 if rev.startswith(R_HEADS):
487 rev = rev[len(R_HEADS):]
488
489 print >>sys.stderr
490 print >>sys.stderr,\
491 "warning: project '%s' branch '%s' is not signed" \
492 % (project.name, rev)
493 return False
494
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800495 env = os.environ.copy()
496 env['GIT_DIR'] = project.gitdir.encode()
497 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700498
499 cmd = [GIT, 'tag', '-v', cur]
500 proc = subprocess.Popen(cmd,
501 stdout = subprocess.PIPE,
502 stderr = subprocess.PIPE,
503 env = env)
504 out = proc.stdout.read()
505 proc.stdout.close()
506
507 err = proc.stderr.read()
508 proc.stderr.close()
509
510 if proc.wait() != 0:
511 print >>sys.stderr
512 print >>sys.stderr, out
513 print >>sys.stderr, err
514 print >>sys.stderr
515 return False
516 return True