blob: b2658d87949965c9fff352b16659dd44dd5e6b9d [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))
David 'Digit' Turnere2126652012-09-05 10:35:06 +0200264 # Ensure that Ctrl-C will not freeze the repo process.
265 t.daemon = True
Roy Lee18afd7f2010-05-09 04:32:08 +0800266 threads.add(t)
267 t.start()
268
269 for t in threads:
270 t.join()
271
Doug Andersonfc06ced2011-03-16 15:49:18 -0700272 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400273 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700274 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
275 sys.exit(1)
276
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700277 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700278 for project in projects:
279 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700280 return fetched
281
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700282 def UpdateProjectList(self):
283 new_project_paths = []
Colin Cross5acde752012-03-28 20:15:45 -0700284 for project in self.GetProjects(None, missing_ok=True):
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700285 if project.relpath:
286 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700287 file_name = 'project.list'
288 file_path = os.path.join(self.manifest.repodir, file_name)
289 old_project_paths = []
290
291 if os.path.exists(file_path):
292 fd = open(file_path, 'r')
293 try:
294 old_project_paths = fd.read().split('\n')
295 finally:
296 fd.close()
297 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700298 if not path:
299 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700300 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400301 """If the path has already been deleted, we don't need to do it
302 """
303 if os.path.exists(self.manifest.topdir + '/' + path):
304 project = Project(
305 manifest = self.manifest,
306 name = path,
307 remote = RemoteSpec('origin'),
308 gitdir = os.path.join(self.manifest.topdir,
309 path, '.git'),
310 worktree = os.path.join(self.manifest.topdir, path),
311 relpath = path,
312 revisionExpr = 'HEAD',
Colin Cross5acde752012-03-28 20:15:45 -0700313 revisionId = None,
314 groups = None)
Anthonyf3fdf822009-09-26 13:38:52 -0400315
316 if project.IsDirty():
317 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700318uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400319 print >>sys.stderr, ' commit changes, then run sync again'
320 return -1
321 else:
322 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
323 shutil.rmtree(project.worktree)
324 # Try deleting parent subdirs if they are empty
325 dir = os.path.dirname(project.worktree)
326 while dir != self.manifest.topdir:
327 try:
328 os.rmdir(dir)
329 except OSError:
330 break
331 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700332
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700333 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700334 fd = open(file_path, 'w')
335 try:
336 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700337 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700338 finally:
339 fd.close()
340 return 0
341
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700342 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800343 if opt.jobs:
344 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700345 if self.jobs > 1:
346 soft_limit, _ = _rlimit_nofile()
347 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
348
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700349 if opt.network_only and opt.detach_head:
350 print >>sys.stderr, 'error: cannot combine -n and -d'
351 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700352 if opt.network_only and opt.local_only:
353 print >>sys.stderr, 'error: cannot combine -n and -l'
354 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500355 if opt.manifest_name and opt.smart_sync:
356 print >>sys.stderr, 'error: cannot combine -m and -s'
357 sys.exit(1)
358 if opt.manifest_name and opt.smart_tag:
359 print >>sys.stderr, 'error: cannot combine -m and -t'
360 sys.exit(1)
361
362 if opt.manifest_name:
363 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700364
Victor Boivie08c880d2011-04-19 10:32:52 +0200365 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700366 if not self.manifest.manifest_server:
367 print >>sys.stderr, \
368 'error: cannot smart sync: no manifest server defined in manifest'
369 sys.exit(1)
370 try:
371 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200372 if opt.smart_sync:
373 p = self.manifest.manifestProject
374 b = p.GetBranch(p.CurrentBranch)
375 branch = b.merge
376 if branch.startswith(R_HEADS):
377 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700378
Victor Boivie08c880d2011-04-19 10:32:52 +0200379 env = os.environ.copy()
380 if (env.has_key('TARGET_PRODUCT') and
381 env.has_key('TARGET_BUILD_VARIANT')):
382 target = '%s-%s' % (env['TARGET_PRODUCT'],
383 env['TARGET_BUILD_VARIANT'])
384 [success, manifest_str] = server.GetApprovedManifest(branch, target)
385 else:
386 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700387 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200388 assert(opt.smart_tag)
389 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700390
391 if success:
392 manifest_name = "smart_sync_override.xml"
393 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
394 manifest_name)
395 try:
396 f = open(manifest_path, 'w')
397 try:
398 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700399 finally:
400 f.close()
401 except IOError:
402 print >>sys.stderr, 'error: cannot write manifest to %s' % \
403 manifest_path
404 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700405 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700406 else:
407 print >>sys.stderr, 'error: %s' % manifest_str
408 sys.exit(1)
David Pursehousebd489c42012-08-23 10:21:26 +0900409 except (socket.error, IOError, xmlrpclib.Fault), e:
410 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%s' % (
411 self.manifest.manifest_server, e)
412 sys.exit(1)
413 except xmlrpclib.ProtocolError, e:
414 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%d %s' % (
415 self.manifest.manifest_server, e.errcode, e.errmsg)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700416 sys.exit(1)
417
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700418 rp = self.manifest.repoProject
419 rp.PreSync()
420
421 mp = self.manifest.manifestProject
422 mp.PreSync()
423
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800424 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700425 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800426
Nico Sallembien9bb18162009-12-07 15:38:01 -0800427 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700428 mp.Sync_NetworkHalf(quiet=opt.quiet,
429 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800430
431 if mp.HasChanges:
432 syncbuf = SyncBuffer(mp.config)
433 mp.Sync_LocalHalf(syncbuf)
434 if not syncbuf.Finish():
435 sys.exit(1)
436 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700437 if opt.jobs is None:
438 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700439 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700440
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700441 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700442 to_fetch = []
443 now = time.time()
444 if (24 * 60 * 60) <= (now - rp.LastFetch):
445 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700446 to_fetch.extend(all)
447
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700448 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700449 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700450 if opt.network_only:
451 # bail out now; the rest touches the working tree
452 return
453
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700454 self.manifest._Unload()
455 all = self.GetProjects(args, missing_ok=True)
456 missing = []
457 for project in all:
458 if project.gitdir not in fetched:
459 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700460 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700461
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700462 if self.manifest.IsMirror:
463 # bail out now, we have no working tree
464 return
465
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700466 if self.UpdateProjectList():
467 sys.exit(1)
468
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700469 syncbuf = SyncBuffer(mp.config,
470 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700471 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700472 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700473 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800474 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700475 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700476 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700477 print >>sys.stderr
478 if not syncbuf.Finish():
479 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700480
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700481 # If there's a notice that's supposed to print at the end of the sync, print
482 # it now...
483 if self.manifest.notice:
484 print self.manifest.notice
485
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700486def _PostRepoUpgrade(manifest):
487 for project in manifest.projects.values():
488 if project.Exists:
489 project.PostRepoUpgrade()
490
491def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
492 if rp.HasChanges:
493 print >>sys.stderr, 'info: A new version of repo is available'
494 print >>sys.stderr, ''
495 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700496 syncbuf = SyncBuffer(rp.config)
497 rp.Sync_LocalHalf(syncbuf)
498 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700499 sys.exit(1)
500 print >>sys.stderr, 'info: Restarting repo with latest version'
501 raise RepoChangedException(['--repo-upgraded'])
502 else:
503 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
504 else:
505 if verbose:
506 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
507
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700508def _VerifyTag(project):
509 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
510 if not os.path.exists(gpg_dir):
511 print >>sys.stderr,\
512"""warning: GnuPG was not available during last "repo init"
513warning: Cannot automatically authenticate repo."""
514 return True
515
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700516 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700517 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700518 except GitError:
519 cur = None
520
521 if not cur \
522 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700523 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700524 if rev.startswith(R_HEADS):
525 rev = rev[len(R_HEADS):]
526
527 print >>sys.stderr
528 print >>sys.stderr,\
529 "warning: project '%s' branch '%s' is not signed" \
530 % (project.name, rev)
531 return False
532
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800533 env = os.environ.copy()
534 env['GIT_DIR'] = project.gitdir.encode()
535 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700536
537 cmd = [GIT, 'tag', '-v', cur]
538 proc = subprocess.Popen(cmd,
539 stdout = subprocess.PIPE,
540 stderr = subprocess.PIPE,
541 env = env)
542 out = proc.stdout.read()
543 proc.stdout.close()
544
545 err = proc.stderr.read()
546 proc.stderr.close()
547
548 if proc.wait() != 0:
549 print >>sys.stderr
550 print >>sys.stderr, out
551 print >>sys.stderr, err
552 print >>sys.stderr
553 return False
554 return True