blob: cbf0decc229f768ac47ff03efb9c8934e5e6c9ec [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
David Pursehoused94aaef2012-09-07 09:52:04 +090040from git_refs import R_HEADS, HEAD
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070041from project import Project
42from project import RemoteSpec
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080043from command import Command, MirrorSafeCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070044from error import RepoChangedException, GitError
Shawn O. Pearce350cde42009-04-16 11:21:18 -070045from project import SyncBuffer
Shawn O. Pearce68194f42009-04-10 16:48:52 -070046from progress import Progress
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070047
Doug Andersonfc06ced2011-03-16 15:49:18 -070048class _FetchError(Exception):
49 """Internal error thrown in _FetchHelper() when we don't want stack trace."""
50 pass
51
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080052class Sync(Command, MirrorSafeCommand):
Roy Lee18afd7f2010-05-09 04:32:08 +080053 jobs = 1
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070054 common = True
55 helpSummary = "Update working tree to the latest revision"
56 helpUsage = """
57%prog [<project>...]
58"""
59 helpDescription = """
60The '%prog' command synchronizes local project directories
61with the remote repositories specified in the manifest. If a local
62project does not yet exist, it will clone a new local directory from
63the remote repository and set up tracking branches as specified in
64the manifest. If the local project already exists, '%prog'
65will update the remote branches and rebase any new local changes
66on top of the new remote changes.
67
68'%prog' will synchronize all projects listed at the command
69line. Projects can be specified either by name, or by a relative
70or absolute path to the project's local directory. If no projects
71are specified, '%prog' will synchronize all projects listed in
72the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070073
74The -d/--detach option can be used to switch specified projects
75back to the manifest revision. This option is especially helpful
76if the project is currently on a topic branch, but the manifest
77revision is temporarily needed.
Shawn O. Pearceeb7af872009-04-21 08:02:04 -070078
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070079The -s/--smart-sync option can be used to sync to a known good
80build as specified by the manifest-server element in the current
Victor Boivie08c880d2011-04-19 10:32:52 +020081manifest. The -t/--smart-tag option is similar and allows you to
82specify a custom tag/label.
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070083
Andrei Warkentin5df6de02010-07-02 17:58:31 -050084The -f/--force-broken option can be used to proceed with syncing
85other projects if a project sync fails.
86
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -070087The --no-clone-bundle option disables any attempt to use
88$URL/clone.bundle to bootstrap a new Git repository from a
89resumeable bundle file on a content delivery network. This
90may be necessary if there are problems with the local Python
91HTTP client or proxy configuration, but the Git binary works.
92
Shawn O. Pearceeb7af872009-04-21 08:02:04 -070093SSH Connections
94---------------
95
96If at least one project remote URL uses an SSH connection (ssh://,
97git+ssh://, or user@host:path syntax) repo will automatically
98enable the SSH ControlMaster option when connecting to that host.
99This feature permits other projects in the same '%prog' session to
100reuse the same SSH tunnel, saving connection setup overheads.
101
102To disable this behavior on UNIX platforms, set the GIT_SSH
103environment variable to 'ssh'. For example:
104
105 export GIT_SSH=ssh
106 %prog
107
108Compatibility
109~~~~~~~~~~~~~
110
111This feature is automatically disabled on Windows, due to the lack
112of UNIX domain socket support.
113
114This feature is not compatible with url.insteadof rewrites in the
115user's ~/.gitconfig. '%prog' is currently not able to perform the
116rewrite early enough to establish the ControlMaster tunnel.
117
118If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or
119later is required to fix a server side protocol bug.
120
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700121"""
122
Nico Sallembien6623b212010-05-11 12:57:01 -0700123 def _Options(self, p, show_smart=True):
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700124 self.jobs = self.manifest.default.sync_j
125
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500126 p.add_option('-f', '--force-broken',
127 dest='force_broken', action='store_true',
128 help="continue sync even if a project fails to sync")
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700129 p.add_option('-l','--local-only',
130 dest='local_only', action='store_true',
131 help="only update working tree, don't fetch")
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -0700132 p.add_option('-n','--network-only',
133 dest='network_only', action='store_true',
134 help="fetch only, don't update working tree")
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700135 p.add_option('-d','--detach',
136 dest='detach_head', action='store_true',
137 help='detach projects back to manifest revision')
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700138 p.add_option('-c','--current-branch',
139 dest='current_branch_only', action='store_true',
140 help='fetch only current branch from server')
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700141 p.add_option('-q','--quiet',
142 dest='quiet', action='store_true',
143 help='be more quiet')
Roy Lee18afd7f2010-05-09 04:32:08 +0800144 p.add_option('-j','--jobs',
145 dest='jobs', action='store', type='int',
Shawn O. Pearce6392c872011-09-22 17:44:31 -0700146 help="projects to fetch simultaneously (default %d)" % self.jobs)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500147 p.add_option('-m', '--manifest-name',
148 dest='manifest_name',
149 help='temporary manifest to use for this sync', metavar='NAME.xml')
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700150 p.add_option('--no-clone-bundle',
151 dest='no_clone_bundle', action='store_true',
152 help='disable use of /clone.bundle on HTTP/HTTPS')
Nico Sallembien6623b212010-05-11 12:57:01 -0700153 if show_smart:
154 p.add_option('-s', '--smart-sync',
155 dest='smart_sync', action='store_true',
156 help='smart sync using manifest from a known good build')
Victor Boivie08c880d2011-04-19 10:32:52 +0200157 p.add_option('-t', '--smart-tag',
158 dest='smart_tag', action='store',
159 help='smart sync using manifest from a known tag')
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700160
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700161 g = p.add_option_group('repo Version options')
162 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700163 dest='no_repo_verify', action='store_true',
164 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700165 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800166 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -0700167 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700168
Doug Andersonfc06ced2011-03-16 15:49:18 -0700169 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
170 """Main function of the fetch threads when jobs are > 1.
Roy Lee18afd7f2010-05-09 04:32:08 +0800171
Doug Andersonfc06ced2011-03-16 15:49:18 -0700172 Args:
173 opt: Program options returned from optparse. See _Options().
174 project: Project object for the project to fetch.
175 lock: Lock for accessing objects that are shared amongst multiple
176 _FetchHelper() threads.
177 fetched: set object that we will add project.gitdir to when we're done
178 (with our lock held).
179 pm: Instance of a Project object. We will call pm.update() (with our
180 lock held).
181 sem: We'll release() this semaphore when we exit so that another thread
182 can be started up.
183 err_event: We'll set this event in the case of an error (after printing
184 out info about the error).
185 """
186 # We'll set to true once we've locked the lock.
187 did_lock = False
188
189 # Encapsulate everything in a try/except/finally so that:
190 # - We always set err_event in the case of an exception.
191 # - We always make sure we call sem.release().
192 # - We always make sure we unlock the lock if we locked it.
193 try:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700194 try:
Shawn O. Pearcee02ac0a2012-03-14 15:36:59 -0700195 success = project.Sync_NetworkHalf(
196 quiet=opt.quiet,
197 current_branch_only=opt.current_branch_only,
198 clone_bundle=not opt.no_clone_bundle)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700199
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700200 # Lock around all the rest of the code, since printing, updating a set
201 # and Progress.update() are not thread safe.
202 lock.acquire()
203 did_lock = True
Doug Andersonfc06ced2011-03-16 15:49:18 -0700204
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700205 if not success:
206 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
207 if opt.force_broken:
208 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
209 else:
210 raise _FetchError()
Doug Andersonfc06ced2011-03-16 15:49:18 -0700211
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700212 fetched.add(project.gitdir)
213 pm.update()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700214 except _FetchError:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700215 err_event.set()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700216 except:
217 err_event.set()
218 raise
Doug Andersonfc06ced2011-03-16 15:49:18 -0700219 finally:
220 if did_lock:
221 lock.release()
222 sem.release()
Roy Lee18afd7f2010-05-09 04:32:08 +0800223
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700224 def _Fetch(self, projects, opt):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700225 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700226 pm = Progress('Fetching projects', len(projects))
Roy Lee18afd7f2010-05-09 04:32:08 +0800227
228 if self.jobs == 1:
229 for project in projects:
230 pm.update()
Shawn O. Pearce5d0efdb2012-08-02 12:13:01 -0700231 if project.Sync_NetworkHalf(
232 quiet=opt.quiet,
233 current_branch_only=opt.current_branch_only,
234 clone_bundle=not opt.no_clone_bundle):
Roy Lee18afd7f2010-05-09 04:32:08 +0800235 fetched.add(project.gitdir)
236 else:
237 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
Andrei Warkentin5df6de02010-07-02 17:58:31 -0500238 if opt.force_broken:
239 print >>sys.stderr, 'warn: --force-broken, continuing to sync'
240 else:
241 sys.exit(1)
Roy Lee18afd7f2010-05-09 04:32:08 +0800242 else:
243 threads = set()
244 lock = _threading.Lock()
245 sem = _threading.Semaphore(self.jobs)
Doug Andersonfc06ced2011-03-16 15:49:18 -0700246 err_event = _threading.Event()
Roy Lee18afd7f2010-05-09 04:32:08 +0800247 for project in projects:
Doug Andersonfc06ced2011-03-16 15:49:18 -0700248 # Check for any errors before starting any new threads.
249 # ...we'll let existing threads finish, though.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400250 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700251 break
252
Roy Lee18afd7f2010-05-09 04:32:08 +0800253 sem.acquire()
254 t = _threading.Thread(target = self._FetchHelper,
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700255 args = (opt,
256 project,
257 lock,
258 fetched,
259 pm,
Doug Andersonfc06ced2011-03-16 15:49:18 -0700260 sem,
261 err_event))
David 'Digit' Turnere2126652012-09-05 10:35:06 +0200262 # Ensure that Ctrl-C will not freeze the repo process.
263 t.daemon = True
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)
David Pursehousebd489c42012-08-23 10:21:26 +0900407 except (socket.error, IOError, xmlrpclib.Fault), e:
408 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%s' % (
409 self.manifest.manifest_server, e)
410 sys.exit(1)
411 except xmlrpclib.ProtocolError, e:
412 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%d %s' % (
413 self.manifest.manifest_server, e.errcode, e.errmsg)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700414 sys.exit(1)
415
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700416 rp = self.manifest.repoProject
417 rp.PreSync()
418
419 mp = self.manifest.manifestProject
420 mp.PreSync()
421
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800422 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700423 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800424
Nico Sallembien9bb18162009-12-07 15:38:01 -0800425 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700426 mp.Sync_NetworkHalf(quiet=opt.quiet,
427 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800428
429 if mp.HasChanges:
430 syncbuf = SyncBuffer(mp.config)
431 mp.Sync_LocalHalf(syncbuf)
432 if not syncbuf.Finish():
433 sys.exit(1)
434 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700435 if opt.jobs is None:
436 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700437 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700438
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700439 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700440 to_fetch = []
441 now = time.time()
442 if (24 * 60 * 60) <= (now - rp.LastFetch):
443 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700444 to_fetch.extend(all)
445
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700446 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700447 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700448 if opt.network_only:
449 # bail out now; the rest touches the working tree
450 return
451
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700452 self.manifest._Unload()
453 all = self.GetProjects(args, missing_ok=True)
454 missing = []
455 for project in all:
456 if project.gitdir not in fetched:
457 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700458 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700459
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700460 if self.manifest.IsMirror:
461 # bail out now, we have no working tree
462 return
463
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700464 if self.UpdateProjectList():
465 sys.exit(1)
466
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700467 syncbuf = SyncBuffer(mp.config,
468 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700469 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700470 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700471 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800472 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700473 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700474 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700475 print >>sys.stderr
476 if not syncbuf.Finish():
477 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700478
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700479 # If there's a notice that's supposed to print at the end of the sync, print
480 # it now...
481 if self.manifest.notice:
482 print self.manifest.notice
483
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700484def _PostRepoUpgrade(manifest):
485 for project in manifest.projects.values():
486 if project.Exists:
487 project.PostRepoUpgrade()
488
489def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
490 if rp.HasChanges:
491 print >>sys.stderr, 'info: A new version of repo is available'
492 print >>sys.stderr, ''
493 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700494 syncbuf = SyncBuffer(rp.config)
495 rp.Sync_LocalHalf(syncbuf)
496 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700497 sys.exit(1)
498 print >>sys.stderr, 'info: Restarting repo with latest version'
499 raise RepoChangedException(['--repo-upgraded'])
500 else:
501 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
502 else:
503 if verbose:
504 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
505
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700506def _VerifyTag(project):
507 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
508 if not os.path.exists(gpg_dir):
509 print >>sys.stderr,\
510"""warning: GnuPG was not available during last "repo init"
511warning: Cannot automatically authenticate repo."""
512 return True
513
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700514 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700515 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700516 except GitError:
517 cur = None
518
519 if not cur \
520 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700521 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700522 if rev.startswith(R_HEADS):
523 rev = rev[len(R_HEADS):]
524
525 print >>sys.stderr
526 print >>sys.stderr,\
527 "warning: project '%s' branch '%s' is not signed" \
528 % (project.name, rev)
529 return False
530
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800531 env = os.environ.copy()
532 env['GIT_DIR'] = project.gitdir.encode()
533 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700534
535 cmd = [GIT, 'tag', '-v', cur]
536 proc = subprocess.Popen(cmd,
537 stdout = subprocess.PIPE,
538 stderr = subprocess.PIPE,
539 env = env)
540 out = proc.stdout.read()
541 proc.stdout.close()
542
543 err = proc.stderr.read()
544 proc.stderr.close()
545
546 if proc.wait() != 0:
547 print >>sys.stderr
548 print >>sys.stderr, out
549 print >>sys.stderr, err
550 print >>sys.stderr
551 return False
552 return True