blob: 63227afdd596c212dbd05794d4f0a1fce26b680c [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 = []
Colin Cross5acde752012-03-28 20:15:45 -0700280 for project in self.GetProjects(None, missing_ok=True):
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',
Colin Cross5acde752012-03-28 20:15:45 -0700309 revisionId = None,
310 groups = None)
Anthonyf3fdf822009-09-26 13:38:52 -0400311
312 if project.IsDirty():
313 print >>sys.stderr, 'error: Cannot remove project "%s": \
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700314uncommitted changes are present' % project.relpath
Anthonyf3fdf822009-09-26 13:38:52 -0400315 print >>sys.stderr, ' commit changes, then run sync again'
316 return -1
317 else:
318 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree
319 shutil.rmtree(project.worktree)
320 # Try deleting parent subdirs if they are empty
321 dir = os.path.dirname(project.worktree)
322 while dir != self.manifest.topdir:
323 try:
324 os.rmdir(dir)
325 except OSError:
326 break
327 dir = os.path.dirname(dir)
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700328
Shawn O. Pearce9fb29ce2009-06-04 20:41:02 -0700329 new_project_paths.sort()
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700330 fd = open(file_path, 'w')
331 try:
332 fd.write('\n'.join(new_project_paths))
Shawn O. Pearce3a68bb42009-06-04 16:18:09 -0700333 fd.write('\n')
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700334 finally:
335 fd.close()
336 return 0
337
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700338 def Execute(self, opt, args):
Roy Lee18afd7f2010-05-09 04:32:08 +0800339 if opt.jobs:
340 self.jobs = opt.jobs
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -0700341 if self.jobs > 1:
342 soft_limit, _ = _rlimit_nofile()
343 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
344
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700345 if opt.network_only and opt.detach_head:
346 print >>sys.stderr, 'error: cannot combine -n and -d'
347 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700348 if opt.network_only and opt.local_only:
349 print >>sys.stderr, 'error: cannot combine -n and -l'
350 sys.exit(1)
Chris Wolfee9dc3b32012-01-26 11:36:18 -0500351 if opt.manifest_name and opt.smart_sync:
352 print >>sys.stderr, 'error: cannot combine -m and -s'
353 sys.exit(1)
354 if opt.manifest_name and opt.smart_tag:
355 print >>sys.stderr, 'error: cannot combine -m and -t'
356 sys.exit(1)
357
358 if opt.manifest_name:
359 self.manifest.Override(opt.manifest_name)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700360
Victor Boivie08c880d2011-04-19 10:32:52 +0200361 if opt.smart_sync or opt.smart_tag:
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700362 if not self.manifest.manifest_server:
363 print >>sys.stderr, \
364 'error: cannot smart sync: no manifest server defined in manifest'
365 sys.exit(1)
366 try:
367 server = xmlrpclib.Server(self.manifest.manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200368 if opt.smart_sync:
369 p = self.manifest.manifestProject
370 b = p.GetBranch(p.CurrentBranch)
371 branch = b.merge
372 if branch.startswith(R_HEADS):
373 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700374
Victor Boivie08c880d2011-04-19 10:32:52 +0200375 env = os.environ.copy()
376 if (env.has_key('TARGET_PRODUCT') and
377 env.has_key('TARGET_BUILD_VARIANT')):
378 target = '%s-%s' % (env['TARGET_PRODUCT'],
379 env['TARGET_BUILD_VARIANT'])
380 [success, manifest_str] = server.GetApprovedManifest(branch, target)
381 else:
382 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700383 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200384 assert(opt.smart_tag)
385 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700386
387 if success:
388 manifest_name = "smart_sync_override.xml"
389 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
390 manifest_name)
391 try:
392 f = open(manifest_path, 'w')
393 try:
394 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700395 finally:
396 f.close()
397 except IOError:
398 print >>sys.stderr, 'error: cannot write manifest to %s' % \
399 manifest_path
400 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700401 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700402 else:
403 print >>sys.stderr, 'error: %s' % manifest_str
404 sys.exit(1)
405 except socket.error:
406 print >>sys.stderr, 'error: cannot connect to manifest server %s' % (
407 self.manifest.manifest_server)
408 sys.exit(1)
409
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700410 rp = self.manifest.repoProject
411 rp.PreSync()
412
413 mp = self.manifest.manifestProject
414 mp.PreSync()
415
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800416 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700417 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800418
Nico Sallembien9bb18162009-12-07 15:38:01 -0800419 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700420 mp.Sync_NetworkHalf(quiet=opt.quiet,
421 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800422
423 if mp.HasChanges:
424 syncbuf = SyncBuffer(mp.config)
425 mp.Sync_LocalHalf(syncbuf)
426 if not syncbuf.Finish():
427 sys.exit(1)
428 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700429 if opt.jobs is None:
430 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700431 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700432
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700433 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700434 to_fetch = []
435 now = time.time()
436 if (24 * 60 * 60) <= (now - rp.LastFetch):
437 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700438 to_fetch.extend(all)
439
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700440 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700441 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700442 if opt.network_only:
443 # bail out now; the rest touches the working tree
444 return
445
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700446 self.manifest._Unload()
447 all = self.GetProjects(args, missing_ok=True)
448 missing = []
449 for project in all:
450 if project.gitdir not in fetched:
451 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700452 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700453
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700454 if self.manifest.IsMirror:
455 # bail out now, we have no working tree
456 return
457
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700458 if self.UpdateProjectList():
459 sys.exit(1)
460
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700461 syncbuf = SyncBuffer(mp.config,
462 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700463 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700464 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700465 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800466 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700467 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700468 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700469 print >>sys.stderr
470 if not syncbuf.Finish():
471 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700472
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700473 # If there's a notice that's supposed to print at the end of the sync, print
474 # it now...
475 if self.manifest.notice:
476 print self.manifest.notice
477
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700478def _PostRepoUpgrade(manifest):
479 for project in manifest.projects.values():
480 if project.Exists:
481 project.PostRepoUpgrade()
482
483def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
484 if rp.HasChanges:
485 print >>sys.stderr, 'info: A new version of repo is available'
486 print >>sys.stderr, ''
487 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700488 syncbuf = SyncBuffer(rp.config)
489 rp.Sync_LocalHalf(syncbuf)
490 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700491 sys.exit(1)
492 print >>sys.stderr, 'info: Restarting repo with latest version'
493 raise RepoChangedException(['--repo-upgraded'])
494 else:
495 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
496 else:
497 if verbose:
498 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
499
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700500def _VerifyTag(project):
501 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
502 if not os.path.exists(gpg_dir):
503 print >>sys.stderr,\
504"""warning: GnuPG was not available during last "repo init"
505warning: Cannot automatically authenticate repo."""
506 return True
507
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700508 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700509 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700510 except GitError:
511 cur = None
512
513 if not cur \
514 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700515 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700516 if rev.startswith(R_HEADS):
517 rev = rev[len(R_HEADS):]
518
519 print >>sys.stderr
520 print >>sys.stderr,\
521 "warning: project '%s' branch '%s' is not signed" \
522 % (project.name, rev)
523 return False
524
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800525 env = os.environ.copy()
526 env['GIT_DIR'] = project.gitdir.encode()
527 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700528
529 cmd = [GIT, 'tag', '-v', cur]
530 proc = subprocess.Popen(cmd,
531 stdout = subprocess.PIPE,
532 stderr = subprocess.PIPE,
533 env = env)
534 out = proc.stdout.read()
535 proc.stdout.close()
536
537 err = proc.stderr.read()
538 proc.stderr.close()
539
540 if proc.wait() != 0:
541 print >>sys.stderr
542 print >>sys.stderr, out
543 print >>sys.stderr, err
544 print >>sys.stderr
545 return False
546 return True