blob: 74b3f1838da8a494d9011531a362193203ea2396 [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.
173
174 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()
Roy Lee18afd7f2010-05-09 04:32:08 +0800213
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:
217 err_event.set()
218 except:
Shawn O. Pearcee6a0eeb2011-03-22 19:04:47 -0700219 err_event.set()
Shawn O. Pearcedf5ee522011-10-11 14:05:21 -0700220 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()
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700233 if project.Sync_NetworkHalf(quiet=opt.quiet,
234 current_branch_only=opt.current_branch_only):
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))
Roy Lee18afd7f2010-05-09 04:32:08 +0800262 threads.add(t)
263 t.start()
264
265 for t in threads:
266 t.join()
267
Doug Andersonfc06ced2011-03-16 15:49:18 -0700268 # If we saw an error, exit with code 1 so that other scripts can check.
Daniel Sandler723c5dc2011-04-04 11:15:17 -0400269 if err_event.isSet():
Doug Andersonfc06ced2011-03-16 15:49:18 -0700270 print >>sys.stderr, '\nerror: Exited sync due to fetch errors'
271 sys.exit(1)
272
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700273 pm.end()
Shawn O. Pearce0d2b61f2009-07-03 15:22:49 -0700274 for project in projects:
275 project.bare_git.gc('--auto')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700276 return fetched
277
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700278 def UpdateProjectList(self):
279 new_project_paths = []
280 for project in self.manifest.projects.values():
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700281 if project.relpath:
282 new_project_paths.append(project.relpath)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700283 file_name = 'project.list'
284 file_path = os.path.join(self.manifest.repodir, file_name)
285 old_project_paths = []
286
287 if os.path.exists(file_path):
288 fd = open(file_path, 'r')
289 try:
290 old_project_paths = fd.read().split('\n')
291 finally:
292 fd.close()
293 for path in old_project_paths:
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700294 if not path:
295 continue
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700296 if path not in new_project_paths:
Anthonyf3fdf822009-09-26 13:38:52 -0400297 """If the path has already been deleted, we don't need to do it
298 """
299 if os.path.exists(self.manifest.topdir + '/' + path):
300 project = Project(
301 manifest = self.manifest,
302 name = path,
303 remote = RemoteSpec('origin'),
304 gitdir = os.path.join(self.manifest.topdir,
305 path, '.git'),
306 worktree = os.path.join(self.manifest.topdir, path),
307 relpath = path,
308 revisionExpr = 'HEAD',
309 revisionId = None)
310
311 if project.IsDirty():
312 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700313uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400314 print >>sys.stderr, ' commit changes, then run sync again'
315 return -1
316 else:
317 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
318 shutil.rmtree(project.worktree)
319 # Try deleting parent subdirs if they are empty
320 dir = os.path.dirname(project.worktree)
321 while dir != self.manifest.topdir:
322 try:
323 os.rmdir(dir)
324 except OSError:
325 break
326 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700327
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700328 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700329 fd = open(file_path, 'w')
330 try:
331 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700332 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700333 finally:
334 fd.close()
335 return 0
336
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700337 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800338 if opt.jobs:
339 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700340 if self.jobs > 1:
341 soft_limit, _ = _rlimit_nofile()
342 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
343
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700344 if opt.network_only and opt.detach_head:
345 print >>sys.stderr, 'error: cannot combine -n and -d'
346 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700347 if opt.network_only and opt.local_only:
348 print >>sys.stderr, 'error: cannot combine -n and -l'
349 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500350 if opt.manifest_name and opt.smart_sync:
351 print >>sys.stderr, 'error: cannot combine -m and -s'
352 sys.exit(1)
353 if opt.manifest_name and opt.smart_tag:
354 print >>sys.stderr, 'error: cannot combine -m and -t'
355 sys.exit(1)
356
357 if opt.manifest_name:
358 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700359
Victor Boivie08c880d2011-04-19 10:32:52 +0200360 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700361 if not self.manifest.manifest_server:
362 print >>sys.stderr, \
363 'error: cannot smart sync: no manifest server defined in manifest'
364 sys.exit(1)
365 try:
366 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200367 if opt.smart_sync:
368 p = self.manifest.manifestProject
369 b = p.GetBranch(p.CurrentBranch)
370 branch = b.merge
371 if branch.startswith(R_HEADS):
372 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700373
Victor Boivie08c880d2011-04-19 10:32:52 +0200374 env = os.environ.copy()
375 if (env.has_key('TARGET_PRODUCT') and
376 env.has_key('TARGET_BUILD_VARIANT')):
377 target = '%s-%s' % (env['TARGET_PRODUCT'],
378 env['TARGET_BUILD_VARIANT'])
379 [success, manifest_str] = server.GetApprovedManifest(branch, target)
380 else:
381 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700382 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200383 assert(opt.smart_tag)
384 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700385
386 if success:
387 manifest_name = "smart_sync_override.xml"
388 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
389 manifest_name)
390 try:
391 f = open(manifest_path, 'w')
392 try:
393 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700394 finally:
395 f.close()
396 except IOError:
397 print >>sys.stderr, 'error: cannot write manifest to %s' % \
398 manifest_path
399 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700400 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700401 else:
402 print >>sys.stderr, 'error: %s' % manifest_str
403 sys.exit(1)
404 except socket.error:
405 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
406 self.manifest.manifest_server)
407 sys.exit(1)
408
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700409 rp = self.manifest.repoProject
410 rp.PreSync()
411
412 mp = self.manifest.manifestProject
413 mp.PreSync()
414
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800415 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700416 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800417
Nico Sallembien9bb18162009-12-07 15:38:01 -0800418 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700419 mp.Sync_NetworkHalf(quiet=opt.quiet,
420 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800421
422 if mp.HasChanges:
423 syncbuf = SyncBuffer(mp.config)
424 mp.Sync_LocalHalf(syncbuf)
425 if not syncbuf.Finish():
426 sys.exit(1)
427 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700428 if opt.jobs is None:
429 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700430 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700431
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700432 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700433 to_fetch = []
434 now = time.time()
435 if (24 * 60 * 60) <= (now - rp.LastFetch):
436 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700437 to_fetch.extend(all)
438
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700439 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700440 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700441 if opt.network_only:
442 # bail out now; the rest touches the working tree
443 return
444
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700445 self.manifest._Unload()
446 all = self.GetProjects(args, missing_ok=True)
447 missing = []
448 for project in all:
449 if project.gitdir not in fetched:
450 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700451 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700452
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700453 if self.manifest.IsMirror:
454 # bail out now, we have no working tree
455 return
456
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700457 if self.UpdateProjectList():
458 sys.exit(1)
459
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700460 syncbuf = SyncBuffer(mp.config,
461 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700462 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700463 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700464 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800465 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700466 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700467 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700468 print >>sys.stderr
469 if not syncbuf.Finish():
470 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700471
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700472 # If there's a notice that's supposed to print at the end of the sync, print
473 # it now...
474 if self.manifest.notice:
475 print self.manifest.notice
476
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700477def _PostRepoUpgrade(manifest):
478 for project in manifest.projects.values():
479 if project.Exists:
480 project.PostRepoUpgrade()
481
482def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
483 if rp.HasChanges:
484 print >>sys.stderr, 'info: A new version of repo is available'
485 print >>sys.stderr, ''
486 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700487 syncbuf = SyncBuffer(rp.config)
488 rp.Sync_LocalHalf(syncbuf)
489 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700490 sys.exit(1)
491 print >>sys.stderr, 'info: Restarting repo with latest version'
492 raise RepoChangedException(['--repo-upgraded'])
493 else:
494 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
495 else:
496 if verbose:
497 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
498
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700499def _VerifyTag(project):
500 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
501 if not os.path.exists(gpg_dir):
502 print >>sys.stderr,\
503"""warning: GnuPG was not available during last "repo init"
504warning: Cannot automatically authenticate repo."""
505 return True
506
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700507 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700508 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700509 except GitError:
510 cur = None
511
512 if not cur \
513 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700514 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700515 if rev.startswith(R_HEADS):
516 rev = rev[len(R_HEADS):]
517
518 print >>sys.stderr
519 print >>sys.stderr,\
520 "warning: project '%s' branch '%s' is not signed" \
521 % (project.name, rev)
522 return False
523
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800524 env = os.environ.copy()
525 env['GIT_DIR'] = project.gitdir.encode()
526 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700527
528 cmd = [GIT, 'tag', '-v', cur]
529 proc = subprocess.Popen(cmd,
530 stdout = subprocess.PIPE,
531 stderr = subprocess.PIPE,
532 env = env)
533 out = proc.stdout.read()
534 proc.stdout.close()
535
536 err = proc.stderr.read()
537 proc.stderr.close()
538
539 if proc.wait() != 0:
540 print >>sys.stderr
541 print >>sys.stderr, out
542 print >>sys.stderr, err
543 print >>sys.stderr
544 return False
545 return True