2
0
mirror of https://github.com/frappe/bench.git synced 2024-11-13 16:56:33 +00:00

refactor: Simplify Bench with OOP

Goals:
- Commonify bench operations in a way that intuitive
- Get rid of the multiple duplicate functions because it's so hard to
  understand flow in the codebase ;)
- Eliminate the need to guess, re-guess and pass bench info in each
  function that needs to do literally anything
- Increase my happiness index because I just realised that I'm the top
  contributor of this project and I'd like to make it my own.
- Adopt the principles of Least Surprise & The Principle of The Bigger Smile (of DHH) [inspired by ruby & ror]

Changes:
- The bench module has Bench and the action classes that can be accessed
  through the bench object
- Used the Bench class to access properties like sites, apps & run (to execute commands in context) to reduce effort and clutter
- Style improvements & minor changes included
This commit is contained in:
Gavin D'souza 2021-10-15 03:12:19 +05:30
parent b59379c5a9
commit 153546afd7
16 changed files with 297 additions and 87 deletions

View File

@ -102,13 +102,15 @@ class App(AppMeta):
def add_to_appstxt(app, bench_path='.'):
apps = get_apps(bench_path=bench_path)
apps = Bench(bench_path).apps
if app not in apps:
apps.append(app)
return write_appstxt(apps, bench_path=bench_path)
def remove_from_appstxt(app, bench_path='.'):
apps = get_apps(bench_path=bench_path)
apps = Bench(bench_path).apps
if app in apps:
apps.remove(app)
return write_appstxt(apps, bench_path=bench_path)
@ -189,7 +191,7 @@ def setup_app_dependencies(repo_name, bench_path='.', branch=None):
required_apps = eval(lines[0].strip('required_apps').strip().lstrip('=').strip())
# TODO: when the time comes, add version check here
for app in required_apps:
if app not in get_apps(bench_path=bench_path):
if app not in Bench(bench_path).apps:
get_app(app, bench_path=bench_path, branch=branch)
def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False, overwrite=False):
@ -219,12 +221,14 @@ def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=Fal
if dir_already_exists:
# application directory already exists
# prompt user to overwrite it
if overwrite or click.confirm(f'''A directory for the application "{repo_name}" already exists.
Do you want to continue and overwrite it?'''):
if overwrite or click.confirm(
f"A directory for the application '{repo_name}' already exists."
"Do you want to continue and overwrite it?"
):
import shutil
shutil.rmtree(cloned_path)
to_clone = True
elif click.confirm('''Do you want to reinstall the existing application?''', abort=True):
elif click.confirm("Do you want to reinstall the existing application?", abort=True):
pass
if to_clone:
@ -282,7 +286,6 @@ def new_app(app, bench_path='.'):
def install_app(app, bench_path=".", verbose=False, no_cache=False, restart_bench=True, skip_assets=False):
from bench.utils import get_env_cmd
from bench.config.common_site_config import get_config
install_text = f'Installing {app}'
click.secho(install_text, fg="yellow")
@ -300,7 +303,7 @@ def install_app(app, bench_path=".", verbose=False, no_cache=False, restart_benc
add_to_appstxt(app, bench_path=bench_path)
conf = get_config(bench_path=bench_path)
conf = Bench(bench_path).conf
if conf.get("developer_mode"):
from bench.utils import install_python_dev_dependencies
@ -318,13 +321,13 @@ def install_app(app, bench_path=".", verbose=False, no_cache=False, restart_benc
def remove_app(app, bench_path='.'):
import shutil
from bench.config.common_site_config import get_config
bench = Bench(bench_path)
app_path = os.path.join(bench_path, 'apps', app)
py = os.path.join(bench_path, 'env', 'bin', 'python')
# validate app removal
if app not in get_apps(bench_path):
if app not in bench.apps:
print(f"No app named {app}")
sys.exit(1)
@ -337,9 +340,10 @@ def remove_app(app, bench_path='.'):
# re-build assets and restart processes
run_frappe_cmd("build", bench_path=bench_path)
if get_config(bench_path).get('restart_supervisor_on_update'):
if bench.conf.get('restart_supervisor_on_update'):
restart_supervisor_processes(bench_path=bench_path)
if get_config(bench_path).get('restart_systemd_on_update'):
if bench.conf.get('restart_systemd_on_update'):
restart_systemd_processes(bench_path=bench_path)
@ -388,11 +392,10 @@ def check_app_installed_legacy(app, bench_path="."):
def pull_apps(apps=None, bench_path='.', reset=False):
'''Check all apps if there no local changes, pull'''
from bench.config.common_site_config import get_config
bench = Bench(bench_path)
rebase = '--rebase' if bench.conf.get('rebase_on_pull') else ''
apps = apps or bench.apps
rebase = '--rebase' if get_config(bench_path).get('rebase_on_pull') else ''
apps = apps or get_apps(bench_path=bench_path)
# check for local changes
if not reset:
for app in apps:
@ -432,7 +435,7 @@ Here are your choices:
print(f"Skipping pull for app {app}, since remote doesn't exist, and adding it to excluded apps")
continue
if not get_config(bench_path).get('shallow_clone') or not reset:
if not bench.conf.get('shallow_clone') or not reset:
is_shallow = os.path.exists(os.path.join(app_dir, ".git", "shallow"))
if is_shallow:
s = " to safely pull remote changes." if not reset else ""
@ -443,7 +446,7 @@ Here are your choices:
logger.log(f'pulling {app}')
if reset:
reset_cmd = f"git reset --hard {remote}/{branch}"
if get_config(bench_path).get('shallow_clone'):
if bench.conf.get('shallow_clone'):
exec_cmd(f"git fetch --depth=1 --no-tags {remote} {branch}",
cwd=app_dir)
exec_cmd(reset_cmd, cwd=app_dir)
@ -638,7 +641,9 @@ def get_apps_json(path):
return json.load(f)
def validate_branch():
installed_apps = set(get_apps())
apps = Bench(".").apps
installed_apps = set(apps)
check_apps = set(['frappe', 'erpnext'])
intersection_apps = installed_apps.intersection(check_apps)

203
bench/bench.py Normal file
View File

@ -0,0 +1,203 @@
import os
import shutil
import sys
import logging
from typing import MutableSequence
import bench
from bench.utils import remove_backups_crontab, folders_in_bench, get_venv_path, exec_cmd, get_env_cmd
from bench.config.common_site_config import setup_config
logger = logging.getLogger(bench.PROJECT_NAME)
class Base:
def run(self, cmd):
return exec_cmd(cmd, cwd=self.cwd)
class Bench(Base):
def __init__(self, path):
self.name = path
self.cwd = os.path.abspath(path)
self.exists = os.path.exists(self.name)
self.setup = BenchSetup(self)
self.teardown = BenchTearDown(self)
self.apps = BenchApps(self)
@property
def sites(self):
return [
path for path in os.listdir(os.path.join(self.name, 'sites'))
if os.path.exists(
os.path.join("sites", path, "site_config.json")
)
]
@property
def conf(self):
from bench.config.common_site_config import get_config
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 get_app(self, app, version=None):
pass
def drop_app(self, app, version=None):
pass
def install(self, app, branch=None):
from bench.app import App
app = App(app, branch=branch)
# get app?
# install app to env
# add to apps.txt
return
def uninstall(self, app):
# remove from apps.txt
# uninstall app from env
# remove app?
return
class BenchApps(MutableSequence):
def __init__(self, bench : Bench):
self.bench = bench
self.initialize_apps()
def initialize_apps(self):
try:
self.apps = open(
os.path.join(self.bench.name, "sites", "apps.txt")
).read().splitlines()
except FileNotFoundError:
self.apps = []
def __getitem__(self, key):
''' retrieves an item by its index, key'''
return self.apps[key]
def __setitem__(self, key, value):
''' set the item at index, key, to value '''
# should probably not be allowed
# self.apps[key] = value
raise NotImplementedError
def __delitem__(self, key):
''' removes the item at index, key '''
# TODO: uninstall and delete app from bench
del self.apps[key]
def __len__(self):
return len(self.apps)
def insert(self, key, value):
''' add an item, value, at index, key. '''
# TODO: fetch and install app to bench
self.apps.insert(key, value)
def __repr__(self):
return self.__str__()
def __str__(self):
return str([x for x in self.apps])
class BenchSetup(Base):
def __init__(self, bench : Bench):
self.bench = bench
self.cwd = self.bench.cwd
def dirs(self):
os.makedirs(self.bench.name, exist_ok=True)
for dirname in folders_in_bench:
os.makedirs(os.path.join(self.bench.name, dirname), exist_ok=True)
def env(self, python="python3"):
"""Setup env folder
- create env if not exists
- upgrade env pip
- install frappe python dependencies
"""
frappe = os.path.join(self.bench.name, "apps", "frappe")
env_python = get_env_cmd("python", bench_path=self.bench.name)
virtualenv = get_venv_path()
if not os.path.exists(env_python):
self.run(f"{virtualenv} -q env -p {python}")
self.run(f"{env_python} -m pip install -q -U pip")
if os.path.exists(frappe):
self.run(f"{env_python} -m pip install -q -U -e {frappe}")
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
generate_config(self.bench.name)
if procfile:
from bench.config.procfile import setup_procfile
setup_procfile(self.bench.name, skip_redis=not redis)
def logging(self):
from bench.utils import setup_logging
return setup_logging(bench_path=self.bench.name)
def patches(self):
import shutil
shutil.copy(
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'patches', 'patches.txt'),
os.path.join(self.bench.name, 'patches.txt')
)
def backups(self):
# TODO: to something better for logging data? - maybe a wrapper that auto-logs with more context
logger.log('setting up backups')
from crontab import CronTab
bench_dir = os.path.abspath(self.bench.name)
user = self.bench.conf.get('frappe_user')
logfile = os.path.join(bench_dir, 'logs', 'backup.log')
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):
job = system_crontab.new(command=job_command, comment="bench auto backups set for every 6 hours")
job.every(6).hours()
system_crontab.write()
logger.log('backups were set up')
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)

View File

@ -10,7 +10,7 @@ import click
# imports - module imports
import bench
from bench.app import get_apps
from bench.bench import Bench
from bench.commands import bench_command
from bench.config.common_site_config import get_config
from bench.utils import (
@ -87,7 +87,7 @@ def cli():
if sys.argv[1] in get_frappe_commands():
frappe_cmd()
if sys.argv[1] in get_apps():
if sys.argv[1] in Bench(".").apps:
app_cmd()
if not (len(sys.argv) > 1 and sys.argv[1] == "src"):

View File

@ -1,5 +1,5 @@
# imports - module imports
from bench.config.common_site_config import update_config, get_config, put_config
from bench.config.common_site_config import update_config, put_config
# imports - third party imports
import click
@ -68,7 +68,8 @@ def set_common_config(configs):
@click.command('remove-common-config', help='Remove specific keys from current bench\'s common config')
@click.argument('keys', nargs=-1)
def remove_common_config(keys):
common_site_config = get_config('.')
from bench.bench import Bench
common_site_config = Bench('.').conf
for key in keys:
if key in common_site_config:
del common_site_config[key]

View File

@ -3,7 +3,8 @@ import os
import subprocess
# imports - module imports
from bench.app import get_repo_dir, get_apps, get_remote
from bench.bench import Bench
from bench.app import get_repo_dir, get_remote
from bench.utils import set_git_remote_url
# imports - third party imports
@ -25,7 +26,7 @@ def remote_reset_url(app):
@click.command('remote-urls', help="Show apps remote url")
def remote_urls():
for app in get_apps():
for app in Bench(".").apps:
repo_dir = get_repo_dir(app)
if os.path.exists(os.path.join(repo_dir, '.git')):

View File

@ -70,13 +70,15 @@ def setup_production(user, yes=False):
@click.command("backups", help="Add cronjob for bench backups")
def setup_backups():
bench.utils.setup_backups()
from bench.bench import Bench
Bench(".").setup.backups()
@click.command("env", help="Setup virtualenv for bench")
@click.option("--python", type = str, default = "python3", help = "Path to Python Executable.")
def setup_env(python="python3"):
bench.utils.setup_env(python=python)
from bench.bench import Bench
return Bench(".").setup.env(python=python)
@click.command("firewall", help="Setup firewall for system")
@ -162,8 +164,7 @@ def setup_requirements(node=False, python=False, dev=False):
@click.option("--port", help="Port on which you want to run bench manager", default=23624)
@click.option("--domain", help="Domain on which you want to run bench manager")
def setup_manager(yes=False, port=23624, domain=None):
from bench.utils import get_sites
from bench.config.common_site_config import get_config
from bench.bench import Bench
from bench.config.nginx import make_bench_manager_nginx_conf
create_new_site = True
@ -182,15 +183,15 @@ def setup_manager(yes=False, port=23624, domain=None):
exec_cmd("bench --site bench-manager.local install-app bench_manager")
bench_path = "."
conf = get_config(bench_path)
bench = Bench(bench_path)
if conf.get("restart_supervisor_on_update") or conf.get("restart_systemd_on_update"):
if bench.conf.get("restart_supervisor_on_update") or bench.conf.get("restart_systemd_on_update"):
# implicates a production setup or so I presume
if not domain:
print("Please specify the site name on which you want to host bench-manager using the 'domain' flag")
sys.exit(1)
if domain not in get_sites(bench_path):
if domain not in bench.sites:
raise Exception("No such site")
make_bench_manager_nginx_conf(bench_path, yes=yes, port=port, domain=domain)

View File

@ -22,10 +22,13 @@ def start(no_dev, concurrency, procfile, no_prefix):
@click.option('--systemd', is_flag=True, default=False)
def restart(web, supervisor, systemd):
from bench.utils import restart_supervisor_processes, restart_systemd_processes
from bench.config.common_site_config import get_config
if get_config('.').get('restart_supervisor_on_update') or supervisor:
from bench.bench import Bench
bench = Bench(".")
if bench.conf.get('restart_supervisor_on_update') or supervisor:
restart_supervisor_processes(bench_path='.', web_workers=web)
if get_config('.').get('restart_systemd_on_update') or systemd:
if bench.conf.get('restart_systemd_on_update') or systemd:
restart_systemd_processes(bench_path='.', web_workers=web)
@ -114,8 +117,9 @@ def renew_lets_encrypt():
@click.command('backup', help="Backup single site")
@click.argument('site')
def backup_site(site):
from bench.utils import get_sites, backup_site
if site not in get_sites(bench_path='.'):
from bench.bench import Bench
from bench.utils import backup_site
if site not in Bench(".").sites:
print(f'Site `{site}` not found')
sys.exit(1)
backup_site(site, bench_path='.')

View File

@ -6,10 +6,10 @@ import click
# imports - module imports
import bench
from bench.config.common_site_config import get_config
from bench.config.nginx import make_nginx_conf
from bench.config.production_setup import service
from bench.config.site_config import get_domains, remove_domain, update_site_config
from bench.bench import Bench
from bench.utils import exec_cmd, update_common_site_config
from bench.exceptions import CommandFailedError
@ -37,7 +37,7 @@ def setup_letsencrypt(site, custom_domain, bench_path, interactive):
'Do you want to continue?',
abort=True)
if not get_config(bench_path).get("dns_multitenant"):
if not Bench(bench_path).conf.get("dns_multitenant"):
print("You cannot setup SSL without DNS Multitenancy")
return
@ -151,7 +151,7 @@ def setup_wildcard_ssl(domain, email, bench_path, exclude_base_domain):
return domain_list
if not get_config(bench_path).get("dns_multitenant"):
if not Bench(bench_path).conf.get("dns_multitenant"):
print("You cannot setup SSL without DNS Multitenancy")
return

View File

@ -9,7 +9,8 @@ import click
# imports - module imports
import bench
from bench.utils import get_bench_name, get_sites
from bench.bench import Bench
from bench.utils import get_bench_name
def make_nginx_conf(bench_path, yes=False):
@ -23,7 +24,7 @@ def make_nginx_conf(bench_path, yes=False):
bench_path = os.path.abspath(bench_path)
sites_path = os.path.join(bench_path, "sites")
config = bench.config.common_site_config.get_config(bench_path)
config = Bench(bench_path).conf
sites = prepare_sites(config, bench_path)
bench_name = get_bench_name(bench_path)
@ -56,13 +57,12 @@ def make_nginx_conf(bench_path, yes=False):
def make_bench_manager_nginx_conf(bench_path, yes=False, port=23624, domain=None):
from bench.config.site_config import get_site_config
from bench.config.common_site_config import get_config
template = bench.config.env().get_template('bench_manager_nginx.conf')
bench_path = os.path.abspath(bench_path)
sites_path = os.path.join(bench_path, "sites")
config = get_config(bench_path)
config = Bench(bench_path).conf
site_config = get_site_config(domain, bench_path=bench_path)
bench_name = get_bench_name(bench_path)
@ -182,18 +182,20 @@ def prepare_sites(config, bench_path):
return sites
def get_sites_with_config(bench_path):
from bench.config.common_site_config import get_config
from bench.bench import Bench
from bench.config.site_config import get_site_config
sites = get_sites(bench_path=bench_path)
dns_multitenant = get_config(bench_path).get('dns_multitenant')
bench = Bench(bench_path)
sites = bench.sites
conf = bench.conf
dns_multitenant = conf.get('dns_multitenant')
ret = []
for site in sites:
try:
site_config = get_site_config(site, bench_path=bench_path)
except Exception as e:
strict_nginx = get_config(bench_path).get('strict_nginx')
strict_nginx = conf.get('strict_nginx')
if strict_nginx:
print(f"\n\nERROR: The site config for the site {site} is broken.",
"If you want this command to pass, instead of just throwing an error,",
@ -236,8 +238,8 @@ def use_wildcard_certificate(bench_path, ret):
"ssl_certificate_key": "/path/to/erpnext.com.key"
}
'''
from bench.config.common_site_config import get_config
config = get_config(bench_path=bench_path)
from bench.bench import Bench
config = Bench(bench_path).conf
wildcard = config.get('wildcard')
if not wildcard:

View File

@ -7,12 +7,12 @@ import click
# imports - module imports
import bench
from bench.app import use_rq
from bench.config.common_site_config import get_config
from bench.utils import which
from bench.bench import Bench
def setup_procfile(bench_path, yes=False, skip_redis=False):
config = get_config(bench_path=bench_path)
config = Bench(bench_path).conf
procfile_path = os.path.join(bench_path, 'Procfile')
if not yes and os.path.exists(procfile_path):
click.confirm('A Procfile already exists and this will overwrite it. Do you want to continue?',

View File

@ -5,10 +5,10 @@ import sys
# imports - module imports
import bench
from bench.config.common_site_config import get_config
from bench.config.nginx import make_nginx_conf
from bench.config.supervisor import generate_supervisor_config, update_supervisord_config
from bench.config.systemd import generate_systemd_config
from bench.bench import Bench
from bench.utils import exec_cmd, which, fix_prod_setup_perms, get_bench_name, get_cmd_output, log
from bench.exceptions import CommandFailedError
@ -30,10 +30,13 @@ def setup_production_prerequisites():
def setup_production(user, bench_path='.', yes=False):
print("Setting Up prerequisites...")
setup_production_prerequisites()
if get_config(bench_path).get('restart_supervisor_on_update') and get_config(bench_path).get('restart_systemd_on_update'):
conf = Bench(bench_path).conf
if conf.get('restart_supervisor_on_update') and conf.get('restart_systemd_on_update'):
raise Exception("You cannot use supervisor and systemd at the same time. Modify your common_site_config accordingly." )
if get_config(bench_path).get('restart_systemd_on_update'):
if conf.get('restart_systemd_on_update'):
print("Setting Up systemd...")
generate_systemd_config(bench_path=bench_path, user=user, yes=yes)
else:
@ -50,7 +53,7 @@ def setup_production(user, bench_path='.', yes=False):
nginx_conf = f'/etc/nginx/conf.d/{bench_name}.conf'
print("Setting Up symlinks and reloading services...")
if get_config(bench_path).get('restart_supervisor_on_update'):
if conf.get('restart_supervisor_on_update'):
supervisor_conf_extn = "ini" if is_centos7() else "conf"
supervisor_conf = os.path.join(get_supervisor_confdir(), f'{bench_name}.{supervisor_conf_extn}')
@ -61,7 +64,7 @@ def setup_production(user, bench_path='.', yes=False):
if not os.path.islink(nginx_conf):
os.symlink(os.path.abspath(os.path.join(bench_path, 'config', 'nginx.conf')), nginx_conf)
if get_config(bench_path).get('restart_supervisor_on_update'):
if conf.get('restart_supervisor_on_update'):
reload_supervisor()
if os.environ.get('NO_SERVICE_RESTART'):
@ -72,6 +75,7 @@ def setup_production(user, bench_path='.', yes=False):
def disable_production(bench_path='.'):
bench_name = get_bench_name(bench_path)
conf = Bench(bench_path).conf
# supervisorctl
supervisor_conf_extn = "ini" if is_centos7() else "conf"
@ -80,7 +84,7 @@ def disable_production(bench_path='.'):
if os.path.islink(supervisor_conf):
os.unlink(supervisor_conf)
if get_config(bench_path).get('restart_supervisor_on_update'):
if conf.get('restart_supervisor_on_update'):
reload_supervisor()
# nginx

View File

@ -5,13 +5,13 @@ import subprocess
# imports - module imports
import bench
from bench.config.common_site_config import get_config
def generate_config(bench_path):
from urllib.parse import urlparse
from bench.bench import Bench
config = get_config(bench_path)
config = Bench(bench_path).conf
redis_version = get_redis_version()
ports = {}

View File

@ -3,9 +3,6 @@ import json
import os
from collections import defaultdict
# imports - module imports
from bench.utils import get_sites
def get_site_config(site, bench_path='.'):
config_path = os.path.join(bench_path, 'sites', site, 'site_config.json')
@ -35,8 +32,9 @@ def set_ssl_certificate_key(site, ssl_certificate_key, bench_path='.', gen_confi
def set_site_config_nginx_property(site, config, bench_path='.', gen_config=True):
from bench.config.nginx import make_nginx_conf
from bench.bench import Bench
if site not in get_sites(bench_path=bench_path):
if site not in Bench(bench_path).sites:
raise Exception("No such site")
update_site_config(site, config, bench_path=bench_path)
if gen_config:

View File

@ -7,7 +7,8 @@ import os
import bench
from bench.app import use_rq
from bench.utils import get_bench_name, which
from bench.config.common_site_config import get_config, update_config, get_gunicorn_workers
from bench.bench import Bench
from bench.config.common_site_config import update_config, get_gunicorn_workers
# imports - third party imports
import click
@ -21,8 +22,8 @@ def generate_supervisor_config(bench_path, user=None, yes=False, skip_redis=Fals
if not user:
user = getpass.getuser()
config = Bench(bench_path).conf
template = bench.config.env().get_template('supervisor.conf')
config = get_config(bench_path=bench_path)
bench_dir = os.path.abspath(bench_path)
config = template.render(**{

View File

@ -8,7 +8,8 @@ import click
# imports - module imports
import bench
from bench.app import use_rq
from bench.config.common_site_config import get_config, get_gunicorn_workers, update_config
from bench.bench import Bench
from bench.config.common_site_config import get_gunicorn_workers, update_config
from bench.utils import exec_cmd, which, get_bench_name
@ -19,7 +20,7 @@ def generate_systemd_config(bench_path, user=None, yes=False,
if not user:
user = getpass.getuser()
config = get_config(bench_path=bench_path)
config = Bench(bench_path).conf
bench_dir = os.path.abspath(bench_path)
bench_name = get_bench_name(bench_path)

View File

@ -395,7 +395,10 @@ def setup_socketio(bench_path='.'):
def patch_sites(bench_path='.'):
for site in get_sites(bench_path=bench_path):
from bench.bench import Bench
bench = Bench(bench_path)
for site in bench.sites:
try:
migrate_site(site, bench_path=bench_path)
except subprocess.CalledProcessError:
@ -417,21 +420,7 @@ def get_sites(bench_path='.'):
def setup_backups(bench_path='.'):
from crontab import CronTab
from bench.config.common_site_config import get_config
logger.log('setting up backups')
bench_dir = os.path.abspath(bench_path)
user = get_config(bench_path=bench_dir).get('frappe_user')
logfile = os.path.join(bench_dir, 'logs', 'backup.log')
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):
job = system_crontab.new(command=job_command, comment="bench auto backups set for every 6 hours")
job.every(6).hours()
system_crontab.write()
from bench.bench import Bench
def remove_backups_crontab(bench_path='.'):
from crontab import CronTab, CronItem
@ -439,7 +428,7 @@ def remove_backups_crontab(bench_path='.'):
logger.log('removing backup cronjob')
bench_dir = os.path.abspath(bench_path)
user = get_config(bench_path=bench_dir).get('frappe_user')
user = Bench(bench_dir).conf.get('frappe_user')
logfile = os.path.join(bench_dir, 'logs', 'backup.log')
system_crontab = CronTab(user=user)
backup_command = f"cd {bench_dir} && {sys.argv[0]} --verbose --site all backup"
@ -540,8 +529,8 @@ def get_git_version():
def check_git_for_shallow_clone():
from bench.config.common_site_config import get_config
config = get_config('.')
from bench.bench import Bench
config = Bench('.').conf
if config:
if config.get('release_bench'):