blob: c5955a383d831c750be3de257aaec63d4b9a15aa [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')
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700134 p.add_option('-c','--current-branch',
135 dest='current_branch_only', action='store_true',
136 help='fetch only current branch from server')
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700137 p.add_option('-q','--quiet',
138 dest='quiet', action='store_true',
139 help='be more quiet')
Roy Lee18afd7f2010-05-09 04:32:08 +0800140 p.add_option('-j','--jobs',
141 dest='jobs', action='store', type='int',
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700142 help="projects to fetch simultaneously (default %d)" % self.jobs)
Nico Sallembien6623b212010-05-11 12:57:01 -0700143 if show_smart:
144 p.add_option('-s', '--smart-sync',
145 dest='smart_sync', action='store_true',
146 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200147 p.add_option('-t', '--smart-tag',
148 dest='smart_tag', action='store',
149 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700150
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700151 g = p.add_option_group('repo Version options')
152 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700153 dest='no_repo_verify', action='store_true',
154 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700155 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800156 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700157 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700158
Doug Andersonfc06ced2011-03-16 15:49:18 -0700159 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
160 """Main function of the fetch threads when jobs are > 1.
161
162 Args:
163 opt: Program options returned from optparse. See _Options().
164 project: Project object for the project to fetch.
165 lock: Lock for accessing objects that are shared amongst multiple
166 _FetchHelper() threads.
167 fetched: set object that we will add project.gitdir to when we're done
168 (with our lock held).
169 pm: Instance of a Project object. We will call pm.update() (with our
170 lock held).
171 sem: We'll release() this semaphore when we exit so that another thread
172 can be started up.
173 err_event: We'll set this event in the case of an error (after printing
174 out info about the error).
175 """
176 # We'll set to true once we've locked the lock.
177 did_lock = False
178
179 # Encapsulate everything in a try/except/finally so that:
180 # - We always set err_event in the case of an exception.
181 # - We always make sure we call sem.release().
182 # - We always make sure we unlock the lock if we locked it.
183 try:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700184 try:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700185 success = project.Sync_NetworkHalf(quiet=opt.quiet,
186 current_branch_only=opt.current_branch_only)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700187
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700188 # Lock around all the rest of the code, since printing, updating a set
189 # and Progress.update() are not thread safe.
190 lock.acquire()
191 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700192
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700193 if not success:
194 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
195 if opt.force_broken:
196 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
197 else:
198 raise _FetchError()
Roy Lee18afd7f2010-05-09 04:32:08 +0800199
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700200 fetched.add(project.gitdir)
201 pm.update()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700202 except _FetchError:
203 err_event.set()
204 except:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700205 err_event.set()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700206 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()
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700219 if project.Sync_NetworkHalf(quiet=opt.quiet,
220 current_branch_only=opt.current_branch_only):
Roy Lee18afd7f2010-05-09 04:32:08 +0800221 fetched.add(project.gitdir)
222 else:
223 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500224 if opt.force_broken:
225 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
226 else:
227 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800228 else:
229 threads = set()
230 lock = _threading.Lock()
231 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700232 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800233 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700234 # Check for any errors before starting any new threads.
235 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400236 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700237 break
238
Roy Lee18afd7f2010-05-09 04:32:08 +0800239 sem.acquire()
240 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700241 args = (opt,
242 project,
243 lock,
244 fetched,
245 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700246 sem,
247 err_event))
Roy Lee18afd7f2010-05-09 04:32:08 +0800248 threads.add(t)
249 t.start()
250
251 for t in threads:
252 t.join()
253
Doug Andersonfc06ced2011-03-16 15:49:18 -0700254 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400255 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700256 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
257 sys.exit(1)
258
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700259 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700260 for project in projects:
261 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700262 return fetched
263
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700264 def UpdateProjectList(self):
265 new_project_paths = []
266 for project in self.manifest.projects.values():
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700267 if project.relpath:
268 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700269 file_name = 'project.list'
270 file_path = os.path.join(self.manifest.repodir, file_name)
271 old_project_paths = []
272
273 if os.path.exists(file_path):
274 fd = open(file_path, 'r')
275 try:
276 old_project_paths = fd.read().split('\n')
277 finally:
278 fd.close()
279 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700280 if not path:
281 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700282 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400283 """If the path has already been deleted, we don't need to do it
284 """
285 if os.path.exists(self.manifest.topdir + '/' + path):
286 project = Project(
287 manifest = self.manifest,
288 name = path,
289 remote = RemoteSpec('origin'),
290 gitdir = os.path.join(self.manifest.topdir,
291 path, '.git'),
292 worktree = os.path.join(self.manifest.topdir, path),
293 relpath = path,
294 revisionExpr = 'HEAD',
295 revisionId = None)
296
297 if project.IsDirty():
298 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700299uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400300 print >>sys.stderr, ' commit changes, then run sync again'
301 return -1
302 else:
303 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
304 shutil.rmtree(project.worktree)
305 # Try deleting parent subdirs if they are empty
306 dir = os.path.dirname(project.worktree)
307 while dir != self.manifest.topdir:
308 try:
309 os.rmdir(dir)
310 except OSError:
311 break
312 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700313
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700314 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700315 fd = open(file_path, 'w')
316 try:
317 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700318 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700319 finally:
320 fd.close()
321 return 0
322
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700323 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800324 if opt.jobs:
325 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700326 if self.jobs > 1:
327 soft_limit, _ = _rlimit_nofile()
328 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
329
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700330 if opt.network_only and opt.detach_head:
331 print >>sys.stderr, 'error: cannot combine -n and -d'
332 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700333 if opt.network_only and opt.local_only:
334 print >>sys.stderr, 'error: cannot combine -n and -l'
335 sys.exit(1)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700336
Victor Boivie08c880d2011-04-19 10:32:52 +0200337 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700338 if not self.manifest.manifest_server:
339 print >>sys.stderr, \
340 'error: cannot smart sync: no manifest server defined in manifest'
341 sys.exit(1)
342 try:
343 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200344 if opt.smart_sync:
345 p = self.manifest.manifestProject
346 b = p.GetBranch(p.CurrentBranch)
347 branch = b.merge
348 if branch.startswith(R_HEADS):
349 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700350
Victor Boivie08c880d2011-04-19 10:32:52 +0200351 env = os.environ.copy()
352 if (env.has_key('TARGET_PRODUCT') and
353 env.has_key('TARGET_BUILD_VARIANT')):
354 target = '%s-%s' % (env['TARGET_PRODUCT'],
355 env['TARGET_BUILD_VARIANT'])
356 [success, manifest_str] = server.GetApprovedManifest(branch, target)
357 else:
358 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700359 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200360 assert(opt.smart_tag)
361 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700362
363 if success:
364 manifest_name = "smart_sync_override.xml"
365 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
366 manifest_name)
367 try:
368 f = open(manifest_path, 'w')
369 try:
370 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700371 finally:
372 f.close()
373 except IOError:
374 print >>sys.stderr, 'error: cannot write manifest to %s' % \
375 manifest_path
376 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700377 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700378 else:
379 print >>sys.stderr, 'error: %s' % manifest_str
380 sys.exit(1)
381 except socket.error:
382 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
383 self.manifest.manifest_server)
384 sys.exit(1)
385
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700386 rp = self.manifest.repoProject
387 rp.PreSync()
388
389 mp = self.manifest.manifestProject
390 mp.PreSync()
391
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800392 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700393 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800394
Nico Sallembien9bb18162009-12-07 15:38:01 -0800395 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700396 mp.Sync_NetworkHalf(quiet=opt.quiet,
397 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800398
399 if mp.HasChanges:
400 syncbuf = SyncBuffer(mp.config)
401 mp.Sync_LocalHalf(syncbuf)
402 if not syncbuf.Finish():
403 sys.exit(1)
404 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700405 if opt.jobs is None:
406 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700407 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700408
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700409 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700410 to_fetch = []
411 now = time.time()
412 if (24 * 60 * 60) <= (now - rp.LastFetch):
413 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700414 to_fetch.extend(all)
415
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700416 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700417 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700418 if opt.network_only:
419 # bail out now; the rest touches the working tree
420 return
421
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700422 self.manifest._Unload()
423 all = self.GetProjects(args, missing_ok=True)
424 missing = []
425 for project in all:
426 if project.gitdir not in fetched:
427 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700428 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700429
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700430 if self.manifest.IsMirror:
431 # bail out now, we have no working tree
432 return
433
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700434 if self.UpdateProjectList():
435 sys.exit(1)
436
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700437 syncbuf = SyncBuffer(mp.config,
438 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700439 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700440 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700441 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800442 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700443 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700444 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700445 print >>sys.stderr
446 if not syncbuf.Finish():
447 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700448
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700449 # If there's a notice that's supposed to print at the end of the sync, print
450 # it now...
451 if self.manifest.notice:
452 print self.manifest.notice
453
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700454def _PostRepoUpgrade(manifest):
455 for project in manifest.projects.values():
456 if project.Exists:
457 project.PostRepoUpgrade()
458
459def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
460 if rp.HasChanges:
461 print >>sys.stderr, 'info: A new version of repo is available'
462 print >>sys.stderr, ''
463 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700464 syncbuf = SyncBuffer(rp.config)
465 rp.Sync_LocalHalf(syncbuf)
466 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700467 sys.exit(1)
468 print >>sys.stderr, 'info: Restarting repo with latest version'
469 raise RepoChangedException(['--repo-upgraded'])
470 else:
471 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
472 else:
473 if verbose:
474 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
475
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700476def _VerifyTag(project):
477 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
478 if not os.path.exists(gpg_dir):
479 print >>sys.stderr,\
480"""warning: GnuPG was not available during last "repo init"
481warning: Cannot automatically authenticate repo."""
482 return True
483
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700484 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700485 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700486 except GitError:
487 cur = None
488
489 if not cur \
490 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700491 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700492 if rev.startswith(R_HEADS):
493 rev = rev[len(R_HEADS):]
494
495 print >>sys.stderr
496 print >>sys.stderr,\
497 "warning: project '%s' branch '%s' is not signed" \
498 % (project.name, rev)
499 return False
500
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800501 env = os.environ.copy()
502 env['GIT_DIR'] = project.gitdir.encode()
503 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700504
505 cmd = [GIT, 'tag', '-v', cur]
506 proc = subprocess.Popen(cmd,
507 stdout = subprocess.PIPE,
508 stderr = subprocess.PIPE,
509 env = env)
510 out = proc.stdout.read()
511 proc.stdout.close()
512
513 err = proc.stderr.read()
514 proc.stderr.close()
515
516 if proc.wait() != 0:
517 print >>sys.stderr
518 print >>sys.stderr, out
519 print >>sys.stderr, err
520 print >>sys.stderr
521 return False
522 return True