blob: 595a35aa9523b1a596e2f3295f1435587f25e1b8 [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)
409 except socket.error:
410 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
411 self.manifest.manifest_server)
412 sys.exit(1)
413
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700414 rp = self.manifest.repoProject
415 rp.PreSync()
416
417 mp = self.manifest.manifestProject
418 mp.PreSync()
419
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800420 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700421 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800422
Nico Sallembien9bb18162009-12-07 15:38:01 -0800423 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700424 mp.Sync_NetworkHalf(quiet=opt.quiet,
425 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800426
427 if mp.HasChanges:
428 syncbuf = SyncBuffer(mp.config)
429 mp.Sync_LocalHalf(syncbuf)
430 if not syncbuf.Finish():
431 sys.exit(1)
432 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700433 if opt.jobs is None:
434 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700435 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700436
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700437 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700438 to_fetch = []
439 now = time.time()
440 if (24 * 60 * 60) <= (now - rp.LastFetch):
441 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700442 to_fetch.extend(all)
443
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700444 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700445 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700446 if opt.network_only:
447 # bail out now; the rest touches the working tree
448 return
449
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700450 self.manifest._Unload()
451 all = self.GetProjects(args, missing_ok=True)
452 missing = []
453 for project in all:
454 if project.gitdir not in fetched:
455 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700456 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700457
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700458 if self.manifest.IsMirror:
459 # bail out now, we have no working tree
460 return
461
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700462 if self.UpdateProjectList():
463 sys.exit(1)
464
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700465 syncbuf = SyncBuffer(mp.config,
466 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700467 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700468 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700469 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800470 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700471 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700472 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700473 print >>sys.stderr
474 if not syncbuf.Finish():
475 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700476
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700477 # If there's a notice that's supposed to print at the end of the sync, print
478 # it now...
479 if self.manifest.notice:
480 print self.manifest.notice
481
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700482def _PostRepoUpgrade(manifest):
483 for project in manifest.projects.values():
484 if project.Exists:
485 project.PostRepoUpgrade()
486
487def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
488 if rp.HasChanges:
489 print >>sys.stderr, 'info: A new version of repo is available'
490 print >>sys.stderr, ''
491 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700492 syncbuf = SyncBuffer(rp.config)
493 rp.Sync_LocalHalf(syncbuf)
494 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700495 sys.exit(1)
496 print >>sys.stderr, 'info: Restarting repo with latest version'
497 raise RepoChangedException(['--repo-upgraded'])
498 else:
499 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
500 else:
501 if verbose:
502 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
503
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700504def _VerifyTag(project):
505 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
506 if not os.path.exists(gpg_dir):
507 print >>sys.stderr,\
508"""warning: GnuPG was not available during last "repo init"
509warning: Cannot automatically authenticate repo."""
510 return True
511
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700512 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700513 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700514 except GitError:
515 cur = None
516
517 if not cur \
518 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700519 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700520 if rev.startswith(R_HEADS):
521 rev = rev[len(R_HEADS):]
522
523 print >>sys.stderr
524 print >>sys.stderr,\
525 "warning: project '%s' branch '%s' is not signed" \
526 % (project.name, rev)
527 return False
528
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800529 env = os.environ.copy()
530 env['GIT_DIR'] = project.gitdir.encode()
531 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700532
533 cmd = [GIT, 'tag', '-v', cur]
534 proc = subprocess.Popen(cmd,
535 stdout = subprocess.PIPE,
536 stderr = subprocess.PIPE,
537 env = env)
538 out = proc.stdout.read()
539 proc.stdout.close()
540
541 err = proc.stderr.read()
542 proc.stderr.close()
543
544 if proc.wait() != 0:
545 print >>sys.stderr
546 print >>sys.stderr, out
547 print >>sys.stderr, err
548 print >>sys.stderr
549 return False
550 return True