summaryrefslogtreecommitdiffstats
path: root/subcmds/sync.py
diff options
context:
space:
mode:
Diffstat (limited to 'subcmds/sync.py')
-rw-r--r--subcmds/sync.py84
1 files changed, 54 insertions, 30 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 7ba9ebfc..cda47fdd 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -19,7 +19,6 @@ import netrc
19from optparse import SUPPRESS_HELP 19from optparse import SUPPRESS_HELP
20import os 20import os
21import re 21import re
22import shutil
23import socket 22import socket
24import subprocess 23import subprocess
25import sys 24import sys
@@ -64,6 +63,7 @@ try:
64except ImportError: 63except ImportError:
65 multiprocessing = None 64 multiprocessing = None
66 65
66import event_log
67from git_command import GIT, git_require 67from git_command import GIT, git_require
68from git_config import GetUrlCookieFile 68from git_config import GetUrlCookieFile
69from git_refs import R_HEADS, HEAD 69from git_refs import R_HEADS, HEAD
@@ -72,6 +72,7 @@ from project import Project
72from project import RemoteSpec 72from project import RemoteSpec
73from command import Command, MirrorSafeCommand 73from command import Command, MirrorSafeCommand
74from error import RepoChangedException, GitError, ManifestParseError 74from error import RepoChangedException, GitError, ManifestParseError
75import platform_utils
75from project import SyncBuffer 76from project import SyncBuffer
76from progress import Progress 77from progress import Progress
77from wrapper import Wrapper 78from wrapper import Wrapper
@@ -255,7 +256,7 @@ later is required to fix a server side protocol bug.
255 dest='repo_upgraded', action='store_true', 256 dest='repo_upgraded', action='store_true',
256 help=SUPPRESS_HELP) 257 help=SUPPRESS_HELP)
257 258
258 def _FetchProjectList(self, opt, projects, *args, **kwargs): 259 def _FetchProjectList(self, opt, projects, sem, *args, **kwargs):
259 """Main function of the fetch threads when jobs are > 1. 260 """Main function of the fetch threads when jobs are > 1.
260 261
261 Delegates most of the work to _FetchHelper. 262 Delegates most of the work to _FetchHelper.
@@ -263,15 +264,20 @@ later is required to fix a server side protocol bug.
263 Args: 264 Args:
264 opt: Program options returned from optparse. See _Options(). 265 opt: Program options returned from optparse. See _Options().
265 projects: Projects to fetch. 266 projects: Projects to fetch.
267 sem: We'll release() this semaphore when we exit so that another thread
268 can be started up.
266 *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the 269 *args, **kwargs: Remaining arguments to pass to _FetchHelper. See the
267 _FetchHelper docstring for details. 270 _FetchHelper docstring for details.
268 """ 271 """
269 for project in projects: 272 try:
270 success = self._FetchHelper(opt, project, *args, **kwargs) 273 for project in projects:
271 if not success and not opt.force_broken: 274 success = self._FetchHelper(opt, project, *args, **kwargs)
272 break 275 if not success and not opt.force_broken:
276 break
277 finally:
278 sem.release()
273 279
274 def _FetchHelper(self, opt, project, lock, fetched, pm, sem, err_event): 280 def _FetchHelper(self, opt, project, lock, fetched, pm, err_event):
275 """Fetch git objects for a single project. 281 """Fetch git objects for a single project.
276 282
277 Args: 283 Args:
@@ -283,8 +289,6 @@ later is required to fix a server side protocol bug.
283 (with our lock held). 289 (with our lock held).
284 pm: Instance of a Project object. We will call pm.update() (with our 290 pm: Instance of a Project object. We will call pm.update() (with our
285 lock held). 291 lock held).
286 sem: We'll release() this semaphore when we exit so that another thread
287 can be started up.
288 err_event: We'll set this event in the case of an error (after printing 292 err_event: We'll set this event in the case of an error (after printing
289 out info about the error). 293 out info about the error).
290 294
@@ -301,9 +305,10 @@ later is required to fix a server side protocol bug.
301 # - We always set err_event in the case of an exception. 305 # - We always set err_event in the case of an exception.
302 # - We always make sure we call sem.release(). 306 # - We always make sure we call sem.release().
303 # - We always make sure we unlock the lock if we locked it. 307 # - We always make sure we unlock the lock if we locked it.
308 start = time.time()
309 success = False
304 try: 310 try:
305 try: 311 try:
306 start = time.time()
307 success = project.Sync_NetworkHalf( 312 success = project.Sync_NetworkHalf(
308 quiet=opt.quiet, 313 quiet=opt.quiet,
309 current_branch_only=opt.current_branch_only, 314 current_branch_only=opt.current_branch_only,
@@ -321,7 +326,9 @@ later is required to fix a server side protocol bug.
321 326
322 if not success: 327 if not success:
323 err_event.set() 328 err_event.set()
324 print('error: Cannot fetch %s' % project.name, file=sys.stderr) 329 print('error: Cannot fetch %s from %s'
330 % (project.name, project.remote.url),
331 file=sys.stderr)
325 if opt.force_broken: 332 if opt.force_broken:
326 print('warn: --force-broken, continuing to sync', 333 print('warn: --force-broken, continuing to sync',
327 file=sys.stderr) 334 file=sys.stderr)
@@ -340,14 +347,18 @@ later is required to fix a server side protocol bug.
340 finally: 347 finally:
341 if did_lock: 348 if did_lock:
342 lock.release() 349 lock.release()
343 sem.release() 350 finish = time.time()
351 self.event_log.AddSync(project, event_log.TASK_SYNC_NETWORK,
352 start, finish, success)
344 353
345 return success 354 return success
346 355
347 def _Fetch(self, projects, opt): 356 def _Fetch(self, projects, opt):
348 fetched = set() 357 fetched = set()
349 lock = _threading.Lock() 358 lock = _threading.Lock()
350 pm = Progress('Fetching projects', len(projects)) 359 pm = Progress('Fetching projects', len(projects),
360 print_newline=not(opt.quiet),
361 always_print_percentage=opt.quiet)
351 362
352 objdir_project_map = dict() 363 objdir_project_map = dict()
353 for project in projects: 364 for project in projects:
@@ -365,10 +376,10 @@ later is required to fix a server side protocol bug.
365 sem.acquire() 376 sem.acquire()
366 kwargs = dict(opt=opt, 377 kwargs = dict(opt=opt,
367 projects=project_list, 378 projects=project_list,
379 sem=sem,
368 lock=lock, 380 lock=lock,
369 fetched=fetched, 381 fetched=fetched,
370 pm=pm, 382 pm=pm,
371 sem=sem,
372 err_event=err_event) 383 err_event=err_event)
373 if self.jobs > 1: 384 if self.jobs > 1:
374 t = _threading.Thread(target = self._FetchProjectList, 385 t = _threading.Thread(target = self._FetchProjectList,
@@ -384,7 +395,7 @@ later is required to fix a server side protocol bug.
384 t.join() 395 t.join()
385 396
386 # If we saw an error, exit with code 1 so that other scripts can check. 397 # If we saw an error, exit with code 1 so that other scripts can check.
387 if err_event.isSet(): 398 if err_event.isSet() and not opt.force_broken:
388 print('\nerror: Exited sync due to fetch errors', file=sys.stderr) 399 print('\nerror: Exited sync due to fetch errors', file=sys.stderr)
389 sys.exit(1) 400 sys.exit(1)
390 401
@@ -464,7 +475,7 @@ later is required to fix a server side protocol bug.
464 # working git repository around. There shouldn't be any git projects here, 475 # working git repository around. There shouldn't be any git projects here,
465 # so rmtree works. 476 # so rmtree works.
466 try: 477 try:
467 shutil.rmtree(os.path.join(path, '.git')) 478 platform_utils.rmtree(os.path.join(path, '.git'))
468 except OSError: 479 except OSError:
469 print('Failed to remove %s' % os.path.join(path, '.git'), file=sys.stderr) 480 print('Failed to remove %s' % os.path.join(path, '.git'), file=sys.stderr)
470 print('error: Failed to delete obsolete path %s' % path, file=sys.stderr) 481 print('error: Failed to delete obsolete path %s' % path, file=sys.stderr)
@@ -478,7 +489,7 @@ later is required to fix a server side protocol bug.
478 for root, dirs, files in os.walk(path): 489 for root, dirs, files in os.walk(path):
479 for f in files: 490 for f in files:
480 try: 491 try:
481 os.remove(os.path.join(root, f)) 492 platform_utils.remove(os.path.join(root, f))
482 except OSError: 493 except OSError:
483 print('Failed to remove %s' % os.path.join(root, f), file=sys.stderr) 494 print('Failed to remove %s' % os.path.join(root, f), file=sys.stderr)
484 failed = True 495 failed = True
@@ -487,9 +498,9 @@ later is required to fix a server side protocol bug.
487 dirs_to_remove += [os.path.join(root, d) for d in dirs 498 dirs_to_remove += [os.path.join(root, d) for d in dirs
488 if os.path.join(root, d) not in dirs_to_remove] 499 if os.path.join(root, d) not in dirs_to_remove]
489 for d in reversed(dirs_to_remove): 500 for d in reversed(dirs_to_remove):
490 if os.path.islink(d): 501 if platform_utils.islink(d):
491 try: 502 try:
492 os.remove(d) 503 platform_utils.remove(d)
493 except OSError: 504 except OSError:
494 print('Failed to remove %s' % os.path.join(root, d), file=sys.stderr) 505 print('Failed to remove %s' % os.path.join(root, d), file=sys.stderr)
495 failed = True 506 failed = True
@@ -701,7 +712,7 @@ later is required to fix a server side protocol bug.
701 else: # Not smart sync or smart tag mode 712 else: # Not smart sync or smart tag mode
702 if os.path.isfile(smart_sync_manifest_path): 713 if os.path.isfile(smart_sync_manifest_path):
703 try: 714 try:
704 os.remove(smart_sync_manifest_path) 715 platform_utils.remove(smart_sync_manifest_path)
705 except OSError as e: 716 except OSError as e:
706 print('error: failed to remove existing smart sync override manifest: %s' % 717 print('error: failed to remove existing smart sync override manifest: %s' %
707 e, file=sys.stderr) 718 e, file=sys.stderr)
@@ -716,15 +727,24 @@ later is required to fix a server side protocol bug.
716 _PostRepoUpgrade(self.manifest, quiet=opt.quiet) 727 _PostRepoUpgrade(self.manifest, quiet=opt.quiet)
717 728
718 if not opt.local_only: 729 if not opt.local_only:
719 mp.Sync_NetworkHalf(quiet=opt.quiet, 730 start = time.time()
720 current_branch_only=opt.current_branch_only, 731 success = mp.Sync_NetworkHalf(quiet=opt.quiet,
721 no_tags=opt.no_tags, 732 current_branch_only=opt.current_branch_only,
722 optimized_fetch=opt.optimized_fetch) 733 no_tags=opt.no_tags,
734 optimized_fetch=opt.optimized_fetch,
735 submodules=self.manifest.HasSubmodules)
736 finish = time.time()
737 self.event_log.AddSync(mp, event_log.TASK_SYNC_NETWORK,
738 start, finish, success)
723 739
724 if mp.HasChanges: 740 if mp.HasChanges:
725 syncbuf = SyncBuffer(mp.config) 741 syncbuf = SyncBuffer(mp.config)
726 mp.Sync_LocalHalf(syncbuf) 742 start = time.time()
727 if not syncbuf.Finish(): 743 mp.Sync_LocalHalf(syncbuf, submodules=self.manifest.HasSubmodules)
744 clean = syncbuf.Finish()
745 self.event_log.AddSync(mp, event_log.TASK_SYNC_LOCAL,
746 start, time.time(), clean)
747 if not clean:
728 sys.exit(1) 748 sys.exit(1)
729 self._ReloadManifest(manifest_name) 749 self._ReloadManifest(manifest_name)
730 if opt.jobs is None: 750 if opt.jobs is None:
@@ -761,8 +781,8 @@ later is required to fix a server side protocol bug.
761 # generate a new args list to represent the opened projects. 781 # generate a new args list to represent the opened projects.
762 # TODO: make this more reliable -- if there's a project name/path overlap, 782 # TODO: make this more reliable -- if there's a project name/path overlap,
763 # this may choose the wrong project. 783 # this may choose the wrong project.
764 args = [os.path.relpath(self.manifest.paths[p].worktree, os.getcwd()) 784 args = [os.path.relpath(self.manifest.paths[path].worktree, os.getcwd())
765 for p in opened_projects] 785 for path in opened_projects]
766 if not args: 786 if not args:
767 return 787 return
768 all_projects = self.GetProjects(args, 788 all_projects = self.GetProjects(args,
@@ -818,7 +838,10 @@ later is required to fix a server side protocol bug.
818 for project in all_projects: 838 for project in all_projects:
819 pm.update() 839 pm.update()
820 if project.worktree: 840 if project.worktree:
841 start = time.time()
821 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync) 842 project.Sync_LocalHalf(syncbuf, force_sync=opt.force_sync)
843 self.event_log.AddSync(project, event_log.TASK_SYNC_LOCAL,
844 start, time.time(), syncbuf.Recently())
822 pm.end() 845 pm.end()
823 print(file=sys.stderr) 846 print(file=sys.stderr)
824 if not syncbuf.Finish(): 847 if not syncbuf.Finish():
@@ -902,6 +925,7 @@ def _VerifyTag(project):
902 return False 925 return False
903 return True 926 return True
904 927
928
905class _FetchTimes(object): 929class _FetchTimes(object):
906 _ALPHA = 0.5 930 _ALPHA = 0.5
907 931
@@ -932,7 +956,7 @@ class _FetchTimes(object):
932 f.close() 956 f.close()
933 except (IOError, ValueError): 957 except (IOError, ValueError):
934 try: 958 try:
935 os.remove(self._path) 959 platform_utils.remove(self._path)
936 except OSError: 960 except OSError:
937 pass 961 pass
938 self._times = {} 962 self._times = {}
@@ -956,7 +980,7 @@ class _FetchTimes(object):
956 f.close() 980 f.close()
957 except (IOError, TypeError): 981 except (IOError, TypeError):
958 try: 982 try:
959 os.remove(self._path) 983 platform_utils.remove(self._path)
960 except OSError: 984 except OSError:
961 pass 985 pass
962 986