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 | ||
