blob: a3d0692278d2d9a51066aaf6d52831a2bd578e0a [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()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700198 except _FetchError:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700199 err_event.set()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700200 except:
201 err_event.set()
202 raise
Doug Andersonfc06ced2011-03-16 15:49:18 -0700203 finally:
204 if did_lock:
205 lock.release()
206 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800207
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700208 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700209 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700210 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800211
212 if self.jobs == 1:
213 for project in projects:
214 pm.update()
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700215 if project.Sync_NetworkHalf(quiet=opt.quiet):
Roy Lee18afd7f2010-05-09 04:32:08 +0800216 fetched.add(project.gitdir)
217 else:
218 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500219 if opt.force_broken:
220 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
221 else:
222 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800223 else:
224 threads = set()
225 lock = _threading.Lock()
226 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700227 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800228 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700229 # Check for any errors before starting any new threads.
230 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400231 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700232 break
233
Roy Lee18afd7f2010-05-09 04:32:08 +0800234 sem.acquire()
235 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700236 args = (opt,
237 project,
238 lock,
239 fetched,
240 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700241 sem,
242 err_event))
Roy Lee18afd7f2010-05-09 04:32:08 +0800243 threads.add(t)
244 t.start()
245
246 for t in threads:
247 t.join()
248
Doug Andersonfc06ced2011-03-16 15:49:18 -0700249 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400250 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700251 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
252 sys.exit(1)
253
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700254 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700255 for project in projects:
256 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700257 return fetched
258
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700259 def UpdateProjectList(self):
260 new_project_paths = []
261 for project in self.manifest.projects.values():
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700262 if project.relpath:
263 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700264 file_name = 'project.list'
265 file_path = os.path.join(self.manifest.repodir, file_name)
266 old_project_paths = []
267
268 if os.path.exists(file_path):
269 fd = open(file_path, 'r')
270 try:
271 old_project_paths = fd.read().split('\n')
272 finally:
273 fd.close()
274 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700275 if not path:
276 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700277 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400278 """If the path has already been deleted, we don't need to do it
279 """
280 if os.path.exists(self.manifest.topdir + '/' + path):
281 project = Project(
282 manifest = self.manifest,
283 name = path,
284 remote = RemoteSpec('origin'),
285 gitdir = os.path.join(self.manifest.topdir,
286 path, '.git'),
287 worktree = os.path.join(self.manifest.topdir, path),
288 relpath = path,
289 revisionExpr = 'HEAD',
290 revisionId = None)
291
292 if project.IsDirty():
293 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700294uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400295 print >>sys.stderr, ' commit changes, then run sync again'
296 return -1
297 else:
298 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
299 shutil.rmtree(project.worktree)
300 # Try deleting parent subdirs if they are empty
301 dir = os.path.dirname(project.worktree)
302 while dir != self.manifest.topdir:
303 try:
304 os.rmdir(dir)
305 except OSError:
306 break
307 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700308
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700309 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700310 fd = open(file_path, 'w')
311 try:
312 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700313 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700314 finally:
315 fd.close()
316 return 0
317
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700318 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800319 if opt.jobs:
320 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700321 if self.jobs > 1:
322 soft_limit, _ = _rlimit_nofile()
323 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
324
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700325 if opt.network_only and opt.detach_head:
326 print >>sys.stderr, 'error: cannot combine -n and -d'
327 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700328 if opt.network_only and opt.local_only:
329 print >>sys.stderr, 'error: cannot combine -n and -l'
330 sys.exit(1)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700331
Victor Boivie08c880d2011-04-19 10:32:52 +0200332 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700333 if not self.manifest.manifest_server:
334 print >>sys.stderr, \
335 'error: cannot smart sync: no manifest server defined in manifest'
336 sys.exit(1)
337 try:
338 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200339 if opt.smart_sync:
340 p = self.manifest.manifestProject
341 b = p.GetBranch(p.CurrentBranch)
342 branch = b.merge
343 if branch.startswith(R_HEADS):
344 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700345
Victor Boivie08c880d2011-04-19 10:32:52 +0200346 env = os.environ.copy()
347 if (env.has_key('TARGET_PRODUCT') and
348 env.has_key('TARGET_BUILD_VARIANT')):
349 target = '%s-%s' % (env['TARGET_PRODUCT'],
350 env['TARGET_BUILD_VARIANT'])
351 [success, manifest_str] = server.GetApprovedManifest(branch, target)
352 else:
353 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700354 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200355 assert(opt.smart_tag)
356 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700357
358 if success:
359 manifest_name = "smart_sync_override.xml"
360 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
361 manifest_name)
362 try:
363 f = open(manifest_path, 'w')
364 try:
365 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700366 finally:
367 f.close()
368 except IOError:
369 print >>sys.stderr, 'error: cannot write manifest to %s' % \
370 manifest_path
371 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700372 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700373 else:
374 print >>sys.stderr, 'error: %s' % manifest_str
375 sys.exit(1)
376 except socket.error:
377 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
378 self.manifest.manifest_server)
379 sys.exit(1)
380
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700381 rp = self.manifest.repoProject
382 rp.PreSync()
383
384 mp = self.manifest.manifestProject
385 mp.PreSync()
386
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800387 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700388 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800389
Nico Sallembien9bb18162009-12-07 15:38:01 -0800390 if not opt.local_only:
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700391 mp.Sync_NetworkHalf(quiet=opt.quiet)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800392
393 if mp.HasChanges:
394 syncbuf = SyncBuffer(mp.config)
395 mp.Sync_LocalHalf(syncbuf)
396 if not syncbuf.Finish():
397 sys.exit(1)
398 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700399 if opt.jobs is None:
400 self.jobs = self.manifest.default.sync_j
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