blob: bfe146b6147df5ac7739b1e46fdb707e8c4403bc [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. Pearcee02ac0a2012-03-14 15:36:59 -070089The --no-clone-bundle option disables any attempt to use
90$URL/clone.bundle to bootstrap a new Git repository from a
91resumeable bundle file on a content delivery network. This
92may be necessary if there are problems with the local Python
93HTTP client or proxy configuration, but the Git binary works.
94
Shawn O. Pearceeb7af872009-04-21 08:02:04 -070095SSH Connections
96---------------
97
98If at least one project remote URL uses an SSH connection (ssh://,
99git+ssh://, or user@host:path syntax) repo will automatically
100enable the SSH ControlMaster option when connecting to that host.
101This feature permits other projects in the same '%prog' session to
102reuse the same SSH tunnel, saving connection setup overheads.
103
104To disable this behavior on UNIX platforms, set the GIT_SSH
105environment variable to 'ssh'. For example:
106
107 export GIT_SSH=ssh
108 %prog
109
110Compatibility
111~~~~~~~~~~~~~
112
113This feature is automatically disabled on Windows, due to the lack
114of UNIX domain socket support.
115
116This feature is not compatible with url.insteadof rewrites in the
117user's ~/.gitconfig. '%prog' is currently not able to perform the
118rewrite early enough to establish the ControlMaster tunnel.
119
120If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or
121later is required to fix a server side protocol bug.
122
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700123"""
124
Nico Sallembien6623b212010-05-11 12:57:01 -0700125 def _Options(self, p, show_smart=True):
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700126 self.jobs = self.manifest.default.sync_j
127
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500128 p.add_option('-f', '--force-broken',
129 dest='force_broken', action='store_true',
130 help="continue sync even if a project fails to sync")
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700131 p.add_option('-l','--local-only',
132 dest='local_only', action='store_true',
133 help="only update working tree, don't fetch")
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700134 p.add_option('-n','--network-only',
135 dest='network_only', action='store_true',
136 help="fetch only, don't update working tree")
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700137 p.add_option('-d','--detach',
138 dest='detach_head', action='store_true',
139 help='detach projects back to manifest revision')
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700140 p.add_option('-c','--current-branch',
141 dest='current_branch_only', action='store_true',
142 help='fetch only current branch from server')
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700143 p.add_option('-q','--quiet',
144 dest='quiet', action='store_true',
145 help='be more quiet')
Roy Lee18afd7f2010-05-09 04:32:08 +0800146 p.add_option('-j','--jobs',
147 dest='jobs', action='store', type='int',
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700148 help="projects to fetch simultaneously (default %d)" % self.jobs)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500149 p.add_option('-m', '--manifest-name',
150 dest='manifest_name',
151 help='temporary manifest to use for this sync', metavar='NAME.xml')
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700152 p.add_option('--no-clone-bundle',
153 dest='no_clone_bundle', action='store_true',
154 help='disable use of /clone.bundle on HTTP/HTTPS')
Nico Sallembien6623b212010-05-11 12:57:01 -0700155 if show_smart:
156 p.add_option('-s', '--smart-sync',
157 dest='smart_sync', action='store_true',
158 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200159 p.add_option('-t', '--smart-tag',
160 dest='smart_tag', action='store',
161 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700162
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700163 g = p.add_option_group('repo Version options')
164 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700165 dest='no_repo_verify', action='store_true',
166 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700167 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800168 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700169 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700170
Doug Andersonfc06ced2011-03-16 15:49:18 -0700171 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
172 """Main function of the fetch threads when jobs are > 1.
Roy Lee18afd7f2010-05-09 04:32:08 +0800173
Doug Andersonfc06ced2011-03-16 15:49:18 -0700174 Args:
175 opt: Program options returned from optparse. See _Options().
176 project: Project object for the project to fetch.
177 lock: Lock for accessing objects that are shared amongst multiple
178 _FetchHelper() threads.
179 fetched: set object that we will add project.gitdir to when we're done
180 (with our lock held).
181 pm: Instance of a Project object. We will call pm.update() (with our
182 lock held).
183 sem: We'll release() this semaphore when we exit so that another thread
184 can be started up.
185 err_event: We'll set this event in the case of an error (after printing
186 out info about the error).
187 """
188 # We'll set to true once we've locked the lock.
189 did_lock = False
190
191 # Encapsulate everything in a try/except/finally so that:
192 # - We always set err_event in the case of an exception.
193 # - We always make sure we call sem.release().
194 # - We always make sure we unlock the lock if we locked it.
195 try:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700196 try:
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700197 success = project.Sync_NetworkHalf(
198 quiet=opt.quiet,
199 current_branch_only=opt.current_branch_only,
200 clone_bundle=not opt.no_clone_bundle)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700201
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700202 # Lock around all the rest of the code, since printing, updating a set
203 # and Progress.update() are not thread safe.
204 lock.acquire()
205 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700206
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700207 if not success:
208 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
209 if opt.force_broken:
210 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
211 else:
212 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700213
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700214 fetched.add(project.gitdir)
215 pm.update()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700216 except _FetchError:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700217 err_event.set()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700218 except:
219 err_event.set()
220 raise
Doug Andersonfc06ced2011-03-16 15:49:18 -0700221 finally:
222 if did_lock:
223 lock.release()
224 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800225
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700226 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700227 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700228 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800229
230 if self.jobs == 1:
231 for project in projects:
232 pm.update()
Shawn O. Pearce5d0efdb2012-08-02 12:13:01 -0700233 if project.Sync_NetworkHalf(
234 quiet=opt.quiet,
235 current_branch_only=opt.current_branch_only,
236 clone_bundle=not opt.no_clone_bundle):
Roy Lee18afd7f2010-05-09 04:32:08 +0800237 fetched.add(project.gitdir)
238 else:
239 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500240 if opt.force_broken:
241 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
242 else:
243 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800244 else:
245 threads = set()
246 lock = _threading.Lock()
247 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700248 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800249 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700250 # Check for any errors before starting any new threads.
251 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400252 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700253 break
254
Roy Lee18afd7f2010-05-09 04:32:08 +0800255 sem.acquire()
256 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700257 args = (opt,
258 project,
259 lock,
260 fetched,
261 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700262 sem,
263 err_event))
Roy Lee18afd7f2010-05-09 04:32:08 +0800264 threads.add(t)
265 t.start()
266
267 for t in threads:
268 t.join()
269
Doug Andersonfc06ced2011-03-16 15:49:18 -0700270 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400271 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700272 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
273 sys.exit(1)
274
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700275 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700276 for project in projects:
277 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700278 return fetched
279
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700280 def UpdateProjectList(self):
281 new_project_paths = []
Colin Cross5acde752012-03-28 20:15:45 -0700282 for project in self.GetProjects(None, missing_ok=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700283 if project.relpath:
284 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700285 file_name = 'project.list'
286 file_path = os.path.join(self.manifest.repodir, file_name)
287 old_project_paths = []
288
289 if os.path.exists(file_path):
290 fd = open(file_path, 'r')
291 try:
292 old_project_paths = fd.read().split('\n')
293 finally:
294 fd.close()
295 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700296 if not path:
297 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700298 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400299 """If the path has already been deleted, we don't need to do it
300 """
301 if os.path.exists(self.manifest.topdir + '/' + path):
302 project = Project(
303 manifest = self.manifest,
304 name = path,
305 remote = RemoteSpec('origin'),
306 gitdir = os.path.join(self.manifest.topdir,
307 path, '.git'),
308 worktree = os.path.join(self.manifest.topdir, path),
309 relpath = path,
310 revisionExpr = 'HEAD',
Colin Cross5acde752012-03-28 20:15:45 -0700311 revisionId = None,
312 groups = None)
Anthonyf3fdf822009-09-26 13:38:52 -0400313
314 if project.IsDirty():
315 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700316uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400317 print >>sys.stderr, ' commit changes, then run sync again'
318 return -1
319 else:
320 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
321 shutil.rmtree(project.worktree)
322 # Try deleting parent subdirs if they are empty
323 dir = os.path.dirname(project.worktree)
324 while dir != self.manifest.topdir:
325 try:
326 os.rmdir(dir)
327 except OSError:
328 break
329 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700330
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700331 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700332 fd = open(file_path, 'w')
333 try:
334 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700335 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700336 finally:
337 fd.close()
338 return 0
339
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700340 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800341 if opt.jobs:
342 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700343 if self.jobs > 1:
344 soft_limit, _ = _rlimit_nofile()
345 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
346
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700347 if opt.network_only and opt.detach_head:
348 print >>sys.stderr, 'error: cannot combine -n and -d'
349 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700350 if opt.network_only and opt.local_only:
351 print >>sys.stderr, 'error: cannot combine -n and -l'
352 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500353 if opt.manifest_name and opt.smart_sync:
354 print >>sys.stderr, 'error: cannot combine -m and -s'
355 sys.exit(1)
356 if opt.manifest_name and opt.smart_tag:
357 print >>sys.stderr, 'error: cannot combine -m and -t'
358 sys.exit(1)
359
360 if opt.manifest_name:
361 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700362
Victor Boivie08c880d2011-04-19 10:32:52 +0200363 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700364 if not self.manifest.manifest_server:
365 print >>sys.stderr, \
366 'error: cannot smart sync: no manifest server defined in manifest'
367 sys.exit(1)
368 try:
369 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200370 if opt.smart_sync:
371 p = self.manifest.manifestProject
372 b = p.GetBranch(p.CurrentBranch)
373 branch = b.merge
374 if branch.startswith(R_HEADS):
375 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700376
Victor Boivie08c880d2011-04-19 10:32:52 +0200377 env = os.environ.copy()
378 if (env.has_key('TARGET_PRODUCT') and
379 env.has_key('TARGET_BUILD_VARIANT')):
380 target = '%s-%s' % (env['TARGET_PRODUCT'],
381 env['TARGET_BUILD_VARIANT'])
382 [success, manifest_str] = server.GetApprovedManifest(branch, target)
383 else:
384 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700385 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200386 assert(opt.smart_tag)
387 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700388
389 if success:
390 manifest_name = "smart_sync_override.xml"
391 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
392 manifest_name)
393 try:
394 f = open(manifest_path, 'w')
395 try:
396 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700397 finally:
398 f.close()
399 except IOError:
400 print >>sys.stderr, 'error: cannot write manifest to %s' % \
401 manifest_path
402 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700403 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700404 else:
405 print >>sys.stderr, 'error: %s' % manifest_str
406 sys.exit(1)
407 except socket.error:
408 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
409 self.manifest.manifest_server)
410 sys.exit(1)
411
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700412 rp = self.manifest.repoProject
413 rp.PreSync()
414
415 mp = self.manifest.manifestProject
416 mp.PreSync()
417
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800418 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700419 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800420
Nico Sallembien9bb18162009-12-07 15:38:01 -0800421 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700422 mp.Sync_NetworkHalf(quiet=opt.quiet,
423 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800424
425 if mp.HasChanges:
426 syncbuf = SyncBuffer(mp.config)
427 mp.Sync_LocalHalf(syncbuf)
428 if not syncbuf.Finish():
429 sys.exit(1)
430 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700431 if opt.jobs is None:
432 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700433 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700434
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700435 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700436 to_fetch = []
437 now = time.time()
438 if (24 * 60 * 60) <= (now - rp.LastFetch):
439 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700440 to_fetch.extend(all)
441
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700442 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700443 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700444 if opt.network_only:
445 # bail out now; the rest touches the working tree
446 return
447
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700448 self.manifest._Unload()
449 all = self.GetProjects(args, missing_ok=True)
450 missing = []
451 for project in all:
452 if project.gitdir not in fetched:
453 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700454 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700455
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700456 if self.manifest.IsMirror:
457 # bail out now, we have no working tree
458 return
459
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700460 if self.UpdateProjectList():
461 sys.exit(1)
462
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700463 syncbuf = SyncBuffer(mp.config,
464 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700465 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700466 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700467 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800468 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700469 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700470 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700471 print >>sys.stderr
472 if not syncbuf.Finish():
473 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700474
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700475 # If there's a notice that's supposed to print at the end of the sync, print
476 # it now...
477 if self.manifest.notice:
478 print self.manifest.notice
479
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700480def _PostRepoUpgrade(manifest):
481 for project in manifest.projects.values():
482 if project.Exists:
483 project.PostRepoUpgrade()
484
485def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
486 if rp.HasChanges:
487 print >>sys.stderr, 'info: A new version of repo is available'
488 print >>sys.stderr, ''
489 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700490 syncbuf = SyncBuffer(rp.config)
491 rp.Sync_LocalHalf(syncbuf)
492 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700493 sys.exit(1)
494 print >>sys.stderr, 'info: Restarting repo with latest version'
495 raise RepoChangedException(['--repo-upgraded'])
496 else:
497 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
498 else:
499 if verbose:
500 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
501
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700502def _VerifyTag(project):
503 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
504 if not os.path.exists(gpg_dir):
505 print >>sys.stderr,\
506"""warning: GnuPG was not available during last "repo init"
507warning: Cannot automatically authenticate repo."""
508 return True
509
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700510 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700511 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700512 except GitError:
513 cur = None
514
515 if not cur \
516 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700517 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700518 if rev.startswith(R_HEADS):
519 rev = rev[len(R_HEADS):]
520
521 print >>sys.stderr
522 print >>sys.stderr,\
523 "warning: project '%s' branch '%s' is not signed" \
524 % (project.name, rev)
525 return False
526
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800527 env = os.environ.copy()
528 env['GIT_DIR'] = project.gitdir.encode()
529 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700530
531 cmd = [GIT, 'tag', '-v', cur]
532 proc = subprocess.Popen(cmd,
533 stdout = subprocess.PIPE,
534 stderr = subprocess.PIPE,
535 env = env)
536 out = proc.stdout.read()
537 proc.stdout.close()
538
539 err = proc.stderr.read()
540 proc.stderr.close()
541
542 if proc.wait() != 0:
543 print >>sys.stderr
544 print >>sys.stderr, out
545 print >>sys.stderr, err
546 print >>sys.stderr
547 return False
548 return True