diff options
Diffstat (limited to 'subcmds/sync.py')
-rw-r--r-- | subcmds/sync.py | 84 |
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 | |||
19 | from optparse import SUPPRESS_HELP | 19 | from optparse import SUPPRESS_HELP |
20 | import os | 20 | import os |
21 | import re | 21 | import re |
22 | import shutil | ||
23 | import socket | 22 | import socket |
24 | import subprocess | 23 | import subprocess |
25 | import sys | 24 | import sys |
@@ -64,6 +63,7 @@ try: | |||
64 | except ImportError: | 63 | except ImportError: |
65 | multiprocessing = None | 64 | multiprocessing = None |
66 | 65 | ||
66 | import event_log | ||
67 | from git_command import GIT, git_require | 67 | from git_command import GIT, git_require |
68 | from git_config import GetUrlCookieFile | 68 | from git_config import GetUrlCookieFile |
69 | from git_refs import R_HEADS, HEAD | 69 | from git_refs import R_HEADS, HEAD |
@@ -72,6 +72,7 @@ from project import Project | |||
72 | from project import RemoteSpec | 72 | from project import RemoteSpec |
73 | from command import Command, MirrorSafeCommand | 73 | from command import Command, MirrorSafeCommand |
74 | from error import RepoChangedException, GitError, ManifestParseError | 74 | from error import RepoChangedException, GitError, ManifestParseError |
75 | import platform_utils | ||
75 | from project import SyncBuffer | 76 | from project import SyncBuffer |
76 | from progress import Progress | 77 | from progress import Progress |
77 | from wrapper import Wrapper | 78 | from 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 | |||
905 | class _FetchTimes(object): | 929 | class _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 | ||