diff options
| author | Mike Frysinger <vapier@google.com> | 2020-02-19 19:19:18 -0500 |
|---|---|---|
| committer | Mike Frysinger <vapier@google.com> | 2020-02-20 00:51:42 +0000 |
| commit | c0d1866b35d3e8d0bee3760a9f52574fa2ab8491 (patch) | |
| tree | c6be761e1dbf5e93dfe499e8f53d90386a2d6769 /subcmds | |
| parent | f81c72ed7727ca408d1859a86c56b532a8de8d59 (diff) | |
| download | git-repo-c0d1866b35d3e8d0bee3760a9f52574fa2ab8491.tar.gz | |
project/sync: move DeleteProject helper to Project
Since deleting a source checkout involves a good bit of internal
knowledge of .repo/, move the DeleteProject helper out of the sync
code and into the Project class itself. This allows us to add git
worktree support to it so we can unlock/unlink project checkouts.
Change-Id: If9af8bd4a9c7e29743827d8166bc3db81547ca50
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/256072
Reviewed-by: Jonathan Nieder <jrn@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
Diffstat (limited to 'subcmds')
| -rw-r--r-- | subcmds/sync.py | 85 |
1 files changed, 4 insertions, 81 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py index eada76a7..f2af0ec3 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
| @@ -16,7 +16,6 @@ | |||
| 16 | 16 | ||
| 17 | from __future__ import print_function | 17 | from __future__ import print_function |
| 18 | 18 | ||
| 19 | import errno | ||
| 20 | import json | 19 | import json |
| 21 | import netrc | 20 | import netrc |
| 22 | from optparse import SUPPRESS_HELP | 21 | from optparse import SUPPRESS_HELP |
| @@ -633,74 +632,6 @@ later is required to fix a server side protocol bug. | |||
| 633 | else: | 632 | else: |
| 634 | self.manifest._Unload() | 633 | self.manifest._Unload() |
| 635 | 634 | ||
| 636 | def _DeleteProject(self, path): | ||
| 637 | print('Deleting obsolete path %s' % path, file=sys.stderr) | ||
| 638 | |||
| 639 | # Delete the .git directory first, so we're less likely to have a partially | ||
| 640 | # working git repository around. There shouldn't be any git projects here, | ||
| 641 | # so rmtree works. | ||
| 642 | dotgit = os.path.join(path, '.git') | ||
| 643 | # Try to remove plain files first in case of git worktrees. If this fails | ||
| 644 | # for any reason, we'll fall back to rmtree, and that'll display errors if | ||
| 645 | # it can't remove things either. | ||
| 646 | try: | ||
| 647 | platform_utils.remove(dotgit) | ||
| 648 | except OSError: | ||
| 649 | pass | ||
| 650 | try: | ||
| 651 | platform_utils.rmtree(dotgit) | ||
| 652 | except OSError as e: | ||
| 653 | if e.errno != errno.ENOENT: | ||
| 654 | print('error: %s: %s' % (dotgit, str(e)), file=sys.stderr) | ||
| 655 | print('error: %s: Failed to delete obsolete path; remove manually, then ' | ||
| 656 | 'run sync again' % (path,), file=sys.stderr) | ||
| 657 | return 1 | ||
| 658 | |||
| 659 | # Delete everything under the worktree, except for directories that contain | ||
| 660 | # another git project | ||
| 661 | dirs_to_remove = [] | ||
| 662 | failed = False | ||
| 663 | for root, dirs, files in platform_utils.walk(path): | ||
| 664 | for f in files: | ||
| 665 | try: | ||
| 666 | platform_utils.remove(os.path.join(root, f)) | ||
| 667 | except OSError as e: | ||
| 668 | print('Failed to remove %s (%s)' % (os.path.join(root, f), str(e)), file=sys.stderr) | ||
| 669 | failed = True | ||
| 670 | dirs[:] = [d for d in dirs | ||
| 671 | if not os.path.lexists(os.path.join(root, d, '.git'))] | ||
| 672 | dirs_to_remove += [os.path.join(root, d) for d in dirs | ||
| 673 | if os.path.join(root, d) not in dirs_to_remove] | ||
| 674 | for d in reversed(dirs_to_remove): | ||
| 675 | if platform_utils.islink(d): | ||
| 676 | try: | ||
| 677 | platform_utils.remove(d) | ||
| 678 | except OSError as e: | ||
| 679 | print('Failed to remove %s (%s)' % (os.path.join(root, d), str(e)), file=sys.stderr) | ||
| 680 | failed = True | ||
| 681 | elif len(platform_utils.listdir(d)) == 0: | ||
| 682 | try: | ||
| 683 | platform_utils.rmdir(d) | ||
| 684 | except OSError as e: | ||
| 685 | print('Failed to remove %s (%s)' % (os.path.join(root, d), str(e)), file=sys.stderr) | ||
| 686 | failed = True | ||
| 687 | continue | ||
| 688 | if failed: | ||
| 689 | print('error: Failed to delete obsolete path %s' % path, file=sys.stderr) | ||
| 690 | print(' remove manually, then run sync again', file=sys.stderr) | ||
| 691 | return 1 | ||
| 692 | |||
| 693 | # Try deleting parent dirs if they are empty | ||
| 694 | project_dir = path | ||
| 695 | while project_dir != self.manifest.topdir: | ||
| 696 | if len(platform_utils.listdir(project_dir)) == 0: | ||
| 697 | platform_utils.rmdir(project_dir) | ||
| 698 | else: | ||
| 699 | break | ||
| 700 | project_dir = os.path.dirname(project_dir) | ||
| 701 | |||
| 702 | return 0 | ||
| 703 | |||
| 704 | def UpdateProjectList(self, opt): | 635 | def UpdateProjectList(self, opt): |
| 705 | new_project_paths = [] | 636 | new_project_paths = [] |
| 706 | for project in self.GetProjects(None, missing_ok=True): | 637 | for project in self.GetProjects(None, missing_ok=True): |
| @@ -727,23 +658,15 @@ later is required to fix a server side protocol bug. | |||
| 727 | remote=RemoteSpec('origin'), | 658 | remote=RemoteSpec('origin'), |
| 728 | gitdir=gitdir, | 659 | gitdir=gitdir, |
| 729 | objdir=gitdir, | 660 | objdir=gitdir, |
| 661 | use_git_worktrees=os.path.isfile(gitdir), | ||
| 730 | worktree=os.path.join(self.manifest.topdir, path), | 662 | worktree=os.path.join(self.manifest.topdir, path), |
| 731 | relpath=path, | 663 | relpath=path, |
| 732 | revisionExpr='HEAD', | 664 | revisionExpr='HEAD', |
| 733 | revisionId=None, | 665 | revisionId=None, |
| 734 | groups=None) | 666 | groups=None) |
| 735 | 667 | if not project.DeleteWorktree( | |
| 736 | if project.IsDirty() and opt.force_remove_dirty: | 668 | quiet=opt.quiet, |
| 737 | print('WARNING: Removing dirty project "%s": uncommitted changes ' | 669 | force=opt.force_remove_dirty): |
| 738 | 'erased' % project.relpath, file=sys.stderr) | ||
| 739 | self._DeleteProject(project.worktree) | ||
| 740 | elif project.IsDirty(): | ||
| 741 | print('error: Cannot remove project "%s": uncommitted changes ' | ||
| 742 | 'are present' % project.relpath, file=sys.stderr) | ||
| 743 | print(' commit changes, then run sync again', | ||
| 744 | file=sys.stderr) | ||
| 745 | return 1 | ||
| 746 | elif self._DeleteProject(project.worktree): | ||
| 747 | return 1 | 670 | return 1 |
| 748 | 671 | ||
| 749 | new_project_paths.sort() | 672 | new_project_paths.sort() |
