blob: b75bedc1fe0fa7b12b11d38994de38864365c956 [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
David Pursehouse86d973d2012-08-24 10:21:02 +090016import netrc
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -070017from optparse import SUPPRESS_HELP
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070018import os
19import re
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070020import shutil
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070021import socket
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070022import subprocess
23import sys
Shawn O. Pearcef6906872009-04-18 10:49:00 -070024import time
David Pursehouse86d973d2012-08-24 10:21:02 +090025import urlparse
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -070026import xmlrpclib
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070027
Roy Lee18afd7f2010-05-09 04:32:08 +080028try:
29 import threading as _threading
30except ImportError:
31 import dummy_threading as _threading
32
Shawn O. Pearce97d2b2f2011-09-22 17:23:41 -070033try:
34 import resource
35 def _rlimit_nofile():
36 return resource.getrlimit(resource.RLIMIT_NOFILE)
37except ImportError:
38 def _rlimit_nofile():
39 return (256, 256)
40
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070041from git_command import GIT
David Pursehoused94aaef2012-09-07 09:52:04 +090042from git_refs import R_HEADS, HEAD
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -070043from project import Project
44from project import RemoteSpec
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080045from command import Command, MirrorSafeCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070046from error import RepoChangedException, GitError
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()
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)
David Pursehouse86d973d2012-08-24 10:21:02 +0900370
371 manifest_server = self.manifest.manifest_server
372 if not '@' in manifest_server:
373 try:
374 info = netrc.netrc()
375 except IOError:
376 print >>sys.stderr, '.netrc file does not exist or could not be opened'
377 else:
378 try:
379 parse_result = urlparse.urlparse(manifest_server)
380 if parse_result.hostname:
381 username, _account, password = \
382 info.authenticators(parse_result.hostname)
383 except TypeError:
384 # TypeError is raised when the given hostname is not present
385 # in the .netrc file.
386 print >>sys.stderr, 'No credentials found for %s in .netrc' % \
387 parse_result.hostname
388 except netrc.NetrcParseError as e:
389 print >>sys.stderr, 'Error parsing .netrc file: %s' % e
390 else:
391 if (username and password):
392 manifest_server = manifest_server.replace('://', '://%s:%s@' %
393 (username, password),
394 1)
395
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700396 try:
David Pursehouse86d973d2012-08-24 10:21:02 +0900397 server = xmlrpclib.Server(manifest_server)
Victor Boivie08c880d2011-04-19 10:32:52 +0200398 if opt.smart_sync:
399 p = self.manifest.manifestProject
400 b = p.GetBranch(p.CurrentBranch)
401 branch = b.merge
402 if branch.startswith(R_HEADS):
403 branch = branch[len(R_HEADS):]
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700404
Victor Boivie08c880d2011-04-19 10:32:52 +0200405 env = os.environ.copy()
406 if (env.has_key('TARGET_PRODUCT') and
407 env.has_key('TARGET_BUILD_VARIANT')):
408 target = '%s-%s' % (env['TARGET_PRODUCT'],
409 env['TARGET_BUILD_VARIANT'])
410 [success, manifest_str] = server.GetApprovedManifest(branch, target)
411 else:
412 [success, manifest_str] = server.GetApprovedManifest(branch)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700413 else:
Victor Boivie08c880d2011-04-19 10:32:52 +0200414 assert(opt.smart_tag)
415 [success, manifest_str] = server.GetManifest(opt.smart_tag)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700416
417 if success:
418 manifest_name = "smart_sync_override.xml"
419 manifest_path = os.path.join(self.manifest.manifestProject.worktree,
420 manifest_name)
421 try:
422 f = open(manifest_path, 'w')
423 try:
424 f.write(manifest_str)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700425 finally:
426 f.close()
427 except IOError:
428 print >>sys.stderr, 'error: cannot write manifest to %s' % \
429 manifest_path
430 sys.exit(1)
Nico Sallembien719965a2010-04-20 15:28:19 -0700431 self.manifest.Override(manifest_name)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700432 else:
433 print >>sys.stderr, 'error: %s' % manifest_str
434 sys.exit(1)
David Pursehousebd489c42012-08-23 10:21:26 +0900435 except (socket.error, IOError, xmlrpclib.Fault), e:
436 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%s' % (
437 self.manifest.manifest_server, e)
438 sys.exit(1)
439 except xmlrpclib.ProtocolError, e:
440 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%d %s' % (
441 self.manifest.manifest_server, e.errcode, e.errmsg)
Nico Sallembiena1bfd2c2010-04-06 10:40:01 -0700442 sys.exit(1)
443
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700444 rp = self.manifest.repoProject
445 rp.PreSync()
446
447 mp = self.manifest.manifestProject
448 mp.PreSync()
449
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800450 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700451 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800452
Nico Sallembien9bb18162009-12-07 15:38:01 -0800453 if not opt.local_only:
Anatol Pomazau53d6f4d2011-08-25 17:21:47 -0700454 mp.Sync_NetworkHalf(quiet=opt.quiet,
455 current_branch_only=opt.current_branch_only)
Nico Sallembien9bb18162009-12-07 15:38:01 -0800456
457 if mp.HasChanges:
458 syncbuf = SyncBuffer(mp.config)
459 mp.Sync_LocalHalf(syncbuf)
460 if not syncbuf.Finish():
461 sys.exit(1)
462 self.manifest._Unload()
Shawn O. Pearcec4657962011-09-26 09:08:01 -0700463 if opt.jobs is None:
464 self.jobs = self.manifest.default.sync_j
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700465 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700466
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700467 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700468 to_fetch = []
469 now = time.time()
470 if (24 * 60 * 60) <= (now - rp.LastFetch):
471 to_fetch.append(rp)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700472 to_fetch.extend(all)
473
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700474 fetched = self._Fetch(to_fetch, opt)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700475 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700476 if opt.network_only:
477 # bail out now; the rest touches the working tree
478 return
479
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700480 self.manifest._Unload()
481 all = self.GetProjects(args, missing_ok=True)
482 missing = []
483 for project in all:
484 if project.gitdir not in fetched:
485 missing.append(project)
Shawn O. Pearce16614f82010-10-29 12:05:43 -0700486 self._Fetch(missing, opt)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700487
Shawn O. Pearcecd1d7ff2009-06-04 16:15:53 -0700488 if self.manifest.IsMirror:
489 # bail out now, we have no working tree
490 return
491
Jaikumar Ganesh4f2517f2009-06-01 21:10:33 -0700492 if self.UpdateProjectList():
493 sys.exit(1)
494
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700495 syncbuf = SyncBuffer(mp.config,
496 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700497 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700498 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700499 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800500 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700501 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700502 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700503 print >>sys.stderr
504 if not syncbuf.Finish():
505 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700506
Doug Anderson2b8db3c2010-11-01 15:08:06 -0700507 # If there's a notice that's supposed to print at the end of the sync, print
508 # it now...
509 if self.manifest.notice:
510 print self.manifest.notice
511
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700512def _PostRepoUpgrade(manifest):
513 for project in manifest.projects.values():
514 if project.Exists:
515 project.PostRepoUpgrade()
516
517def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
518 if rp.HasChanges:
519 print >>sys.stderr, 'info: A new version of repo is available'
520 print >>sys.stderr, ''
521 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700522 syncbuf = SyncBuffer(rp.config)
523 rp.Sync_LocalHalf(syncbuf)
524 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700525 sys.exit(1)
526 print >>sys.stderr, 'info: Restarting repo with latest version'
527 raise RepoChangedException(['--repo-upgraded'])
528 else:
529 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
530 else:
531 if verbose:
532 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
533
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700534def _VerifyTag(project):
535 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
536 if not os.path.exists(gpg_dir):
537 print >>sys.stderr,\
538"""warning: GnuPG was not available during last "repo init"
539warning: Cannot automatically authenticate repo."""
540 return True
541
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700542 try:
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700543 cur = project.bare_git.describe(project.GetRevisionId())
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700544 except GitError:
545 cur = None
546
547 if not cur \
548 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
Shawn O. Pearce3c8dea12009-05-29 18:38:17 -0700549 rev = project.revisionExpr
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700550 if rev.startswith(R_HEADS):
551 rev = rev[len(R_HEADS):]
552
553 print >>sys.stderr
554 print >>sys.stderr,\
555 "warning: project '%s' branch '%s' is not signed" \
556 % (project.name, rev)
557 return False
558
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800559 env = os.environ.copy()
560 env['GIT_DIR'] = project.gitdir.encode()
561 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700562
563 cmd = [GIT, 'tag', '-v', cur]
564 proc = subprocess.Popen(cmd,
565 stdout = subprocess.PIPE,
566 stderr = subprocess.PIPE,
567 env = env)
568 out = proc.stdout.read()
569 proc.stdout.close()
570
571 err = proc.stderr.read()
572 proc.stderr.close()
573
574 if proc.wait() != 0:
575 print >>sys.stderr
576 print >>sys.stderr, out
577 print >>sys.stderr, err
578 print >>sys.stderr
579 return False
580 return True