2
0
mirror of https://github.com/frappe/bench.git synced 2025-01-09 00:21:23 +00:00

Merge pull request #1309 from gavindsouza/remove-app

feat(remove-app): --no-backup, --force
This commit is contained in:
gavin 2022-05-19 15:08:42 +05:30 committed by GitHub
commit 6790f6beaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 19 deletions

View File

@ -113,6 +113,10 @@ class AppMeta:
self.tag = self.branch = self.git_repo.active_branch.name self.tag = self.branch = self.git_repo.active_branch.name
except IndexError: except IndexError:
self.org, self.repo, self.tag = os.path.split(self.mount_path)[-2:] + (self.branch,) self.org, self.repo, self.tag = os.path.split(self.mount_path)[-2:] + (self.branch,)
except TypeError:
# faced a "a detached symbolic reference as it points" in case you're in the middle of
# some git shenanigans
self.tag = self.branch = None
def _setup_details_from_name_tag(self): def _setup_details_from_name_tag(self):
self.org, self.repo, self.tag = fetch_details_from_tag(self.name) self.org, self.repo, self.tag = fetch_details_from_tag(self.name)
@ -175,13 +179,19 @@ class App(AppMeta):
) )
@step(title="Archiving App {repo}", success="App {repo} Archived") @step(title="Archiving App {repo}", success="App {repo} Archived")
def remove(self): def remove(self, no_backup: bool = False):
active_app_path = os.path.join("apps", self.repo) active_app_path = os.path.join("apps", self.name)
archived_path = os.path.join("archived", "apps")
archived_name = get_available_folder_name(f"{self.repo}-{date.today()}", archived_path) if no_backup:
archived_app_path = os.path.join(archived_path, archived_name) shutil.rmtree(active_app_path)
log(f"App moved from {active_app_path} to {archived_app_path}") log(f"App deleted from {active_app_path}")
shutil.move(active_app_path, archived_app_path) else:
archived_path = os.path.join("archived", "apps")
archived_name = get_available_folder_name(f"{self.repo}-{date.today()}", archived_path)
archived_app_path = os.path.join(archived_path, archived_name)
shutil.move(active_app_path, archived_app_path)
log(f"App moved from {active_app_path} to {archived_app_path}")
@step(title="Installing App {repo}", success="App {repo} Installed") @step(title="Installing App {repo}", success="App {repo} Installed")
def install( def install(
@ -220,7 +230,7 @@ class App(AppMeta):
@step(title="Uninstalling App {repo}", success="App {repo} Uninstalled") @step(title="Uninstalling App {repo}", success="App {repo} Uninstalled")
def uninstall(self): def uninstall(self):
self.bench.run(f"{self.bench.python} -m pip uninstall -y {self.repo}") self.bench.run(f"{self.bench.python} -m pip uninstall -y {self.name}")
def _get_dependencies(self): def _get_dependencies(self):
from bench.utils.app import get_required_deps, required_apps_from_hooks from bench.utils.app import get_required_deps, required_apps_from_hooks

View File

@ -10,7 +10,7 @@ from typing import List, MutableSequence, TYPE_CHECKING, Union
# imports - module imports # imports - module imports
import bench import bench
from bench.exceptions import ValidationError from bench.exceptions import AppNotInstalledError, InvalidRemoteException
from bench.config.common_site_config import setup_config from bench.config.common_site_config import setup_config
from bench.utils import ( from bench.utils import (
paths_in_bench, paths_in_bench,
@ -49,7 +49,7 @@ class Base:
class Validator: class Validator:
def validate_app_uninstall(self, app): def validate_app_uninstall(self, app):
if app not in self.apps: if app not in self.apps:
raise ValidationError(f"No app named {app}") raise AppNotInstalledError(f"No app named {app}")
validate_app_installed_on_sites(app, bench_path=self.name) validate_app_installed_on_sites(app, bench_path=self.name)
@ -119,11 +119,16 @@ class Bench(Base, Validator):
self.apps.append(app) self.apps.append(app)
self.apps.sync() self.apps.sync()
def uninstall(self, app): def uninstall(self, app, no_backup=False, force=False):
from bench.app import App from bench.app import App
self.validate_app_uninstall(app) if not force:
self.apps.remove(App(app, bench=self, to_clone=False)) self.validate_app_uninstall(app)
try:
self.apps.remove(App(app, bench=self, to_clone=False), no_backup=no_backup)
except InvalidRemoteException:
if not force:
raise
self.apps.sync() self.apps.sync()
# self.build() - removed because it seems unnecessary # self.build() - removed because it seems unnecessary
self.reload() self.reload()
@ -305,9 +310,9 @@ class BenchApps(MutableSequence):
super().append(app.repo) super().append(app.repo)
self.apps.sort() self.apps.sort()
def remove(self, app: "App"): def remove(self, app: "App", no_backup: bool = False):
app.uninstall() app.uninstall()
app.remove() app.remove(no_backup=no_backup)
super().remove(app.repo) super().remove(app.repo)
def append(self, app: "App"): def append(self, app: "App"):

View File

@ -180,12 +180,14 @@ def new_app(app_name, no_git=None):
"Completely remove app from bench and re-build assets if not installed on any site" "Completely remove app from bench and re-build assets if not installed on any site"
), ),
) )
@click.option("--no-backup", is_flag=True, help="Do not backup app before removing")
@click.option("--force", is_flag=True, help="Force remove app")
@click.argument("app-name") @click.argument("app-name")
def remove_app(app_name): def remove_app(app_name, no_backup=False, force=False):
from bench.bench import Bench from bench.bench import Bench
bench = Bench(".") bench = Bench(".")
bench.uninstall(app_name) bench.uninstall(app_name, no_backup=no_backup, force=force)
@click.command("exclude-app", help="Exclude app from updating") @click.command("exclude-app", help="Exclude app from updating")

View File

@ -21,9 +21,15 @@ class BenchNotFoundError(Exception):
class ValidationError(Exception): class ValidationError(Exception):
pass pass
class AppNotInstalledError(ValidationError):
pass
class CannotUpdateReleaseBench(ValidationError): class CannotUpdateReleaseBench(ValidationError):
pass pass
class FeatureDoesNotExistError(CommandFailedError): class FeatureDoesNotExistError(CommandFailedError):
pass pass

View File

@ -17,7 +17,7 @@ import requests
# imports - module imports # imports - module imports
from bench import PROJECT_NAME, VERSION from bench import PROJECT_NAME, VERSION
from bench.exceptions import CommandFailedError, InvalidRemoteException, ValidationError from bench.exceptions import CommandFailedError, InvalidRemoteException, AppNotInstalledError
logger = logging.getLogger(PROJECT_NAME) logger = logging.getLogger(PROJECT_NAME)
@ -294,7 +294,7 @@ def set_git_remote_url(git_url, bench_path="."):
app = git_url.rsplit("/", 1)[1].rsplit(".", 1)[0] app = git_url.rsplit("/", 1)[1].rsplit(".", 1)[0]
if app not in Bench(bench_path).apps: if app not in Bench(bench_path).apps:
raise ValidationError(f"No app named {app}") raise AppNotInstalledError(f"No app named {app}")
app_dir = get_repo_dir(app, bench_path=bench_path) app_dir = get_repo_dir(app, bench_path=bench_path)