From ab9b6172a4da8d230637069f06c910090d9b4505 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 7 Feb 2024 18:27:54 +0530 Subject: [PATCH] feat: `bench validate-dependencies` command (#1534) This validates all `frappe-dependencies` and exits with 1 if any of specifications fail. This will be internal feature for FC for now. If this works well we can make the validation fail during install-app itself without requiring any additional command/steps. --- bench/app.py | 22 +++++++++++----------- bench/commands/__init__.py | 2 ++ bench/commands/make.py | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/bench/app.py b/bench/app.py index 861d3ffb..158b967c 100755 --- a/bench/app.py +++ b/bench/app.py @@ -308,7 +308,7 @@ class App(AppMeta): self.pyproject = get_pyproject(pyproject_path) return self.pyproject - def validate_app_dependencies(self) -> None: + def validate_app_dependencies(self, throw=False) -> None: pyproject = self.get_pyproject() or {} deps: Optional[dict] = ( pyproject.get("tool", {}).get("bench", {}).get("frappe-dependencies") @@ -317,7 +317,7 @@ class App(AppMeta): return for dep, version in deps.items(): - validate_dependency(self, dep, version) + validate_dependency(self, dep, version, throw=throw) """ Get App Cache @@ -489,16 +489,13 @@ def can_frappe_use_cached(app: App) -> bool: return False -def validate_dependency(app: App, dep: str, req_version: str) -> None: +def validate_dependency(app: App, dep: str, req_version: str, throw=False) -> None: dep_path = Path(app.bench.name) / "apps" / dep if not dep_path.is_dir(): - click.secho( - f"Required frappe-dependency '{dep}' not found. " - f"Aborting '{app.name}' installation. " - f"Please install '{dep}' first and retry", - fg="red", - ) - sys.exit(1) + click.secho(f"Required frappe-dependency '{dep}' not found.", fg="yellow") + if throw: + sys.exit(1) + return dep_version = get_dep_version(dep, dep_path) if not dep_version: @@ -508,9 +505,12 @@ def validate_dependency(app: App, dep: str, req_version: str) -> None: click.secho( f"Installed frappe-dependency '{dep}' version '{dep_version}' " f"does not satisfy required version '{req_version}'. " - f"App '{app.name}' might not work as expected", + f"App '{app.name}' might not work as expected.", fg="yellow", ) + if throw: + click.secho(f"Please install '{dep}{req_version}' first and retry", fg="red") + sys.exit(1) def get_dep_version(dep: str, dep_path: Path) -> Optional[str]: diff --git a/bench/commands/__init__.py b/bench/commands/__init__.py index 1daf6146..40ac8d5d 100755 --- a/bench/commands/__init__.py +++ b/bench/commands/__init__.py @@ -46,6 +46,7 @@ from bench.commands.make import ( new_app, pip, remove_app, + validate_dependencies, ) bench_command.add_command(init) @@ -56,6 +57,7 @@ bench_command.add_command(remove_app) bench_command.add_command(exclude_app_for_update) bench_command.add_command(include_app_for_update) bench_command.add_command(pip) +bench_command.add_command(validate_dependencies) from bench.commands.update import ( diff --git a/bench/commands/make.py b/bench/commands/make.py index 846e7b49..682b7bb6 100755 --- a/bench/commands/make.py +++ b/bench/commands/make.py @@ -253,3 +253,20 @@ def pip(ctx, args): env_py = get_env_cmd("python") os.execv(env_py, (env_py, "-m", "pip") + args) + + +@click.command( + "validate-dependencies", + help="Validates that all requirements specified in frappe-dependencies are met curently.", +) +@click.pass_context +def validate_dependencies(ctx): + "Validate all specified frappe-dependencies." + from bench.bench import Bench + from bench.app import App + + bench = Bench(".") + + for app_name in bench.apps: + app = App(app_name, bench=bench) + app.validate_app_dependencies(throw=True)