blob: 6dcce82e5d824bc03e87abe407e0f47b6efa48a7 [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)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500143 p.add_option('-m', '--manifest-name',
144 dest='manifest_name',
145 help='temporary manifest to use for this sync', metavar='NAME.xml')
Nico Sallembien6623b212010-05-11 12:57:01 -0700146 if show_smart:
147 p.add_option('-s', '--smart-sync',
148 dest='smart_sync', action='store_true',
149 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200150 p.add_option('-t', '--smart-tag',
151 dest='smart_tag', action='store',
152 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700153
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700154 g = p.add_option_group('repo Version options')
155 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700156 dest='no_repo_verify', action='store_true',
157 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700158 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800159 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700160 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700161
Doug Andersonfc06ced2011-03-16 15:49:18 -0700162 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
163 """Main function of the fetch threads when jobs are > 1.
Roy Lee18afd7f2010-05-09 04:32:08 +0800164
Doug Andersonfc06ced2011-03-16 15:49:18 -0700165 Args:
166 opt: Program options returned from optparse. See _Options().
167 project: Project object for the project to fetch.
168 lock: Lock for accessing objects that are shared amongst multiple
169 _FetchHelper() threads.
170 fetched: set object that we will add project.gitdir to when we're done
171 (with our lock held).
172 pm: Instance of a Project object. We will call pm.update() (with our
173 lock held).
174 sem: We'll release() this semaphore when we exit so that another thread
175 can be started up.
176 err_event: We'll set this event in the case of an error (after printing
177 out info about the error).
178 """
179 # We'll set to true once we've locked the lock.
180 did_lock = False
181
182 # Encapsulate everything in a try/except/finally so that:
183 # - We always set err_event in the case of an exception.
184 # - We always make sure we call sem.release().
185 # - We always make sure we unlock the lock if we locked it.
186 try:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700187 try:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700188 success = project.Sync_NetworkHalf(quiet=opt.quiet,
189 current_branch_only=opt.current_branch_only)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700190
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700191 # Lock around all the rest of the code, since printing, updating a set
192 # and Progress.update() are not thread safe.
193 lock.acquire()
194 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700195
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700196 if not success:
197 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
198 if opt.force_broken:
199 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
200 else:
201 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700202
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700203 fetched.add(project.gitdir)
204 pm.update()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700205 except _FetchError:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700206 err_event.set()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700207 except:
208 err_event.set()
209 raise
Doug Andersonfc06ced2011-03-16 15:49:18 -0700210 finally:
211 if did_lock:
212 lock.release()
213 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800214
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700215 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700216 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700217 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800218
219 if self.jobs == 1:
220 for project in projects:
221 pm.update()
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700222 if project.Sync_NetworkHalf(quiet=opt.quiet,
223 current_branch_only=opt.current_branch_only):
Roy Lee18afd7f2010-05-09 04:32:08 +0800224 fetched.add(project.gitdir)
225 else:
226 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500227 if opt.force_broken:
228 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
229 else:
230 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800231 else:
232 threads = set()
233 lock = _threading.Lock()
234 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700235 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800236 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700237 # Check for any errors before starting any new threads.
238 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400239 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700240 break
241
Roy Lee18afd7f2010-05-09 04:32:08 +0800242 sem.acquire()
243 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700244 args = (opt,
245 project,
246 lock,
247 fetched,
248 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700249 sem,
250 err_event))
Roy Lee18afd7f2010-05-09 04:32:08 +0800251 threads.add(t)
252 t.start()
253
254 for t in threads:
255 t.join()
256
Doug Andersonfc06ced2011-03-16 15:49:18 -0700257 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400258 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700259 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
260 sys.exit(1)
261
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700262 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700263 for project in projects:
264 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700265 return fetched
266
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700267 def UpdateProjectList(self):
268 new_project_paths = []
269 for project in self.manifest.projects.values():
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700270 if project.relpath:
271 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700272 file_name = 'project.list'
273 file_path = os.path.join(self.manifest.repodir, file_name)
274 old_project_paths = []
275
276 if os.path.exists(file_path):
277 fd = open(file_path, 'r')
278 try:
279 old_project_paths = fd.read().split('\n')
280 finally:
281 fd.close()
282 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700283 if not path:
284 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700285 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400286 """If the path has already been deleted, we don't need to do it
287 """
288 if os.path.exists(self.manifest.topdir + '/' + path):
289 project = Project(
290 manifest = self.manifest,
291 name = path,
292 remote = RemoteSpec('origin'),
293 gitdir = os.path.join(self.manifest.topdir,
294 path, '.git'),
295 worktree = os.path.join(self.manifest.topdir, path),
296 relpath = path,
297 revisionExpr = 'HEAD',
298 revisionId = None)
299
300 if project.IsDirty():
301 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700302uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400303 print >>sys.stderr, ' commit changes, then run sync again'
304 return -1
305 else:
306 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
307 shutil.rmtree(project.worktree)
308 # Try deleting parent subdirs if they are empty
309 dir = os.path.dirname(project.worktree)
310 while dir != self.manifest.topdir:
311 try:
312 os.rmdir(dir)
313 except OSError:
314 break
315 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700316
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700317 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700318 fd = open(file_path, 'w')
319 try:
320 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700321 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700322 finally:
323 fd.close()
324 return 0
325
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700326 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800327 if opt.jobs:
328 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700329 if self.jobs > 1:
330 soft_limit, _ = _rlimit_nofile()
331 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
332
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700333 if opt.network_only and opt.detach_head:
334 print >>sys.stderr, 'error: cannot combine -n and -d'
335 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700336 if opt.network_only and opt.local_only:
337 print >>sys.stderr, 'error: cannot combine -n and -l'
338 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500339 if opt.manifest_name and opt.smart_sync:
340 print >>sys.stderr, 'error: cannot combine -m and -s'
341 sys.exit(1)
342 if opt.manifest_name and opt.smart_tag:
343 print >>sys.stderr, 'error: cannot combine -m and -t'
344 sys.exit(1)
345
346 if opt.manifest_name:
347 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700348
Victor Boivie08c880d2011-04-19 10:32:52 +0200349 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700350 if not self.manifest.manifest_server:
351 print >>sys.stderr, \
352 'error: cannot smart sync: no manifest server defined in manifest'
353 sys.exit(1)
354 try:
355 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200356 if opt.smart_sync:
357 p = self.manifest.manifestProject
358 b = p.GetBranch(p.CurrentBranch)
359 branch = b.merge
360 if branch.startswith(R_HEADS):
361 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700362
Victor Boivie08c880d2011-04-19 10:32:52 +0200363 env = os.environ.copy()
364 if (env.has_key('TARGET_PRODUCT') and
365 env.has_key('TARGET_BUILD_VARIANT')):
366 target = '%s-%s' % (env['TARGET_PRODUCT'],
367 env['TARGET_BUILD_VARIANT'])
368 [success, manifest_str] = server.GetApprovedManifest(branch, target)
369 else:
370 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700371 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200372 assert(opt.smart_tag)
373 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700374
375 if success:
376 manifest_name = "smart_sync_override.xml"
377 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
378 manifest_name)
379 try:
380 f = open(manifest_path, 'w')
381 try:
382 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700383 finally:
384 f.close()
385 except IOError:
386 print >>sys.stderr, 'error: cannot write manifest to %s' % \
387 manifest_path
388 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700389 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700390 else:
391 print >>sys.stderr, 'error: %s' % manifest_str
392 sys.exit(1)
393 except socket.error:
394 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
395 self.manifest.manifest_server)
396 sys.exit(1)
397
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700398 rp = self.manifest.repoProject
399 rp.PreSync()
400
401 mp = self.manifest.manifestProject
402 mp.PreSync()
403
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800404 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700405 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800406
Nico Sallembien9bb18162009-12-07 15:38:01 -0800407 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700408 mp.Sync_NetworkHalf(quiet=opt.quiet,
409 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800410
411 if mp.HasChanges:
412 syncbuf = SyncBuffer(mp.config)
413 mp.Sync_LocalHalf(syncbuf)
414 if not syncbuf.Finish():
415 sys.exit(1)
416 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700417 if opt.jobs is None:
418 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700419 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700420
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700421 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700422 to_fetch = []
423 now = time.time()
424 if (24 * 60 * 60) <= (now - rp.LastFetch):
425 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700426 to_fetch.extend(all)
427
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700428 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700429 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700430 if opt.network_only:
431 # bail out now; the rest touches the working tree
432 return
433
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700434 self.manifest._Unload()
435 all = self.GetProjects(args, missing_ok=True)
436 missing = []
437 for project in all:
438 if project.gitdir not in fetched:
439 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700440 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700441
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700442 if self.manifest.IsMirror:
443 # bail out now, we have no working tree
444 return
445
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700446 if self.UpdateProjectList():
447 sys.exit(1)
448
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700449 syncbuf = SyncBuffer(mp.config,
450 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700451 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700452 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700453 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800454 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700455 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700456 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700457 print >>sys.stderr
458 if not syncbuf.Finish():
459 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700460
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700461 # If there's a notice that's supposed to print at the end of the sync, print
462 # it now...
463 if self.manifest.notice:
464 print self.manifest.notice
465
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700466def _PostRepoUpgrade(manifest):
467 for project in manifest.projects.values():
468 if project.Exists:
469 project.PostRepoUpgrade()
470
471def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
472 if rp.HasChanges:
473 print >>sys.stderr, 'info: A new version of repo is available'
474 print >>sys.stderr, ''
475 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700476 syncbuf = SyncBuffer(rp.config)
477 rp.Sync_LocalHalf(syncbuf)
478 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700479 sys.exit(1)
480 print >>sys.stderr, 'info: Restarting repo with latest version'
481 raise RepoChangedException(['--repo-upgraded'])
482 else:
483 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
484 else:
485 if verbose:
486 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
487
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700488def _VerifyTag(project):
489 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
490 if not os.path.exists(gpg_dir):
491 print >>sys.stderr,\
492"""warning: GnuPG was not available during last "repo init"
493warning: Cannot automatically authenticate repo."""
494 return True
495
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700496 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700497 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700498 except GitError:
499 cur = None
500
501 if not cur \
502 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700503 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700504 if rev.startswith(R_HEADS):
505 rev = rev[len(R_HEADS):]
506
507 print >>sys.stderr
508 print >>sys.stderr,\
509 "warning: project '%s' branch '%s' is not signed" \
510 % (project.name, rev)
511 return False
512
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800513 env = os.environ.copy()
514 env['GIT_DIR'] = project.gitdir.encode()
515 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700516
517 cmd = [GIT, 'tag', '-v', cur]
518 proc = subprocess.Popen(cmd,
519 stdout = subprocess.PIPE,
520 stderr = subprocess.PIPE,
521 env = env)
522 out = proc.stdout.read()
523 proc.stdout.close()
524
525 err = proc.stderr.read()
526 proc.stderr.close()
527
528 if proc.wait() != 0:
529 print >>sys.stderr
530 print >>sys.stderr, out
531 print >>sys.stderr, err
532 print >>sys.stderr
533 return False
534 return True