2021-11-17 19:09:48 +00:00
|
|
|
# imports - standard imports
|
|
|
|
import functools
|
2021-10-14 21:42:19 +00:00
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import sys
|
|
|
|
import logging
|
2021-11-26 06:24:32 +00:00
|
|
|
from typing import List, MutableSequence, TYPE_CHECKING
|
2021-10-14 21:42:19 +00:00
|
|
|
|
2021-11-17 18:21:28 +00:00
|
|
|
# imports - module imports
|
2021-10-14 21:42:19 +00:00
|
|
|
import bench
|
2021-11-11 04:46:19 +00:00
|
|
|
from bench.exceptions import ValidationError
|
2021-10-14 21:42:19 +00:00
|
|
|
from bench.config.common_site_config import setup_config
|
2021-11-12 21:29:01 +00:00
|
|
|
from bench.utils import (
|
|
|
|
paths_in_bench,
|
|
|
|
exec_cmd,
|
2021-11-29 13:03:32 +00:00
|
|
|
is_bench_directory,
|
2021-11-12 21:29:01 +00:00
|
|
|
is_frappe_app,
|
2021-11-17 18:21:28 +00:00
|
|
|
get_cmd_output,
|
2021-11-12 21:29:01 +00:00
|
|
|
get_git_version,
|
2021-11-26 10:54:56 +00:00
|
|
|
log,
|
2021-11-12 21:29:01 +00:00
|
|
|
run_frappe_cmd,
|
|
|
|
)
|
|
|
|
from bench.utils.bench import (
|
|
|
|
validate_app_installed_on_sites,
|
|
|
|
restart_supervisor_processes,
|
|
|
|
restart_systemd_processes,
|
2021-11-13 08:54:39 +00:00
|
|
|
restart_process_manager,
|
2021-11-12 21:29:01 +00:00
|
|
|
remove_backups_crontab,
|
|
|
|
get_venv_path,
|
|
|
|
get_env_cmd,
|
|
|
|
)
|
2021-11-26 10:58:18 +00:00
|
|
|
from bench.utils.render import job, step
|
2021-10-14 21:42:19 +00:00
|
|
|
|
|
|
|
|
2021-11-12 18:49:12 +00:00
|
|
|
if TYPE_CHECKING:
|
2021-11-11 04:46:19 +00:00
|
|
|
from bench.app import App
|
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
logger = logging.getLogger(bench.PROJECT_NAME)
|
|
|
|
|
|
|
|
|
|
|
|
class Base:
|
2021-11-11 04:46:19 +00:00
|
|
|
def run(self, cmd, cwd=None):
|
|
|
|
return exec_cmd(cmd, cwd=cwd or self.cwd)
|
|
|
|
|
|
|
|
|
|
|
|
class Validator:
|
|
|
|
def validate_app_uninstall(self, app):
|
|
|
|
if app not in self.apps:
|
|
|
|
raise ValidationError(f"No app named {app}")
|
|
|
|
validate_app_installed_on_sites(app, bench_path=self.name)
|
2021-10-14 21:42:19 +00:00
|
|
|
|
|
|
|
|
2021-11-17 19:09:48 +00:00
|
|
|
@functools.lru_cache(maxsize=None)
|
2021-11-11 04:46:19 +00:00
|
|
|
class Bench(Base, Validator):
|
2021-10-14 21:42:19 +00:00
|
|
|
def __init__(self, path):
|
|
|
|
self.name = path
|
|
|
|
self.cwd = os.path.abspath(path)
|
2021-11-29 13:03:32 +00:00
|
|
|
self.exists = is_bench_directory(self.name)
|
2021-11-11 04:46:19 +00:00
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
self.setup = BenchSetup(self)
|
|
|
|
self.teardown = BenchTearDown(self)
|
|
|
|
self.apps = BenchApps(self)
|
|
|
|
|
2021-11-12 21:29:01 +00:00
|
|
|
self.apps_txt = os.path.join(self.name, "sites", "apps.txt")
|
|
|
|
self.excluded_apps_txt = os.path.join(self.name, "sites", "excluded_apps.txt")
|
2021-11-11 04:46:19 +00:00
|
|
|
|
|
|
|
@property
|
2021-11-26 06:24:32 +00:00
|
|
|
def python(self) -> str:
|
|
|
|
return get_env_cmd("python", bench_path=self.name)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def shallow_clone(self) -> bool:
|
2021-11-11 04:46:19 +00:00
|
|
|
config = self.conf
|
|
|
|
|
|
|
|
if config:
|
2021-11-12 21:29:01 +00:00
|
|
|
if config.get("release_bench") or not config.get("shallow_clone"):
|
2021-11-11 04:46:19 +00:00
|
|
|
return False
|
|
|
|
|
2021-11-26 06:24:32 +00:00
|
|
|
return get_git_version() > 1.9
|
2021-11-11 04:46:19 +00:00
|
|
|
|
|
|
|
@property
|
2021-11-26 06:24:32 +00:00
|
|
|
def excluded_apps(self) -> List:
|
2021-11-11 04:46:19 +00:00
|
|
|
try:
|
|
|
|
with open(self.excluded_apps_txt) as f:
|
2021-11-12 21:29:01 +00:00
|
|
|
return f.read().strip().split("\n")
|
2021-11-11 04:46:19 +00:00
|
|
|
except Exception:
|
|
|
|
return []
|
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
@property
|
2021-11-26 06:24:32 +00:00
|
|
|
def sites(self) -> List:
|
2021-10-14 21:42:19 +00:00
|
|
|
return [
|
2021-11-12 21:29:01 +00:00
|
|
|
path
|
|
|
|
for path in os.listdir(os.path.join(self.name, "sites"))
|
|
|
|
if os.path.exists(os.path.join("sites", path, "site_config.json"))
|
2021-10-14 21:42:19 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def conf(self):
|
|
|
|
from bench.config.common_site_config import get_config
|
2021-11-12 21:29:01 +00:00
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
return get_config(self.name)
|
|
|
|
|
|
|
|
def init(self):
|
|
|
|
self.setup.dirs()
|
|
|
|
self.setup.env()
|
|
|
|
self.setup.backups()
|
|
|
|
|
|
|
|
def drop(self):
|
|
|
|
self.teardown.backups()
|
|
|
|
self.teardown.dirs()
|
|
|
|
|
|
|
|
def install(self, app, branch=None):
|
|
|
|
from bench.app import App
|
|
|
|
|
|
|
|
app = App(app, branch=branch)
|
2021-11-11 04:46:19 +00:00
|
|
|
self.apps.append(app)
|
2021-11-12 16:43:27 +00:00
|
|
|
self.apps.sync()
|
2021-10-14 21:42:19 +00:00
|
|
|
|
|
|
|
def uninstall(self, app):
|
2021-11-11 04:46:19 +00:00
|
|
|
from bench.app import App
|
|
|
|
|
|
|
|
self.validate_app_uninstall(app)
|
2021-11-13 08:53:08 +00:00
|
|
|
self.apps.remove(App(app, bench=self, to_clone=False))
|
2021-11-12 16:43:27 +00:00
|
|
|
self.apps.sync()
|
2021-11-13 08:53:08 +00:00
|
|
|
# self.build() - removed because it seems unnecessary
|
2021-11-11 04:46:19 +00:00
|
|
|
self.reload()
|
|
|
|
|
feat: Dynamic Output rendering
Each operation can be broken down to multiple jobs. For instance, the
update operation can be broken down into: setting up bench dirs, env,
backups, requirements, etc.
Each step has a lot of output since Frappe requires a lot of complex
stuff to be done as a pre-requisite. Bench tries to simplify a lot in a
single command. Once, a step is completed, it's output is not really
required. So, we can ignore it to reduce the noise.
Here's where the `bench.cli.fancy` variable kicks in. Along with the
refactored log and new step wrapper, it makes the above thing possible.
At this point, there's no way to set this var from the end user...given
I'm still developing this. In the later commits, the idea is to pass a
flag similar to pip's --use-feature flag.
2021-11-19 04:46:19 +00:00
|
|
|
@step(title="Building Bench Assets", success="Bench Assets Built")
|
2021-11-11 04:46:19 +00:00
|
|
|
def build(self):
|
|
|
|
# build assets & stuff
|
|
|
|
run_frappe_cmd("build", bench_path=self.name)
|
|
|
|
|
2021-11-18 12:52:32 +00:00
|
|
|
@step(title="Reloading Bench Processes", success="Bench Processes Reloaded")
|
2021-11-11 04:46:19 +00:00
|
|
|
def reload(self):
|
|
|
|
conf = self.conf
|
2021-11-12 21:29:01 +00:00
|
|
|
if conf.get("restart_supervisor_on_update"):
|
2021-11-11 04:46:19 +00:00
|
|
|
restart_supervisor_processes(bench_path=self.name)
|
2021-11-12 21:29:01 +00:00
|
|
|
if conf.get("restart_systemd_on_update"):
|
2021-11-11 04:46:19 +00:00
|
|
|
restart_systemd_processes(bench_path=self.name)
|
2021-11-13 08:54:39 +00:00
|
|
|
if conf.get("developer_mode"):
|
|
|
|
restart_process_manager(bench_path=self.name)
|
2021-10-14 21:42:19 +00:00
|
|
|
|
|
|
|
class BenchApps(MutableSequence):
|
2021-11-12 21:29:01 +00:00
|
|
|
def __init__(self, bench: Bench):
|
2021-10-14 21:42:19 +00:00
|
|
|
self.bench = bench
|
|
|
|
self.initialize_apps()
|
|
|
|
|
2021-11-12 16:43:27 +00:00
|
|
|
def sync(self):
|
|
|
|
self.initialize_apps()
|
|
|
|
with open(self.bench.apps_txt, "w") as f:
|
|
|
|
return f.write("\n".join(self.apps))
|
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
def initialize_apps(self):
|
2021-11-17 18:21:28 +00:00
|
|
|
is_installed = lambda app: app in installed_packages
|
|
|
|
|
|
|
|
try:
|
2021-11-26 06:24:32 +00:00
|
|
|
installed_packages = get_cmd_output(f"{self.bench.python} -m pip freeze", cwd=self.bench.name)
|
2021-11-17 18:21:28 +00:00
|
|
|
except Exception:
|
|
|
|
self.apps = []
|
|
|
|
return
|
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
try:
|
2021-11-12 21:29:01 +00:00
|
|
|
self.apps = [
|
|
|
|
x
|
|
|
|
for x in os.listdir(os.path.join(self.bench.name, "apps"))
|
2021-11-17 18:21:28 +00:00
|
|
|
if (
|
|
|
|
is_frappe_app(os.path.join(self.bench.name, "apps", x))
|
|
|
|
and is_installed(x)
|
|
|
|
)
|
2021-11-12 21:29:01 +00:00
|
|
|
]
|
2021-11-11 04:46:19 +00:00
|
|
|
self.apps.sort()
|
2021-10-14 21:42:19 +00:00
|
|
|
except FileNotFoundError:
|
|
|
|
self.apps = []
|
|
|
|
|
|
|
|
def __getitem__(self, key):
|
2021-11-12 21:29:01 +00:00
|
|
|
""" retrieves an item by its index, key"""
|
2021-10-14 21:42:19 +00:00
|
|
|
return self.apps[key]
|
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
2021-11-12 21:29:01 +00:00
|
|
|
""" set the item at index, key, to value """
|
2021-10-14 21:42:19 +00:00
|
|
|
# should probably not be allowed
|
|
|
|
# self.apps[key] = value
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def __delitem__(self, key):
|
2021-11-12 21:29:01 +00:00
|
|
|
""" removes the item at index, key """
|
2021-10-14 21:42:19 +00:00
|
|
|
# TODO: uninstall and delete app from bench
|
|
|
|
del self.apps[key]
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
return len(self.apps)
|
|
|
|
|
|
|
|
def insert(self, key, value):
|
2021-11-12 21:29:01 +00:00
|
|
|
""" add an item, value, at index, key. """
|
2021-10-14 21:42:19 +00:00
|
|
|
# TODO: fetch and install app to bench
|
|
|
|
self.apps.insert(key, value)
|
|
|
|
|
2021-11-11 04:46:19 +00:00
|
|
|
def add(self, app: "App"):
|
|
|
|
app.get()
|
|
|
|
app.install()
|
|
|
|
super().append(app.repo)
|
|
|
|
self.apps.sort()
|
|
|
|
|
|
|
|
def remove(self, app: "App"):
|
|
|
|
app.uninstall()
|
|
|
|
app.remove()
|
|
|
|
super().remove(app.repo)
|
|
|
|
|
2021-11-12 21:29:01 +00:00
|
|
|
def append(self, app: "App"):
|
2021-11-11 04:46:19 +00:00
|
|
|
return self.add(app)
|
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return self.__str__()
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str([x for x in self.apps])
|
|
|
|
|
|
|
|
|
|
|
|
class BenchSetup(Base):
|
2021-11-12 21:29:01 +00:00
|
|
|
def __init__(self, bench: Bench):
|
2021-10-14 21:42:19 +00:00
|
|
|
self.bench = bench
|
|
|
|
self.cwd = self.bench.cwd
|
|
|
|
|
feat: Dynamic Output rendering
Each operation can be broken down to multiple jobs. For instance, the
update operation can be broken down into: setting up bench dirs, env,
backups, requirements, etc.
Each step has a lot of output since Frappe requires a lot of complex
stuff to be done as a pre-requisite. Bench tries to simplify a lot in a
single command. Once, a step is completed, it's output is not really
required. So, we can ignore it to reduce the noise.
Here's where the `bench.cli.fancy` variable kicks in. Along with the
refactored log and new step wrapper, it makes the above thing possible.
At this point, there's no way to set this var from the end user...given
I'm still developing this. In the later commits, the idea is to pass a
flag similar to pip's --use-feature flag.
2021-11-19 04:46:19 +00:00
|
|
|
@step(title="Setting Up Directories", success="Directories Set Up")
|
2021-10-14 21:42:19 +00:00
|
|
|
def dirs(self):
|
|
|
|
os.makedirs(self.bench.name, exist_ok=True)
|
|
|
|
|
2021-11-11 04:46:19 +00:00
|
|
|
for dirname in paths_in_bench:
|
2021-10-14 21:42:19 +00:00
|
|
|
os.makedirs(os.path.join(self.bench.name, dirname), exist_ok=True)
|
|
|
|
|
feat: Dynamic Output rendering
Each operation can be broken down to multiple jobs. For instance, the
update operation can be broken down into: setting up bench dirs, env,
backups, requirements, etc.
Each step has a lot of output since Frappe requires a lot of complex
stuff to be done as a pre-requisite. Bench tries to simplify a lot in a
single command. Once, a step is completed, it's output is not really
required. So, we can ignore it to reduce the noise.
Here's where the `bench.cli.fancy` variable kicks in. Along with the
refactored log and new step wrapper, it makes the above thing possible.
At this point, there's no way to set this var from the end user...given
I'm still developing this. In the later commits, the idea is to pass a
flag similar to pip's --use-feature flag.
2021-11-19 04:46:19 +00:00
|
|
|
@step(title="Setting Up Environment", success="Environment Set Up")
|
2021-10-14 21:42:19 +00:00
|
|
|
def env(self, python="python3"):
|
|
|
|
"""Setup env folder
|
|
|
|
- create env if not exists
|
|
|
|
- upgrade env pip
|
|
|
|
- install frappe python dependencies
|
|
|
|
"""
|
2021-11-26 10:54:56 +00:00
|
|
|
import bench.cli
|
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
frappe = os.path.join(self.bench.name, "apps", "frappe")
|
|
|
|
virtualenv = get_venv_path()
|
2021-11-26 10:54:56 +00:00
|
|
|
quiet_flag = "" if bench.cli.verbose else "--quiet"
|
2021-10-14 21:42:19 +00:00
|
|
|
|
2021-11-26 06:24:32 +00:00
|
|
|
if not os.path.exists(self.bench.python):
|
2021-11-26 10:54:56 +00:00
|
|
|
self.run(f"{virtualenv} {quiet_flag} env -p {python}")
|
2021-10-14 21:42:19 +00:00
|
|
|
|
2021-11-26 07:17:29 +00:00
|
|
|
self.pip()
|
2021-10-14 21:42:19 +00:00
|
|
|
|
|
|
|
if os.path.exists(frappe):
|
2021-11-26 10:54:56 +00:00
|
|
|
self.run(f"{self.bench.python} -m pip install {quiet_flag} --upgrade -e {frappe}")
|
2021-10-14 21:42:19 +00:00
|
|
|
|
feat: Dynamic Output rendering
Each operation can be broken down to multiple jobs. For instance, the
update operation can be broken down into: setting up bench dirs, env,
backups, requirements, etc.
Each step has a lot of output since Frappe requires a lot of complex
stuff to be done as a pre-requisite. Bench tries to simplify a lot in a
single command. Once, a step is completed, it's output is not really
required. So, we can ignore it to reduce the noise.
Here's where the `bench.cli.fancy` variable kicks in. Along with the
refactored log and new step wrapper, it makes the above thing possible.
At this point, there's no way to set this var from the end user...given
I'm still developing this. In the later commits, the idea is to pass a
flag similar to pip's --use-feature flag.
2021-11-19 04:46:19 +00:00
|
|
|
@step(title="Setting Up Bench Config", success="Bench Config Set Up")
|
2021-10-14 21:42:19 +00:00
|
|
|
def config(self, redis=True, procfile=True):
|
|
|
|
"""Setup config folder
|
|
|
|
- create pids folder
|
|
|
|
- generate sites/common_site_config.json
|
|
|
|
"""
|
|
|
|
setup_config(self.bench.name)
|
|
|
|
|
|
|
|
if redis:
|
|
|
|
from bench.config.redis import generate_config
|
2021-11-12 21:29:01 +00:00
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
generate_config(self.bench.name)
|
|
|
|
|
|
|
|
if procfile:
|
|
|
|
from bench.config.procfile import setup_procfile
|
2021-11-12 21:29:01 +00:00
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
setup_procfile(self.bench.name, skip_redis=not redis)
|
|
|
|
|
2021-11-26 10:54:56 +00:00
|
|
|
@step(title="Updating pip", success="Updated pip")
|
|
|
|
def pip(self, verbose=False):
|
2021-11-26 07:17:29 +00:00
|
|
|
"""Updates env pip; assumes that env is setup
|
|
|
|
"""
|
2021-11-26 10:54:56 +00:00
|
|
|
import bench.cli
|
|
|
|
|
|
|
|
verbose = bench.cli.verbose or verbose
|
|
|
|
quiet_flag = "" if verbose else "--quiet"
|
|
|
|
|
|
|
|
return self.run(f"{self.bench.python} -m pip install {quiet_flag} --upgrade pip")
|
2021-11-26 07:17:29 +00:00
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
def logging(self):
|
|
|
|
from bench.utils import setup_logging
|
2021-11-12 21:29:01 +00:00
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
return setup_logging(bench_path=self.bench.name)
|
|
|
|
|
feat: Dynamic Output rendering
Each operation can be broken down to multiple jobs. For instance, the
update operation can be broken down into: setting up bench dirs, env,
backups, requirements, etc.
Each step has a lot of output since Frappe requires a lot of complex
stuff to be done as a pre-requisite. Bench tries to simplify a lot in a
single command. Once, a step is completed, it's output is not really
required. So, we can ignore it to reduce the noise.
Here's where the `bench.cli.fancy` variable kicks in. Along with the
refactored log and new step wrapper, it makes the above thing possible.
At this point, there's no way to set this var from the end user...given
I'm still developing this. In the later commits, the idea is to pass a
flag similar to pip's --use-feature flag.
2021-11-19 04:46:19 +00:00
|
|
|
@step(title="Setting Up Bench Patches", success="Bench Patches Set Up")
|
2021-10-14 21:42:19 +00:00
|
|
|
def patches(self):
|
|
|
|
shutil.copy(
|
2021-11-12 21:29:01 +00:00
|
|
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "patches", "patches.txt"),
|
|
|
|
os.path.join(self.bench.name, "patches.txt"),
|
2021-10-14 21:42:19 +00:00
|
|
|
)
|
|
|
|
|
feat: Dynamic Output rendering
Each operation can be broken down to multiple jobs. For instance, the
update operation can be broken down into: setting up bench dirs, env,
backups, requirements, etc.
Each step has a lot of output since Frappe requires a lot of complex
stuff to be done as a pre-requisite. Bench tries to simplify a lot in a
single command. Once, a step is completed, it's output is not really
required. So, we can ignore it to reduce the noise.
Here's where the `bench.cli.fancy` variable kicks in. Along with the
refactored log and new step wrapper, it makes the above thing possible.
At this point, there's no way to set this var from the end user...given
I'm still developing this. In the later commits, the idea is to pass a
flag similar to pip's --use-feature flag.
2021-11-19 04:46:19 +00:00
|
|
|
@step(title="Setting Up Backups Cronjob", success="Backups Cronjob Set Up")
|
2021-10-14 21:42:19 +00:00
|
|
|
def backups(self):
|
|
|
|
# TODO: to something better for logging data? - maybe a wrapper that auto-logs with more context
|
2021-11-12 21:29:01 +00:00
|
|
|
logger.log("setting up backups")
|
2021-10-14 21:42:19 +00:00
|
|
|
|
|
|
|
from crontab import CronTab
|
|
|
|
|
|
|
|
bench_dir = os.path.abspath(self.bench.name)
|
2021-11-12 21:29:01 +00:00
|
|
|
user = self.bench.conf.get("frappe_user")
|
|
|
|
logfile = os.path.join(bench_dir, "logs", "backup.log")
|
2021-10-14 21:42:19 +00:00
|
|
|
system_crontab = CronTab(user=user)
|
|
|
|
backup_command = f"cd {bench_dir} && {sys.argv[0]} --verbose --site all backup"
|
|
|
|
job_command = f"{backup_command} >> {logfile} 2>&1"
|
|
|
|
|
|
|
|
if job_command not in str(system_crontab):
|
2021-11-12 21:29:01 +00:00
|
|
|
job = system_crontab.new(
|
|
|
|
command=job_command, comment="bench auto backups set for every 6 hours"
|
|
|
|
)
|
2021-10-14 21:42:19 +00:00
|
|
|
job.every(6).hours()
|
|
|
|
system_crontab.write()
|
|
|
|
|
2021-11-12 21:29:01 +00:00
|
|
|
logger.log("backups were set up")
|
2021-10-14 21:42:19 +00:00
|
|
|
|
2021-11-26 10:54:56 +00:00
|
|
|
def __get_installed_apps(self) -> List:
|
|
|
|
"""Returns list of installed apps on bench, not in excluded_apps.txt
|
|
|
|
"""
|
|
|
|
apps = [app for app in self.bench.apps if app not in self.bench.excluded_apps]
|
|
|
|
apps.remove("frappe")
|
|
|
|
apps.insert(0, "frappe")
|
|
|
|
return apps
|
|
|
|
|
2021-11-26 10:58:18 +00:00
|
|
|
@job(title="Setting Up Bench Dependencies", success="Bench Dependencies Set Up")
|
2021-11-17 18:40:25 +00:00
|
|
|
def requirements(self):
|
2021-11-26 10:54:56 +00:00
|
|
|
"""Install and upgrade all installed apps on given Bench
|
|
|
|
"""
|
|
|
|
from bench.app import App
|
|
|
|
|
|
|
|
apps = self.__get_installed_apps()
|
|
|
|
|
|
|
|
self.pip()
|
|
|
|
|
|
|
|
print(f"Installing {len(apps)} applications...")
|
2021-11-26 10:58:18 +00:00
|
|
|
|
2021-11-26 10:54:56 +00:00
|
|
|
for app in apps:
|
|
|
|
App(app, bench=self.bench, to_clone=False).install()
|
|
|
|
|
|
|
|
def python(self):
|
|
|
|
"""Install and upgrade Python dependencies for installed apps on given Bench
|
|
|
|
"""
|
|
|
|
import bench.cli
|
|
|
|
|
|
|
|
apps = self.__get_installed_apps()
|
|
|
|
|
|
|
|
quiet_flag = "" if bench.cli.verbose else "--quiet"
|
|
|
|
|
|
|
|
self.pip()
|
|
|
|
|
|
|
|
for app in apps:
|
|
|
|
app_path = os.path.join(self.bench.name, "apps", app)
|
|
|
|
log(f"\nInstalling python dependencies for {app}", level=3, no_log=True)
|
|
|
|
self.run(f"{self.bench.python} -m pip install {quiet_flag} --upgrade -e {app_path}")
|
|
|
|
|
|
|
|
def node(self):
|
|
|
|
"""Install and upgrade Node dependencies for all apps on given Bench
|
|
|
|
"""
|
|
|
|
from bench.utils.bench import update_node_packages
|
|
|
|
|
|
|
|
return update_node_packages(bench_path=self.bench.name)
|
2021-11-17 18:40:25 +00:00
|
|
|
|
2021-10-14 21:42:19 +00:00
|
|
|
|
|
|
|
class BenchTearDown:
|
|
|
|
def __init__(self, bench):
|
|
|
|
self.bench = bench
|
|
|
|
|
|
|
|
def backups(self):
|
|
|
|
remove_backups_crontab(self.bench.name)
|
|
|
|
|
|
|
|
def dirs(self):
|
|
|
|
shutil.rmtree(self.bench.name)
|