blob: 4689ac8b001f481f5cb2e1c974644200190fed3e [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
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070031from git_command import GIT
Nico Sallembien5732e472010-04-26 11:17:29 -070032from git_refs import R_HEADS
Shawn O. Pearcee756c412009-04-13 11:51:15 -070033from project import HEAD
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070034from project import Project
35from project import RemoteSpec
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080036from command import Command, MirrorSafeCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070037from error import RepoChangedException, GitError
38from project import R_HEADS
Shawn O. Pearce350cde42009-04-16 11:21:18 -070039from project import SyncBuffer
Shawn O. Pearce68194f42009-04-10 16:48:52 -070040from progress import Progress
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070041
Doug Andersonfc06ced2011-03-16 15:49:18 -070042class _FetchError(Exception):
43 """Internal error thrown in _FetchHelper() when we don't want stack trace."""
44 pass
45
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080046class Sync(Command, MirrorSafeCommand):
Roy Lee18afd7f2010-05-09 04:32:08 +080047 jobs = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070048 common = True
49 helpSummary = "Update working tree to the latest revision"
50 helpUsage = """
51%prog [<project>...]
52"""
53 helpDescription = """
54The '%prog' command synchronizes local project directories
55with the remote repositories specified in the manifest. If a local
56project does not yet exist, it will clone a new local directory from
57the remote repository and set up tracking branches as specified in
58the manifest. If the local project already exists, '%prog'
59will update the remote branches and rebase any new local changes
60on top of the new remote changes.
61
62'%prog' will synchronize all projects listed at the command
63line. Projects can be specified either by name, or by a relative
64or absolute path to the project's local directory. If no projects
65are specified, '%prog' will synchronize all projects listed in
66the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070067
68The -d/--detach option can be used to switch specified projects
69back to the manifest revision. This option is especially helpful
70if the project is currently on a topic branch, but the manifest
71revision is temporarily needed.
Shawn O. Pearceeb7af872009-04-21 08:02:04 -070072
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070073The -s/--smart-sync option can be used to sync to a known good
74build as specified by the manifest-server element in the current
Victor Boivie08c880d2011-04-19 10:32:52 +020075manifest. The -t/--smart-tag option is similar and allows you to
76specify a custom tag/label.
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070077
Andrei Warkentin5df6de02010-07-02 17:58:31 -050078The -f/--force-broken option can be used to proceed with syncing
79other projects if a project sync fails.
80
Shawn O. Pearceeb7af872009-04-21 08:02:04 -070081SSH Connections
82---------------
83
84If at least one project remote URL uses an SSH connection (ssh://,
85git+ssh://, or user@host:path syntax) repo will automatically
86enable the SSH ControlMaster option when connecting to that host.
87This feature permits other projects in the same '%prog' session to
88reuse the same SSH tunnel, saving connection setup overheads.
89
90To disable this behavior on UNIX platforms, set the GIT_SSH
91environment variable to 'ssh'. For example:
92
93 export GIT_SSH=ssh
94 %prog
95
96Compatibility
97~~~~~~~~~~~~~
98
99This feature is automatically disabled on Windows, due to the lack
100of UNIX domain socket support.
101
102This feature is not compatible with url.insteadof rewrites in the
103user's ~/.gitconfig. '%prog' is currently not able to perform the
104rewrite early enough to establish the ControlMaster tunnel.
105
106If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or
107later is required to fix a server side protocol bug.
108
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700109"""
110
Nico Sallembien6623b212010-05-11 12:57:01 -0700111 def _Options(self, p, show_smart=True):
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500112 p.add_option('-f', '--force-broken',
113 dest='force_broken', action='store_true',
114 help="continue sync even if a project fails to sync")
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700115 p.add_option('-l','--local-only',
116 dest='local_only', action='store_true',
117 help="only update working tree, don't fetch")
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700118 p.add_option('-n','--network-only',
119 dest='network_only', action='store_true',
120 help="fetch only, don't update working tree")
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700121 p.add_option('-d','--detach',
122 dest='detach_head', action='store_true',
123 help='detach projects back to manifest revision')
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700124 p.add_option('-q','--quiet',
125 dest='quiet', action='store_true',
126 help='be more quiet')
Roy Lee18afd7f2010-05-09 04:32:08 +0800127 p.add_option('-j','--jobs',
128 dest='jobs', action='store', type='int',
129 help="number of projects to fetch simultaneously")
Nico Sallembien6623b212010-05-11 12:57:01 -0700130 if show_smart:
131 p.add_option('-s', '--smart-sync',
132 dest='smart_sync', action='store_true',
133 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200134 p.add_option('-t', '--smart-tag',
135 dest='smart_tag', action='store',
136 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700137
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700138 g = p.add_option_group('repo Version options')
139 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700140 dest='no_repo_verify', action='store_true',
141 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700142 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800143 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700144 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700145
Doug Andersonfc06ced2011-03-16 15:49:18 -0700146 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
147 """Main function of the fetch threads when jobs are > 1.
Roy Lee18afd7f2010-05-09 04:32:08 +0800148
Doug Andersonfc06ced2011-03-16 15:49:18 -0700149 Args:
150 opt: Program options returned from optparse. See _Options().
151 project: Project object for the project to fetch.
152 lock: Lock for accessing objects that are shared amongst multiple
153 _FetchHelper() threads.
154 fetched: set object that we will add project.gitdir to when we're done
155 (with our lock held).
156 pm: Instance of a Project object. We will call pm.update() (with our
157 lock held).
158 sem: We'll release() this semaphore when we exit so that another thread
159 can be started up.
160 err_event: We'll set this event in the case of an error (after printing
161 out info about the error).
162 """
163 # We'll set to true once we've locked the lock.
164 did_lock = False
165
166 # Encapsulate everything in a try/except/finally so that:
167 # - We always set err_event in the case of an exception.
168 # - We always make sure we call sem.release().
169 # - We always make sure we unlock the lock if we locked it.
170 try:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700171 try:
172 success = project.Sync_NetworkHalf(quiet=opt.quiet)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700173
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700174 # Lock around all the rest of the code, since printing, updating a set
175 # and Progress.update() are not thread safe.
176 lock.acquire()
177 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700178
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700179 if not success:
180 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
181 if opt.force_broken:
182 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
183 else:
184 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700185
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700186 fetched.add(project.gitdir)
187 pm.update()
188 except BaseException, e:
189 # Notify the _Fetch() function about all errors.
190 err_event.set()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700191
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700192 # If we got our own _FetchError, we don't want a stack trace.
193 # However, if we got something else (something in Sync_NetworkHalf?),
194 # we'd like one (so re-raise after we've set err_event).
195 if not isinstance(e, _FetchError):
196 raise
Doug Andersonfc06ced2011-03-16 15:49:18 -0700197 finally:
198 if did_lock:
199 lock.release()
200 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800201
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700202 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700203 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700204 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800205
206 if self.jobs == 1:
207 for project in projects:
208 pm.update()
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700209 if project.Sync_NetworkHalf(quiet=opt.quiet):
Roy Lee18afd7f2010-05-09 04:32:08 +0800210 fetched.add(project.gitdir)
211 else:
212 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500213 if opt.force_broken:
214 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
215 else:
216 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800217 else:
218 threads = set()
219 lock = _threading.Lock()
220 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700221 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800222 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700223 # Check for any errors before starting any new threads.
224 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400225 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700226 break
227
Roy Lee18afd7f2010-05-09 04:32:08 +0800228 sem.acquire()
229 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700230 args = (opt,
231 project,
232 lock,
233 fetched,
234 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700235 sem,
236 err_event))
Roy Lee18afd7f2010-05-09 04:32:08 +0800237 threads.add(t)
238 t.start()
239
240 for t in threads:
241 t.join()
242
Doug Andersonfc06ced2011-03-16 15:49:18 -0700243 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400244 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700245 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
246 sys.exit(1)
247
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700248 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700249 for project in projects:
250 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700251 return fetched
252
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700253 def UpdateProjectList(self):
254 new_project_paths = []
255 for project in self.manifest.projects.values():
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700256 if project.relpath:
257 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700258 file_name = 'project.list'
259 file_path = os.path.join(self.manifest.repodir, file_name)
260 old_project_paths = []
261
262 if os.path.exists(file_path):
263 fd = open(file_path, 'r')
264 try:
265 old_project_paths = fd.read().split('\n')
266 finally:
267 fd.close()
268 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700269 if not path:
270 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700271 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400272 """If the path has already been deleted, we don't need to do it
273 """
274 if os.path.exists(self.manifest.topdir + '/' + path):
275 project = Project(
276 manifest = self.manifest,
277 name = path,
278 remote = RemoteSpec('origin'),
279 gitdir = os.path.join(self.manifest.topdir,
280 path, '.git'),
281 worktree = os.path.join(self.manifest.topdir, path),
282 relpath = path,
283 revisionExpr = 'HEAD',
284 revisionId = None)
285
286 if project.IsDirty():
287 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700288uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400289 print >>sys.stderr, ' commit changes, then run sync again'
290 return -1
291 else:
292 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
293 shutil.rmtree(project.worktree)
294 # Try deleting parent subdirs if they are empty
295 dir = os.path.dirname(project.worktree)
296 while dir != self.manifest.topdir:
297 try:
298 os.rmdir(dir)
299 except OSError:
300 break
301 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700302
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700303 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700304 fd = open(file_path, 'w')
305 try:
306 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700307 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700308 finally:
309 fd.close()
310 return 0
311
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700312 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800313 if opt.jobs:
314 self.jobs = opt.jobs
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700315 if opt.network_only and opt.detach_head:
316 print >>sys.stderr, 'error: cannot combine -n and -d'
317 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700318 if opt.network_only and opt.local_only:
319 print >>sys.stderr, 'error: cannot combine -n and -l'
320 sys.exit(1)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700321
Victor Boivie08c880d2011-04-19 10:32:52 +0200322 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700323 if not self.manifest.manifest_server:
324 print >>sys.stderr, \
325 'error: cannot smart sync: no manifest server defined in manifest'
326 sys.exit(1)
327 try:
328 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200329 if opt.smart_sync:
330 p = self.manifest.manifestProject
331 b = p.GetBranch(p.CurrentBranch)
332 branch = b.merge
333 if branch.startswith(R_HEADS):
334 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700335
Victor Boivie08c880d2011-04-19 10:32:52 +0200336 env = os.environ.copy()
337 if (env.has_key('TARGET_PRODUCT') and
338 env.has_key('TARGET_BUILD_VARIANT')):
339 target = '%s-%s' % (env['TARGET_PRODUCT'],
340 env['TARGET_BUILD_VARIANT'])
341 [success, manifest_str] = server.GetApprovedManifest(branch, target)
342 else:
343 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700344 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200345 assert(opt.smart_tag)
346 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700347
348 if success:
349 manifest_name = "smart_sync_override.xml"
350 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
351 manifest_name)
352 try:
353 f = open(manifest_path, 'w')
354 try:
355 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700356 finally:
357 f.close()
358 except IOError:
359 print >>sys.stderr, 'error: cannot write manifest to %s' % \
360 manifest_path
361 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700362 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700363 else:
364 print >>sys.stderr, 'error: %s' % manifest_str
365 sys.exit(1)
366 except socket.error:
367 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
368 self.manifest.manifest_server)
369 sys.exit(1)
370
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700371 rp = self.manifest.repoProject
372 rp.PreSync()
373
374 mp = self.manifest.manifestProject
375 mp.PreSync()
376
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800377 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700378 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800379
Nico Sallembien9bb18162009-12-07 15:38:01 -0800380 if not opt.local_only:
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700381 mp.Sync_NetworkHalf(quiet=opt.quiet)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800382
383 if mp.HasChanges:
384 syncbuf = SyncBuffer(mp.config)
385 mp.Sync_LocalHalf(syncbuf)
386 if not syncbuf.Finish():
387 sys.exit(1)
388 self.manifest._Unload()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700389 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700390
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700391 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700392 to_fetch = []
393 now = time.time()
394 if (24 * 60 * 60) <= (now - rp.LastFetch):
395 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700396 to_fetch.extend(all)
397
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700398 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700399 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700400 if opt.network_only:
401 # bail out now; the rest touches the working tree
402 return
403
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700404 self.manifest._Unload()
405 all = self.GetProjects(args, missing_ok=True)
406 missing = []
407 for project in all:
408 if project.gitdir not in fetched:
409 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700410 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700411
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700412 if self.manifest.IsMirror:
413 # bail out now, we have no working tree
414 return
415
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700416 if self.UpdateProjectList():
417 sys.exit(1)
418
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700419 syncbuf = SyncBuffer(mp.config,
420 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700421 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700422 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700423 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800424 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700425 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700426 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700427 print >>sys.stderr
428 if not syncbuf.Finish():
429 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700430
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700431 # If there's a notice that's supposed to print at the end of the sync, print
432 # it now...
433 if self.manifest.notice:
434 print self.manifest.notice
435
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700436def _PostRepoUpgrade(manifest):
437 for project in manifest.projects.values():
438 if project.Exists:
439 project.PostRepoUpgrade()
440
441def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
442 if rp.HasChanges:
443 print >>sys.stderr, 'info: A new version of repo is available'
444 print >>sys.stderr, ''
445 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700446 syncbuf = SyncBuffer(rp.config)
447 rp.Sync_LocalHalf(syncbuf)
448 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700449 sys.exit(1)
450 print >>sys.stderr, 'info: Restarting repo with latest version'
451 raise RepoChangedException(['--repo-upgraded'])
452 else:
453 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
454 else:
455 if verbose:
456 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
457
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700458def _VerifyTag(project):
459 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
460 if not os.path.exists(gpg_dir):
461 print >>sys.stderr,\
462"""warning: GnuPG was not available during last "repo init"
463warning: Cannot automatically authenticate repo."""
464 return True
465
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700466 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700467 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700468 except GitError:
469 cur = None
470
471 if not cur \
472 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700473 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700474 if rev.startswith(R_HEADS):
475 rev = rev[len(R_HEADS):]
476
477 print >>sys.stderr
478 print >>sys.stderr,\
479 "warning: project '%s' branch '%s' is not signed" \
480 % (project.name, rev)
481 return False
482
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800483 env = os.environ.copy()
484 env['GIT_DIR'] = project.gitdir.encode()
485 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700486
487 cmd = [GIT, 'tag', '-v', cur]
488 proc = subprocess.Popen(cmd,
489 stdout = subprocess.PIPE,
490 stderr = subprocess.PIPE,
491 env = env)
492 out = proc.stdout.read()
493 proc.stdout.close()
494
495 err = proc.stderr.read()
496 proc.stderr.close()
497
498 if proc.wait() != 0:
499 print >>sys.stderr
500 print >>sys.stderr, out
501 print >>sys.stderr, err
502 print >>sys.stderr
503 return False
504 return True