From 4843db2ad383ce3b5179175562130bfef0de3745 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 9 Dec 2022 10:49:29 -0500 Subject: [PATCH 1/7] Add new reset command --- CHANGELOG.md | 6 +++ mepo.d/cmdline/parser.py | 19 ++++++++ mepo.d/command/reset/reset.py | 87 +++++++++++++++++++++++++++++++++++ mepo.d/state/exceptions.py | 4 ++ 4 files changed, 116 insertions(+) create mode 100644 mepo.d/command/reset/reset.py diff --git a/CHANGELOG.md b/CHANGELOG.md index eef1fd6..6016631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [1.48.0] - 2022-12-09 + +### Added + +- Added new `reset` command to reset a mepo clone + ## [1.47.0] - 2022-11-14 ### Added diff --git a/mepo.d/cmdline/parser.py b/mepo.d/cmdline/parser.py index 48936a3..68d24d3 100644 --- a/mepo.d/cmdline/parser.py +++ b/mepo.d/cmdline/parser.py @@ -36,6 +36,7 @@ def parse(self): self.__pull() self.__pull_all() self.__compare() + self.__reset() self.__whereis() self.__stage() self.__unstage() @@ -336,6 +337,24 @@ def __compare(self): action = 'store_true', help = 'Tells command to ignore terminal size and wrap') + def __reset(self): + reset = self.subparsers.add_parser( + 'reset', + description = 'Reset the current mepo clone to the original state. Must be run in the root of the mepo clone.', + aliases=mepoconfig.get_command_alias('reset')) + reset.add_argument( + '-f','--force', + action = 'store_true', + help = 'Force action.') + reset.add_argument( + '--reclone', + action = 'store_true', + help = 'Reclone repos after reset.') + reset.add_argument( + '-n','--dry-run', + action = 'store_true', + help = 'Dry-run only') + def __whereis(self): whereis = self.subparsers.add_parser( 'whereis', diff --git a/mepo.d/command/reset/reset.py b/mepo.d/command/reset/reset.py new file mode 100644 index 0000000..fb9a57c --- /dev/null +++ b/mepo.d/command/reset/reset.py @@ -0,0 +1,87 @@ +import os +import shutil + +from state.state import MepoState +from state.exceptions import NotInRootDirError + +from command.clone import clone as mepo_clone + +# This command will "reset" the mepo clone. This will delete all +# the subrepos, remove the .mepo directory, and then re-clone all the +# subrepos. This is useful if you want to start over with a fresh clone +# of the project. + +def run(args): + # If a user has called this command without the force flag, we + # will ask them to confirm that they want to reset the project + if not args.force and not args.dry_run: + print(f"Are you sure you want to reset the project? If so, type 'yes' and press enter.", end=' ') + answer = input() + if answer != "yes": + print("Reset cancelled.") + return + + allcomps = MepoState.read_state() + + # Check to see that we are in the root directory of the project + ## First get the root directory of the project + rootdir = MepoState.get_root_dir() + ## Then get the current directory + curdir = os.getcwd() + ## Then check that they are the same, if they are not, then throw a NotInRootDirError + if rootdir != curdir: + raise NotInRootDirError('Error! As a safety precaution, you must be in the root directory of the project to reset') + + # If we get this far, then we are in the root directory of the project + + # First, we need to delete all the subrepos + # Loop over all the components in reverse (since we are deleting them) + for comp in reversed(allcomps): + # If the component is the Fixture, then skip it + if comp.fixture: + continue + else: + # Get the relative path to the component + relpath = _get_relative_path(comp.local) + print(f'Removing {relpath}', end='...') + # Remove the component if not dry run + if not args.dry_run: + shutil.rmtree(relpath) + print('done.') + else: + print(f'dry-run only. Not removing {relpath}') + + # Next, we need to remove the .mepo directory + print(f'Removing .mepo', end='...') + if not args.dry_run: + shutil.rmtree('.mepo') + print('done.') + else: + print(f'dry-run only. Not removing .mepo') + + # If they pass in the --reclone flag, then we will re-clone all the subrepos + if args.reclone: + + # mepo_clone requires args which is an Argparse Namespace object + # We will create a new Namespace object with the correct arguments + # for mepo_clone + clone_args = type('Namespace', (object,), {'repo_url': None, 'directory': None, 'branch': None, 'config': None, 'allrepos': False, 'style': None}) + if not args.dry_run: + print('Re-cloning all subrepos') + mepo_clone.run(clone_args) + print('Recloning done.') + else: + print(f'Dry-run only. Not re-cloning all subrepos') + +def _get_relative_path(local_path): + """ + Get the relative path when given a local path. + + local_path: The path to a subrepo as known by mepo (relative to the .mepo directory) + """ + + # This creates a full path on the disk from the root of mepo and the local_path + full_local_path=os.path.join(MepoState.get_root_dir(),local_path) + + # We return the path relative to where we currently are + return os.path.relpath(full_local_path, os.getcwd()) diff --git a/mepo.d/state/exceptions.py b/mepo.d/state/exceptions.py index 02ed152..a6e0aa0 100644 --- a/mepo.d/state/exceptions.py +++ b/mepo.d/state/exceptions.py @@ -17,3 +17,7 @@ class ConfigFileNotFoundError(FileNotFoundError): class SuffixNotRecognizedError(RuntimeError): """Raised when the config suffix is not recognized""" pass + +class NotInRootDirError(SystemExit): + """Raised when a command is run not in the root directory""" + pass From 9d00c306c61f3a188af61cc7306c72c6907c9a2e Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 9 Dec 2022 10:55:00 -0500 Subject: [PATCH 2/7] Change order of operations --- mepo.d/command/reset/reset.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mepo.d/command/reset/reset.py b/mepo.d/command/reset/reset.py index fb9a57c..41cf79e 100644 --- a/mepo.d/command/reset/reset.py +++ b/mepo.d/command/reset/reset.py @@ -12,15 +12,6 @@ # of the project. def run(args): - # If a user has called this command without the force flag, we - # will ask them to confirm that they want to reset the project - if not args.force and not args.dry_run: - print(f"Are you sure you want to reset the project? If so, type 'yes' and press enter.", end=' ') - answer = input() - if answer != "yes": - print("Reset cancelled.") - return - allcomps = MepoState.read_state() # Check to see that we are in the root directory of the project @@ -34,6 +25,15 @@ def run(args): # If we get this far, then we are in the root directory of the project + # If a user has called this command without the force flag, we + # will ask them to confirm that they want to reset the project + if not args.force and not args.dry_run: + print(f"Are you sure you want to reset the project? If so, type 'yes' and press enter.", end=' ') + answer = input() + if answer != "yes": + print("Reset cancelled.") + return + # First, we need to delete all the subrepos # Loop over all the components in reverse (since we are deleting them) for comp in reversed(allcomps): From 8515b4cf91dd3d77949595afaa91a5bfd5fed653 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 9 Dec 2022 11:03:27 -0500 Subject: [PATCH 3/7] Update description --- mepo.d/cmdline/parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mepo.d/cmdline/parser.py b/mepo.d/cmdline/parser.py index 68d24d3..0a810eb 100644 --- a/mepo.d/cmdline/parser.py +++ b/mepo.d/cmdline/parser.py @@ -340,7 +340,9 @@ def __compare(self): def __reset(self): reset = self.subparsers.add_parser( 'reset', - description = 'Reset the current mepo clone to the original state. Must be run in the root of the mepo clone.', + description = 'Reset the current mepo clone to the original state. ' + 'This will delete all subrepos and does not check for uncommitted changes! ' + 'Must be run in the root of the mepo clone.', aliases=mepoconfig.get_command_alias('reset')) reset.add_argument( '-f','--force', From 72592778f4426e5dbd5c588d911cdf777f0b2c6f Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 9 Dec 2022 13:07:55 -0500 Subject: [PATCH 4/7] Update GitHub Actions --- .github/workflows/mepo.yaml | 6 +++--- CHANGELOG.md | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mepo.yaml b/.github/workflows/mepo.yaml index 14a8170..731dfac 100644 --- a/.github/workflows/mepo.yaml +++ b/.github/workflows/mepo.yaml @@ -8,14 +8,14 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - python-version: [3.x, pypy-3.8] + python-version: [3.x, pypy-3.x] name: Python ${{ matrix.python-version }} on ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} cache: 'pip' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6016631..4196add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added new `reset` command to reset a mepo clone +### Changed + +- Updated GitHub Actions + ## [1.47.0] - 2022-11-14 ### Added From dbe938dc1b92979f6a9658eda39b619205751541 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 9 Dec 2022 13:18:11 -0500 Subject: [PATCH 5/7] Specify versions --- .github/workflows/mepo.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mepo.yaml b/.github/workflows/mepo.yaml index 731dfac..4675878 100644 --- a/.github/workflows/mepo.yaml +++ b/.github/workflows/mepo.yaml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - python-version: [3.x, pypy-3.x] + python-version: [3.9, 3.10, 3.11, pypy-3.9] name: Python ${{ matrix.python-version }} on ${{ matrix.os }} steps: From ccc202882c0f441b58b9a355a44612236b97409c Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 9 Dec 2022 13:19:48 -0500 Subject: [PATCH 6/7] Make the versions strings --- .github/workflows/mepo.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mepo.yaml b/.github/workflows/mepo.yaml index 4675878..287f02f 100644 --- a/.github/workflows/mepo.yaml +++ b/.github/workflows/mepo.yaml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - python-version: [3.9, 3.10, 3.11, pypy-3.9] + python-version: ['3.9', '3.10', '3.11', 'pypy-3.9'] name: Python ${{ matrix.python-version }} on ${{ matrix.os }} steps: From 1ce25b2037e93616697dfd4f0d1bd8363a1671fd Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Fri, 9 Dec 2022 13:21:47 -0500 Subject: [PATCH 7/7] Update changelog enforcer --- .github/workflows/changelog-enforcer.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/changelog-enforcer.yml b/.github/workflows/changelog-enforcer.yml index b2009fb..cd31258 100644 --- a/.github/workflows/changelog-enforcer.yml +++ b/.github/workflows/changelog-enforcer.yml @@ -8,8 +8,7 @@ jobs: changelog: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: dangoslen/changelog-enforcer@v2 + - uses: dangoslen/changelog-enforcer@v3 with: changeLogPath: 'CHANGELOG.md' skipLabels: 'Skip Changelog,0 diff trivial,automatic'