summaryrefslogtreecommitdiffstats
path: root/subcmds/sync.py
diff options
context:
space:
mode:
Diffstat (limited to 'subcmds/sync.py')
-rw-r--r--subcmds/sync.py323
1 files changed, 181 insertions, 142 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index d4637d0c..228a279a 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -13,6 +13,7 @@
13# See the License for the specific language governing permissions and 13# See the License for the specific language governing permissions and
14# limitations under the License. 14# limitations under the License.
15 15
16from __future__ import print_function
16import netrc 17import netrc
17from optparse import SUPPRESS_HELP 18from optparse import SUPPRESS_HELP
18import os 19import os
@@ -44,13 +45,13 @@ try:
44except ImportError: 45except ImportError:
45 multiprocessing = None 46 multiprocessing = None
46 47
47from git_command import GIT 48from git_command import GIT, git_require
48from git_refs import R_HEADS, HEAD 49from git_refs import R_HEADS, HEAD
49from main import WrapperModule 50from main import WrapperModule
50from project import Project 51from project import Project
51from project import RemoteSpec 52from project import RemoteSpec
52from command import Command, MirrorSafeCommand 53from command import Command, MirrorSafeCommand
53from error import RepoChangedException, GitError 54from error import RepoChangedException, GitError, ManifestParseError
54from project import SyncBuffer 55from project import SyncBuffer
55from progress import Progress 56from progress import Progress
56 57
@@ -113,6 +114,9 @@ resumeable bundle file on a content delivery network. This
113may be necessary if there are problems with the local Python 114may be necessary if there are problems with the local Python
114HTTP client or proxy configuration, but the Git binary works. 115HTTP client or proxy configuration, but the Git binary works.
115 116
117The --fetch-submodules option enables fetching Git submodules
118of a project from server.
119
116SSH Connections 120SSH Connections
117--------------- 121---------------
118 122
@@ -144,27 +148,30 @@ later is required to fix a server side protocol bug.
144""" 148"""
145 149
146 def _Options(self, p, show_smart=True): 150 def _Options(self, p, show_smart=True):
147 self.jobs = self.manifest.default.sync_j 151 try:
152 self.jobs = self.manifest.default.sync_j
153 except ManifestParseError:
154 self.jobs = 1
148 155
149 p.add_option('-f', '--force-broken', 156 p.add_option('-f', '--force-broken',
150 dest='force_broken', action='store_true', 157 dest='force_broken', action='store_true',
151 help="continue sync even if a project fails to sync") 158 help="continue sync even if a project fails to sync")
152 p.add_option('-l','--local-only', 159 p.add_option('-l', '--local-only',
153 dest='local_only', action='store_true', 160 dest='local_only', action='store_true',
154 help="only update working tree, don't fetch") 161 help="only update working tree, don't fetch")
155 p.add_option('-n','--network-only', 162 p.add_option('-n', '--network-only',
156 dest='network_only', action='store_true', 163 dest='network_only', action='store_true',
157 help="fetch only, don't update working tree") 164 help="fetch only, don't update working tree")
158 p.add_option('-d','--detach', 165 p.add_option('-d', '--detach',
159 dest='detach_head', action='store_true', 166 dest='detach_head', action='store_true',
160 help='detach projects back to manifest revision') 167 help='detach projects back to manifest revision')
161 p.add_option('-c','--current-branch', 168 p.add_option('-c', '--current-branch',
162 dest='current_branch_only', action='store_true', 169 dest='current_branch_only', action='store_true',
163 help='fetch only current branch from server') 170 help='fetch only current branch from server')
164 p.add_option('-q','--quiet', 171 p.add_option('-q', '--quiet',
165 dest='quiet', action='store_true', 172 dest='quiet', action='store_true',
166 help='be more quiet') 173 help='be more quiet')
167 p.add_option('-j','--jobs', 174 p.add_option('-j', '--jobs',
168 dest='jobs', action='store', type='int', 175 dest='jobs', action='store', type='int',
169 help="projects to fetch simultaneously (default %d)" % self.jobs) 176 help="projects to fetch simultaneously (default %d)" % self.jobs)
170 p.add_option('-m', '--manifest-name', 177 p.add_option('-m', '--manifest-name',
@@ -173,6 +180,15 @@ later is required to fix a server side protocol bug.
173 p.add_option('--no-clone-bundle', 180 p.add_option('--no-clone-bundle',
174 dest='no_clone_bundle', action='store_true', 181 dest='no_clone_bundle', action='store_true',
175 help='disable use of /clone.bundle on HTTP/HTTPS') 182 help='disable use of /clone.bundle on HTTP/HTTPS')
183 p.add_option('-u', '--manifest-server-username', action='store',
184 dest='manifest_server_username',
185 help='username to authenticate with the manifest server')
186 p.add_option('-p', '--manifest-server-password', action='store',
187 dest='manifest_server_password',
188 help='password to authenticate with the manifest server')
189 p.add_option('--fetch-submodules',
190 dest='fetch_submodules', action='store_true',
191 help='fetch submodules from server')
176 if show_smart: 192 if show_smart:
177 p.add_option('-s', '--smart-sync', 193 p.add_option('-s', '--smart-sync',
178 dest='smart_sync', action='store_true', 194 dest='smart_sync', action='store_true',
@@ -180,12 +196,6 @@ later is required to fix a server side protocol bug.
180 p.add_option('-t', '--smart-tag', 196 p.add_option('-t', '--smart-tag',
181 dest='smart_tag', action='store', 197 dest='smart_tag', action='store',
182 help='smart sync using manifest from a known tag') 198 help='smart sync using manifest from a known tag')
183 p.add_option('-u', '--manifest-server-username', action='store',
184 dest='manifest_server_username',
185 help='username to authenticate with the manifest server')
186 p.add_option('-p', '--manifest-server-password', action='store',
187 dest='manifest_server_password',
188 help='password to authenticate with the manifest server')
189 199
190 g = p.add_option_group('repo Version options') 200 g = p.add_option_group('repo Version options')
191 g.add_option('--no-repo-verify', 201 g.add_option('--no-repo-verify',
@@ -196,61 +206,62 @@ later is required to fix a server side protocol bug.
196 help=SUPPRESS_HELP) 206 help=SUPPRESS_HELP)
197 207
198 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event): 208 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event):
199 """Main function of the fetch threads when jobs are > 1. 209 """Main function of the fetch threads when jobs are > 1.
200 210
201 Args: 211 Args:
202 opt: Program options returned from optparse. See _Options(). 212 opt: Program options returned from optparse. See _Options().
203 project: Project object for the project to fetch. 213 project: Project object for the project to fetch.
204 lock: Lock for accessing objects that are shared amongst multiple 214 lock: Lock for accessing objects that are shared amongst multiple
205 _FetchHelper() threads. 215 _FetchHelper() threads.
206 fetched: set object that we will add project.gitdir to when we're done 216 fetched: set object that we will add project.gitdir to when we're done
207 (with our lock held). 217 (with our lock held).
208 pm: Instance of a Project object. We will call pm.update() (with our 218 pm: Instance of a Project object. We will call pm.update() (with our
209 lock held). 219 lock held).
210 sem: We'll release() this semaphore when we exit so that another thread 220 sem: We'll release() this semaphore when we exit so that another thread
211 can be started up. 221 can be started up.
212 err_event: We'll set this event in the case of an error (after printing 222 err_event: We'll set this event in the case of an error (after printing
213 out info about the error). 223 out info about the error).
214 """ 224 """
215 # We'll set to true once we've locked the lock. 225 # We'll set to true once we've locked the lock.
216 did_lock = False 226 did_lock = False
217 227
218 # Encapsulate everything in a try/except/finally so that: 228 # Encapsulate everything in a try/except/finally so that:
219 # - We always set err_event in the case of an exception. 229 # - We always set err_event in the case of an exception.
220 # - We always make sure we call sem.release(). 230 # - We always make sure we call sem.release().
221 # - We always make sure we unlock the lock if we locked it. 231 # - We always make sure we unlock the lock if we locked it.
232 try:
222 try: 233 try:
223 try: 234 start = time.time()
224 start = time.time() 235 success = project.Sync_NetworkHalf(
225 success = project.Sync_NetworkHalf( 236 quiet=opt.quiet,
226 quiet=opt.quiet, 237 current_branch_only=opt.current_branch_only,
227 current_branch_only=opt.current_branch_only, 238 clone_bundle=not opt.no_clone_bundle)
228 clone_bundle=not opt.no_clone_bundle) 239 self._fetch_times.Set(project, time.time() - start)
229 self._fetch_times.Set(project, time.time() - start) 240
230 241 # Lock around all the rest of the code, since printing, updating a set
231 # Lock around all the rest of the code, since printing, updating a set 242 # and Progress.update() are not thread safe.
232 # and Progress.update() are not thread safe. 243 lock.acquire()
233 lock.acquire() 244 did_lock = True
234 did_lock = True 245
235 246 if not success:
236 if not success: 247 print('error: Cannot fetch %s' % project.name, file=sys.stderr)
237 print >>sys.stderr, 'error: Cannot fetch %s' % project.name 248 if opt.force_broken:
238 if opt.force_broken: 249 print('warn: --force-broken, continuing to sync',
239 print >>sys.stderr, 'warn: --force-broken, continuing to sync' 250 file=sys.stderr)
240 else: 251 else:
241 raise _FetchError() 252 raise _FetchError()
242 253
243 fetched.add(project.gitdir) 254 fetched.add(project.gitdir)
244 pm.update() 255 pm.update()
245 except _FetchError: 256 except _FetchError:
246 err_event.set() 257 err_event.set()
247 except: 258 except:
248 err_event.set() 259 err_event.set()
249 raise 260 raise
250 finally: 261 finally:
251 if did_lock: 262 if did_lock:
252 lock.release() 263 lock.release()
253 sem.release() 264 sem.release()
254 265
255 def _Fetch(self, projects, opt): 266 def _Fetch(self, projects, opt):
256 fetched = set() 267 fetched = set()
@@ -265,9 +276,9 @@ later is required to fix a server side protocol bug.
265 clone_bundle=not opt.no_clone_bundle): 276 clone_bundle=not opt.no_clone_bundle):
266 fetched.add(project.gitdir) 277 fetched.add(project.gitdir)
267 else: 278 else:
268 print >>sys.stderr, 'error: Cannot fetch %s' % project.name 279 print('error: Cannot fetch %s' % project.name, file=sys.stderr)
269 if opt.force_broken: 280 if opt.force_broken:
270 print >>sys.stderr, 'warn: --force-broken, continuing to sync' 281 print('warn: --force-broken, continuing to sync', file=sys.stderr)
271 else: 282 else:
272 sys.exit(1) 283 sys.exit(1)
273 else: 284 else:
@@ -300,7 +311,7 @@ later is required to fix a server side protocol bug.
300 311
301 # If we saw an error, exit with code 1 so that other scripts can check. 312 # If we saw an error, exit with code 1 so that other scripts can check.
302 if err_event.isSet(): 313 if err_event.isSet():
303 print >>sys.stderr, '\nerror: Exited sync due to fetch errors' 314 print('\nerror: Exited sync due to fetch errors', file=sys.stderr)
304 sys.exit(1) 315 sys.exit(1)
305 316
306 pm.end() 317 pm.end()
@@ -310,7 +321,8 @@ later is required to fix a server side protocol bug.
310 return fetched 321 return fetched
311 322
312 def _GCProjects(self, projects): 323 def _GCProjects(self, projects):
313 if multiprocessing: 324 has_dash_c = git_require((1, 7, 2))
325 if multiprocessing and has_dash_c:
314 cpu_count = multiprocessing.cpu_count() 326 cpu_count = multiprocessing.cpu_count()
315 else: 327 else:
316 cpu_count = 1 328 cpu_count = 1
@@ -352,7 +364,7 @@ later is required to fix a server side protocol bug.
352 t.join() 364 t.join()
353 365
354 if err_event.isSet(): 366 if err_event.isSet():
355 print >>sys.stderr, '\nerror: Exited sync due to gc errors' 367 print('\nerror: Exited sync due to gc errors', file=sys.stderr)
356 sys.exit(1) 368 sys.exit(1)
357 369
358 def UpdateProjectList(self): 370 def UpdateProjectList(self):
@@ -376,34 +388,36 @@ later is required to fix a server side protocol bug.
376 if path not in new_project_paths: 388 if path not in new_project_paths:
377 # If the path has already been deleted, we don't need to do it 389 # If the path has already been deleted, we don't need to do it
378 if os.path.exists(self.manifest.topdir + '/' + path): 390 if os.path.exists(self.manifest.topdir + '/' + path):
379 project = Project( 391 project = Project(
380 manifest = self.manifest, 392 manifest = self.manifest,
381 name = path, 393 name = path,
382 remote = RemoteSpec('origin'), 394 remote = RemoteSpec('origin'),
383 gitdir = os.path.join(self.manifest.topdir, 395 gitdir = os.path.join(self.manifest.topdir,
384 path, '.git'), 396 path, '.git'),
385 worktree = os.path.join(self.manifest.topdir, path), 397 worktree = os.path.join(self.manifest.topdir, path),
386 relpath = path, 398 relpath = path,
387 revisionExpr = 'HEAD', 399 revisionExpr = 'HEAD',
388 revisionId = None, 400 revisionId = None,
389 groups = None) 401 groups = None)
390 402
391 if project.IsDirty(): 403 if project.IsDirty():
392 print >>sys.stderr, 'error: Cannot remove project "%s": \ 404 print('error: Cannot remove project "%s": uncommitted changes'
393uncommitted changes are present' % project.relpath 405 'are present' % project.relpath, file=sys.stderr)
394 print >>sys.stderr, ' commit changes, then run sync again' 406 print(' commit changes, then run sync again',
395 return -1 407 file=sys.stderr)
396 else: 408 return -1
397 print >>sys.stderr, 'Deleting obsolete path %s' % project.worktree 409 else:
398 shutil.rmtree(project.worktree) 410 print('Deleting obsolete path %s' % project.worktree,
399 # Try deleting parent subdirs if they are empty 411 file=sys.stderr)
400 project_dir = os.path.dirname(project.worktree) 412 shutil.rmtree(project.worktree)
401 while project_dir != self.manifest.topdir: 413 # Try deleting parent subdirs if they are empty
402 try: 414 project_dir = os.path.dirname(project.worktree)
403 os.rmdir(project_dir) 415 while project_dir != self.manifest.topdir:
404 except OSError: 416 try:
405 break 417 os.rmdir(project_dir)
406 project_dir = os.path.dirname(project_dir) 418 except OSError:
419 break
420 project_dir = os.path.dirname(project_dir)
407 421
408 new_project_paths.sort() 422 new_project_paths.sort()
409 fd = open(file_path, 'w') 423 fd = open(file_path, 'w')
@@ -422,24 +436,24 @@ uncommitted changes are present' % project.relpath
422 self.jobs = min(self.jobs, (soft_limit - 5) / 3) 436 self.jobs = min(self.jobs, (soft_limit - 5) / 3)
423 437
424 if opt.network_only and opt.detach_head: 438 if opt.network_only and opt.detach_head:
425 print >>sys.stderr, 'error: cannot combine -n and -d' 439 print('error: cannot combine -n and -d', file=sys.stderr)
426 sys.exit(1) 440 sys.exit(1)
427 if opt.network_only and opt.local_only: 441 if opt.network_only and opt.local_only:
428 print >>sys.stderr, 'error: cannot combine -n and -l' 442 print('error: cannot combine -n and -l', file=sys.stderr)
429 sys.exit(1) 443 sys.exit(1)
430 if opt.manifest_name and opt.smart_sync: 444 if opt.manifest_name and opt.smart_sync:
431 print >>sys.stderr, 'error: cannot combine -m and -s' 445 print('error: cannot combine -m and -s', file=sys.stderr)
432 sys.exit(1) 446 sys.exit(1)
433 if opt.manifest_name and opt.smart_tag: 447 if opt.manifest_name and opt.smart_tag:
434 print >>sys.stderr, 'error: cannot combine -m and -t' 448 print('error: cannot combine -m and -t', file=sys.stderr)
435 sys.exit(1) 449 sys.exit(1)
436 if opt.manifest_server_username or opt.manifest_server_password: 450 if opt.manifest_server_username or opt.manifest_server_password:
437 if not (opt.smart_sync or opt.smart_tag): 451 if not (opt.smart_sync or opt.smart_tag):
438 print >>sys.stderr, 'error: -u and -p may only be combined with ' \ 452 print('error: -u and -p may only be combined with -s or -t',
439 '-s or -t' 453 file=sys.stderr)
440 sys.exit(1) 454 sys.exit(1)
441 if None in [opt.manifest_server_username, opt.manifest_server_password]: 455 if None in [opt.manifest_server_username, opt.manifest_server_password]:
442 print >>sys.stderr, 'error: both -u and -p must be given' 456 print('error: both -u and -p must be given', file=sys.stderr)
443 sys.exit(1) 457 sys.exit(1)
444 458
445 if opt.manifest_name: 459 if opt.manifest_name:
@@ -447,8 +461,8 @@ uncommitted changes are present' % project.relpath
447 461
448 if opt.smart_sync or opt.smart_tag: 462 if opt.smart_sync or opt.smart_tag:
449 if not self.manifest.manifest_server: 463 if not self.manifest.manifest_server:
450 print >>sys.stderr, \ 464 print('error: cannot smart sync: no manifest server defined in'
451 'error: cannot smart sync: no manifest server defined in manifest' 465 'manifest', file=sys.stderr)
452 sys.exit(1) 466 sys.exit(1)
453 467
454 manifest_server = self.manifest.manifest_server 468 manifest_server = self.manifest.manifest_server
@@ -463,7 +477,8 @@ uncommitted changes are present' % project.relpath
463 try: 477 try:
464 info = netrc.netrc() 478 info = netrc.netrc()
465 except IOError: 479 except IOError:
466 print >>sys.stderr, '.netrc file does not exist or could not be opened' 480 print('.netrc file does not exist or could not be opened',
481 file=sys.stderr)
467 else: 482 else:
468 try: 483 try:
469 parse_result = urlparse.urlparse(manifest_server) 484 parse_result = urlparse.urlparse(manifest_server)
@@ -473,10 +488,10 @@ uncommitted changes are present' % project.relpath
473 except TypeError: 488 except TypeError:
474 # TypeError is raised when the given hostname is not present 489 # TypeError is raised when the given hostname is not present
475 # in the .netrc file. 490 # in the .netrc file.
476 print >>sys.stderr, 'No credentials found for %s in .netrc' % \ 491 print('No credentials found for %s in .netrc'
477 parse_result.hostname 492 % parse_result.hostname, file=sys.stderr)
478 except netrc.NetrcParseError as e: 493 except netrc.NetrcParseError as e:
479 print >>sys.stderr, 'Error parsing .netrc file: %s' % e 494 print('Error parsing .netrc file: %s' % e, file=sys.stderr)
480 495
481 if (username and password): 496 if (username and password):
482 manifest_server = manifest_server.replace('://', '://%s:%s@' % 497 manifest_server = manifest_server.replace('://', '://%s:%s@' %
@@ -515,20 +530,21 @@ uncommitted changes are present' % project.relpath
515 finally: 530 finally:
516 f.close() 531 f.close()
517 except IOError: 532 except IOError:
518 print >>sys.stderr, 'error: cannot write manifest to %s' % \ 533 print('error: cannot write manifest to %s' % manifest_path,
519 manifest_path 534 file=sys.stderr)
520 sys.exit(1) 535 sys.exit(1)
521 self.manifest.Override(manifest_name) 536 self.manifest.Override(manifest_name)
522 else: 537 else:
523 print >>sys.stderr, 'error: %s' % manifest_str 538 print('error: %s' % manifest_str, file=sys.stderr)
524 sys.exit(1) 539 sys.exit(1)
525 except (socket.error, IOError, xmlrpclib.Fault) as e: 540 except (socket.error, IOError, xmlrpclib.Fault) as e:
526 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%s' % ( 541 print('error: cannot connect to manifest server %s:\n%s'
527 self.manifest.manifest_server, e) 542 % (self.manifest.manifest_server, e), file=sys.stderr)
528 sys.exit(1) 543 sys.exit(1)
529 except xmlrpclib.ProtocolError as e: 544 except xmlrpclib.ProtocolError as e:
530 print >>sys.stderr, 'error: cannot connect to manifest server %s:\n%d %s' % ( 545 print('error: cannot connect to manifest server %s:\n%d %s'
531 self.manifest.manifest_server, e.errcode, e.errmsg) 546 % (self.manifest.manifest_server, e.errcode, e.errmsg),
547 file=sys.stderr)
532 sys.exit(1) 548 sys.exit(1)
533 549
534 rp = self.manifest.repoProject 550 rp = self.manifest.repoProject
@@ -552,7 +568,9 @@ uncommitted changes are present' % project.relpath
552 self.manifest._Unload() 568 self.manifest._Unload()
553 if opt.jobs is None: 569 if opt.jobs is None:
554 self.jobs = self.manifest.default.sync_j 570 self.jobs = self.manifest.default.sync_j
555 all_projects = self.GetProjects(args, missing_ok=True) 571 all_projects = self.GetProjects(args,
572 missing_ok=True,
573 submodules_ok=opt.fetch_submodules)
556 574
557 self._fetch_times = _FetchTimes(self.manifest) 575 self._fetch_times = _FetchTimes(self.manifest)
558 if not opt.local_only: 576 if not opt.local_only:
@@ -563,12 +581,33 @@ uncommitted changes are present' % project.relpath
563 to_fetch.extend(all_projects) 581 to_fetch.extend(all_projects)
564 to_fetch.sort(key=self._fetch_times.Get, reverse=True) 582 to_fetch.sort(key=self._fetch_times.Get, reverse=True)
565 583
566 self._Fetch(to_fetch, opt) 584 fetched = self._Fetch(to_fetch, opt)
567 _PostRepoFetch(rp, opt.no_repo_verify) 585 _PostRepoFetch(rp, opt.no_repo_verify)
568 if opt.network_only: 586 if opt.network_only:
569 # bail out now; the rest touches the working tree 587 # bail out now; the rest touches the working tree
570 return 588 return
571 589
590 # Iteratively fetch missing and/or nested unregistered submodules
591 previously_missing_set = set()
592 while True:
593 self.manifest._Unload()
594 all_projects = self.GetProjects(args,
595 missing_ok=True,
596 submodules_ok=opt.fetch_submodules)
597 missing = []
598 for project in all_projects:
599 if project.gitdir not in fetched:
600 missing.append(project)
601 if not missing:
602 break
603 # Stop us from non-stopped fetching actually-missing repos: If set of
604 # missing repos has not been changed from last fetch, we break.
605 missing_set = set(p.name for p in missing)
606 if previously_missing_set == missing_set:
607 break
608 previously_missing_set = missing_set
609 fetched.update(self._Fetch(missing, opt))
610
572 if self.manifest.IsMirror: 611 if self.manifest.IsMirror:
573 # bail out now, we have no working tree 612 # bail out now, we have no working tree
574 return 613 return
@@ -584,14 +623,14 @@ uncommitted changes are present' % project.relpath
584 if project.worktree: 623 if project.worktree:
585 project.Sync_LocalHalf(syncbuf) 624 project.Sync_LocalHalf(syncbuf)
586 pm.end() 625 pm.end()
587 print >>sys.stderr 626 print(file=sys.stderr)
588 if not syncbuf.Finish(): 627 if not syncbuf.Finish():
589 sys.exit(1) 628 sys.exit(1)
590 629
591 # If there's a notice that's supposed to print at the end of the sync, print 630 # If there's a notice that's supposed to print at the end of the sync, print
592 # it now... 631 # it now...
593 if self.manifest.notice: 632 if self.manifest.notice:
594 print self.manifest.notice 633 print(self.manifest.notice)
595 634
596def _PostRepoUpgrade(manifest, quiet=False): 635def _PostRepoUpgrade(manifest, quiet=False):
597 wrapper = WrapperModule() 636 wrapper = WrapperModule()
@@ -603,27 +642,28 @@ def _PostRepoUpgrade(manifest, quiet=False):
603 642
604def _PostRepoFetch(rp, no_repo_verify=False, verbose=False): 643def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
605 if rp.HasChanges: 644 if rp.HasChanges:
606 print >>sys.stderr, 'info: A new version of repo is available' 645 print('info: A new version of repo is available', file=sys.stderr)
607 print >>sys.stderr, '' 646 print(file=sys.stderr)
608 if no_repo_verify or _VerifyTag(rp): 647 if no_repo_verify or _VerifyTag(rp):
609 syncbuf = SyncBuffer(rp.config) 648 syncbuf = SyncBuffer(rp.config)
610 rp.Sync_LocalHalf(syncbuf) 649 rp.Sync_LocalHalf(syncbuf)
611 if not syncbuf.Finish(): 650 if not syncbuf.Finish():
612 sys.exit(1) 651 sys.exit(1)
613 print >>sys.stderr, 'info: Restarting repo with latest version' 652 print('info: Restarting repo with latest version', file=sys.stderr)
614 raise RepoChangedException(['--repo-upgraded']) 653 raise RepoChangedException(['--repo-upgraded'])
615 else: 654 else:
616 print >>sys.stderr, 'warning: Skipped upgrade to unverified version' 655 print('warning: Skipped upgrade to unverified version', file=sys.stderr)
617 else: 656 else:
618 if verbose: 657 if verbose:
619 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD) 658 print('repo version %s is current' % rp.work_git.describe(HEAD),
659 file=sys.stderr)
620 660
621def _VerifyTag(project): 661def _VerifyTag(project):
622 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg') 662 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
623 if not os.path.exists(gpg_dir): 663 if not os.path.exists(gpg_dir):
624 print >>sys.stderr,\ 664 print('warning: GnuPG was not available during last "repo init"\n'
625"""warning: GnuPG was not available during last "repo init" 665 'warning: Cannot automatically authenticate repo."""',
626warning: Cannot automatically authenticate repo.""" 666 file=sys.stderr)
627 return True 667 return True
628 668
629 try: 669 try:
@@ -637,10 +677,9 @@ warning: Cannot automatically authenticate repo."""
637 if rev.startswith(R_HEADS): 677 if rev.startswith(R_HEADS):
638 rev = rev[len(R_HEADS):] 678 rev = rev[len(R_HEADS):]
639 679
640 print >>sys.stderr 680 print(file=sys.stderr)
641 print >>sys.stderr,\ 681 print("warning: project '%s' branch '%s' is not signed"
642 "warning: project '%s' branch '%s' is not signed" \ 682 % (project.name, rev), file=sys.stderr)
643 % (project.name, rev)
644 return False 683 return False
645 684
646 env = os.environ.copy() 685 env = os.environ.copy()
@@ -659,10 +698,10 @@ warning: Cannot automatically authenticate repo."""
659 proc.stderr.close() 698 proc.stderr.close()
660 699
661 if proc.wait() != 0: 700 if proc.wait() != 0:
662 print >>sys.stderr 701 print(file=sys.stderr)
663 print >>sys.stderr, out 702 print(out, file=sys.stderr)
664 print >>sys.stderr, err 703 print(err, file=sys.stderr)
665 print >>sys.stderr 704 print(file=sys.stderr)
666 return False 705 return False
667 return True 706 return True
668 707
@@ -696,7 +735,7 @@ class _FetchTimes(object):
696 try: 735 try:
697 try: 736 try:
698 self._times = pickle.load(f) 737 self._times = pickle.load(f)
699 except: 738 except IOError:
700 try: 739 try:
701 os.remove(self._path) 740 os.remove(self._path)
702 except OSError: 741 except OSError: