mirror of
https://github.com/frappe/bench.git
synced 2025-01-08 00:04:38 +00:00
Set version as 2.0.0 and split cli.py into multiple files
This commit is contained in:
parent
124abbd725
commit
bba5b46112
@ -1,3 +1,5 @@
|
|||||||
from jinja2 import Environment, PackageLoader
|
from jinja2 import Environment, PackageLoader
|
||||||
|
|
||||||
|
__version__ = "2.0.0"
|
||||||
|
|
||||||
env = Environment(loader=PackageLoader('bench.config'), trim_blocks=True)
|
env = Environment(loader=PackageLoader('bench.config'), trim_blocks=True)
|
||||||
|
527
bench/cli.py
527
bench/cli.py
@ -1,41 +1,13 @@
|
|||||||
import click
|
import click
|
||||||
from .utils import init as _init
|
import os, sys, logging, json, pwd, subprocess
|
||||||
from .utils import setup_env as _setup_env
|
from bench.utils import is_root, PatchError, drop_privileges, get_env_cmd, get_cmd_output, get_frappe
|
||||||
from .utils import new_site as _new_site
|
from bench.app import get_apps
|
||||||
from .utils import setup_backups as _setup_backups
|
from bench.config.common_site_config import get_config
|
||||||
from .utils import setup_auto_update as _setup_auto_update
|
from bench.commands import bench_command
|
||||||
from .utils import setup_sudoers as _setup_sudoers
|
|
||||||
from .utils import start as _start
|
|
||||||
from .utils import set_nginx_port as _set_nginx_port
|
|
||||||
from .utils import set_url_root as _set_url_root
|
|
||||||
from .utils import set_default_site as _set_default_site
|
|
||||||
from .utils import (build_assets, patch_sites, exec_cmd, update_bench, get_env_cmd, get_frappe, setup_logging,
|
|
||||||
restart_supervisor_processes, update_requirements,
|
|
||||||
backup_all_sites, backup_site, get_sites, is_root, set_mariadb_host, drop_privileges,
|
|
||||||
fix_file_perms, fix_prod_setup_perms, set_ssl_certificate, set_ssl_certificate_key,
|
|
||||||
get_cmd_output, post_upgrade, get_bench_name,
|
|
||||||
pre_upgrade, validate_upgrade, PatchError, download_translations_p, setup_socketio, before_update)
|
|
||||||
from .app import get_app as _get_app
|
|
||||||
from .app import new_app as _new_app
|
|
||||||
from .app import pull_all_apps, get_apps, get_current_frappe_version, is_version_upgrade, switch_to_v4, switch_to_v5, switch_to_master, switch_to_develop
|
|
||||||
from .config.nginx import make_nginx_conf
|
|
||||||
from .production_setup import setup_production as _setup_production
|
|
||||||
from .config.common_site_config import get_config, make_config, update_config
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import copy
|
|
||||||
import json
|
|
||||||
import pwd
|
|
||||||
import grp
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
logger = logging.getLogger('bench')
|
logger = logging.getLogger('bench')
|
||||||
from_command_line = False
|
from_command_line = False
|
||||||
|
|
||||||
global FRAPPE_VERSION
|
|
||||||
|
|
||||||
def cli():
|
def cli():
|
||||||
global from_command_line
|
global from_command_line
|
||||||
from_command_line = True
|
from_command_line = True
|
||||||
@ -43,45 +15,42 @@ def cli():
|
|||||||
check_uid()
|
check_uid()
|
||||||
change_dir()
|
change_dir()
|
||||||
change_uid()
|
change_uid()
|
||||||
|
|
||||||
if len(sys.argv) > 2 and sys.argv[1] == "frappe":
|
if len(sys.argv) > 2 and sys.argv[1] == "frappe":
|
||||||
return old_frappe_cli()
|
return old_frappe_cli()
|
||||||
|
|
||||||
elif len(sys.argv) > 1 and sys.argv[1] in get_frappe_commands():
|
elif len(sys.argv) > 1 and sys.argv[1] in get_frappe_commands():
|
||||||
return frappe_cmd()
|
return frappe_cmd()
|
||||||
|
|
||||||
elif len(sys.argv) > 1 and sys.argv[1] in ("--site", "--verbose", "--force", "--profile"):
|
elif len(sys.argv) > 1 and sys.argv[1] in ("--site", "--verbose", "--force", "--profile"):
|
||||||
return frappe_cmd()
|
return frappe_cmd()
|
||||||
|
|
||||||
elif len(sys.argv) > 1 and sys.argv[1]=="--help":
|
elif len(sys.argv) > 1 and sys.argv[1]=="--help":
|
||||||
print click.Context(bench).get_help()
|
print click.Context(bench_command).get_help()
|
||||||
print
|
print
|
||||||
print get_frappe_help()
|
print get_frappe_help()
|
||||||
return
|
return
|
||||||
|
|
||||||
elif len(sys.argv) > 1 and sys.argv[1] in get_apps():
|
elif len(sys.argv) > 1 and sys.argv[1] in get_apps():
|
||||||
return app_cmd()
|
return app_cmd()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
bench()
|
# NOTE: this is the main bench command
|
||||||
|
bench_command()
|
||||||
except PatchError:
|
except PatchError:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def cmd_requires_root():
|
|
||||||
if len(sys.argv) > 2 and sys.argv[2] in ('production', 'sudoers'):
|
|
||||||
return True
|
|
||||||
if len(sys.argv) > 2 and sys.argv[1] in ('patch',):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_uid():
|
def check_uid():
|
||||||
if cmd_requires_root() and not is_root():
|
if cmd_requires_root() and not is_root():
|
||||||
print 'superuser privileges required for this command'
|
print 'superuser privileges required for this command'
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def change_uid():
|
def cmd_requires_root():
|
||||||
if is_root() and not cmd_requires_root():
|
if len(sys.argv) > 2 and sys.argv[2] in ('production', 'sudoers'):
|
||||||
frappe_user = get_config(".").get('frappe_user')
|
return True
|
||||||
if frappe_user:
|
if len(sys.argv) > 2 and sys.argv[1] in ('patch',):
|
||||||
drop_privileges(uid_name=frappe_user, gid_name=frappe_user)
|
return True
|
||||||
os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir
|
|
||||||
else:
|
|
||||||
print 'You should not run this command as root'
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def change_dir():
|
def change_dir():
|
||||||
if os.path.exists('config.json') or "init" in sys.argv:
|
if os.path.exists('config.json') or "init" in sys.argv:
|
||||||
@ -93,6 +62,16 @@ def change_dir():
|
|||||||
if os.path.exists(dir_path):
|
if os.path.exists(dir_path):
|
||||||
os.chdir(dir_path)
|
os.chdir(dir_path)
|
||||||
|
|
||||||
|
def change_uid():
|
||||||
|
if is_root() and not cmd_requires_root():
|
||||||
|
frappe_user = get_config(".").get('frappe_user')
|
||||||
|
if frappe_user:
|
||||||
|
drop_privileges(uid_name=frappe_user, gid_name=frappe_user)
|
||||||
|
os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir
|
||||||
|
else:
|
||||||
|
print 'You should not run this command as root'
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def old_frappe_cli(bench='.'):
|
def old_frappe_cli(bench='.'):
|
||||||
f = get_frappe(bench=bench)
|
f = get_frappe(bench=bench)
|
||||||
os.chdir(os.path.join(bench, 'sites'))
|
os.chdir(os.path.join(bench, 'sites'))
|
||||||
@ -128,451 +107,3 @@ def get_frappe_help(bench='.'):
|
|||||||
return "Framework commands:\n" + out.split('Commands:')[1]
|
return "Framework commands:\n" + out.split('Commands:')[1]
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@click.command()
|
|
||||||
def shell(bench='.'):
|
|
||||||
if not os.environ.get('SHELL'):
|
|
||||||
print "Cannot get shell"
|
|
||||||
sys.exit(1)
|
|
||||||
if not os.path.exists('sites'):
|
|
||||||
print "sites dir doesn't exist"
|
|
||||||
sys.exit(1)
|
|
||||||
env = copy.copy(os.environ)
|
|
||||||
env['PS1'] = '(' + os.path.basename(os.path.dirname(os.path.abspath(__file__))) + ')' + env.get('PS1', '')
|
|
||||||
env['PATH'] = os.path.dirname(os.path.abspath(os.path.join('env','bin')) + ':' + env['PATH'])
|
|
||||||
os.chdir('sites')
|
|
||||||
os.execve(env['SHELL'], [env['SHELL']], env)
|
|
||||||
|
|
||||||
@click.group()
|
|
||||||
def bench(bench='.'):
|
|
||||||
"Bench manager for Frappe"
|
|
||||||
# TODO add bench path context
|
|
||||||
global FRAPPE_VERSION
|
|
||||||
FRAPPE_VERSION = get_current_frappe_version()
|
|
||||||
setup_logging(bench=bench)
|
|
||||||
|
|
||||||
@click.command()
|
|
||||||
@click.argument('path')
|
|
||||||
@click.option('--apps_path', default=None, help="path to json files with apps to install after init")
|
|
||||||
@click.option('--frappe-path', default=None, help="path to frappe repo")
|
|
||||||
@click.option('--frappe-branch', default=None, help="path to frappe repo")
|
|
||||||
@click.option('--no-procfile', is_flag=True, help="Pull changes in all the apps in bench")
|
|
||||||
@click.option('--no-backups',is_flag=True, help="Run migrations for all sites in the bench")
|
|
||||||
@click.option('--no-auto-update',is_flag=True, help="Build JS and CSS artifacts for the bench")
|
|
||||||
@click.option('--verbose',is_flag=True, help="Verbose output during install")
|
|
||||||
def init(path, apps_path, frappe_path, frappe_branch, no_procfile, no_backups,
|
|
||||||
no_auto_update, verbose):
|
|
||||||
"Create a new bench"
|
|
||||||
_init(path, apps_path=apps_path, no_procfile=no_procfile, no_backups=no_backups,
|
|
||||||
no_auto_update=no_auto_update, frappe_path=frappe_path, frappe_branch=frappe_branch, verbose=verbose)
|
|
||||||
click.echo('Bench {} initialized'.format(path))
|
|
||||||
|
|
||||||
@click.command('get-app')
|
|
||||||
@click.argument('name')
|
|
||||||
@click.argument('git-url')
|
|
||||||
@click.option('--branch', default=None, help="branch to checkout")
|
|
||||||
def get_app(name, git_url, branch):
|
|
||||||
"clone an app from the internet and set it up in your bench"
|
|
||||||
_get_app(name, git_url, branch=branch)
|
|
||||||
|
|
||||||
@click.command('new-app')
|
|
||||||
@click.argument('app-name')
|
|
||||||
def new_app(app_name):
|
|
||||||
"start a new app"
|
|
||||||
_new_app(app_name)
|
|
||||||
|
|
||||||
@click.command('new-site')
|
|
||||||
@click.option('--mariadb-root-password', help="MariaDB root password")
|
|
||||||
@click.option('--admin-password', help="admin password to set for site")
|
|
||||||
@click.argument('site')
|
|
||||||
def new_site(site, mariadb_root_password=None, admin_password=None):
|
|
||||||
"Create a new site in the bench"
|
|
||||||
_new_site(site, mariadb_root_password=mariadb_root_password, admin_password=admin_password)
|
|
||||||
|
|
||||||
#TODO: Not DRY
|
|
||||||
@click.command('update')
|
|
||||||
@click.option('--pull', is_flag=True, help="Pull changes in all the apps in bench")
|
|
||||||
@click.option('--patch',is_flag=True, help="Run migrations for all sites in the bench")
|
|
||||||
@click.option('--build',is_flag=True, help="Build JS and CSS artifacts for the bench")
|
|
||||||
@click.option('--bench',is_flag=True, help="Update bench")
|
|
||||||
@click.option('--requirements',is_flag=True, help="Update requirements")
|
|
||||||
@click.option('--restart-supervisor',is_flag=True, help="restart supervisor processes after update")
|
|
||||||
@click.option('--auto',is_flag=True)
|
|
||||||
@click.option('--upgrade',is_flag=True)
|
|
||||||
@click.option('--no-backup',is_flag=True)
|
|
||||||
@click.option('--force',is_flag=True)
|
|
||||||
def _update(pull=False, patch=False, build=False, bench=False, auto=False, restart_supervisor=False, requirements=False, no_backup=False, upgrade=False, force=False):
|
|
||||||
"Update bench"
|
|
||||||
|
|
||||||
if not (pull or patch or build or bench or requirements):
|
|
||||||
pull, patch, build, bench, requirements = True, True, True, True, True
|
|
||||||
|
|
||||||
conf = get_config(".")
|
|
||||||
|
|
||||||
version_upgrade = is_version_upgrade()
|
|
||||||
|
|
||||||
if version_upgrade[0] and not upgrade:
|
|
||||||
print
|
|
||||||
print
|
|
||||||
print "This update will cause a major version change in Frappe/ERPNext from {0} to {1}.".format(*version_upgrade[1:])
|
|
||||||
print "This would take significant time to migrate and might break custom apps. Please run `bench update --upgrade` to confirm."
|
|
||||||
print
|
|
||||||
print "You can stay on the latest stable release by running `bench switch-to-master` or pin your bench to {0} by running `bench switch-to-v{0}`".format(version_upgrade[1])
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if conf.get('release_bench'):
|
|
||||||
print 'Release bench, cannot update'
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if auto:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if bench and conf.get('update_bench_on_update'):
|
|
||||||
update_bench()
|
|
||||||
restart_update({
|
|
||||||
'pull': pull,
|
|
||||||
'patch': patch,
|
|
||||||
'build': build,
|
|
||||||
'requirements': requirements,
|
|
||||||
'no-backup': no_backup,
|
|
||||||
'restart-supervisor': restart_supervisor,
|
|
||||||
'upgrade': upgrade
|
|
||||||
})
|
|
||||||
|
|
||||||
update(pull, patch, build, bench, auto, restart_supervisor, requirements, no_backup, upgrade, force=force)
|
|
||||||
|
|
||||||
def update(pull=False, patch=False, build=False, bench=False, auto=False, restart_supervisor=False, requirements=False, no_backup=False, upgrade=False, bench_path='.', force=False):
|
|
||||||
conf = get_config(bench=bench_path)
|
|
||||||
version_upgrade = is_version_upgrade(bench=bench_path)
|
|
||||||
|
|
||||||
if version_upgrade[0] and not upgrade:
|
|
||||||
raise Exception("Major Version Upgrade")
|
|
||||||
|
|
||||||
if upgrade and (version_upgrade[0] or (not version_upgrade[0] and force)):
|
|
||||||
validate_upgrade(version_upgrade[1], version_upgrade[2], bench=bench_path)
|
|
||||||
|
|
||||||
before_update(bench=bench_path, requirements=requirements)
|
|
||||||
|
|
||||||
if pull:
|
|
||||||
pull_all_apps(bench=bench_path)
|
|
||||||
|
|
||||||
if requirements:
|
|
||||||
update_requirements(bench=bench_path)
|
|
||||||
|
|
||||||
if upgrade and (version_upgrade[0] or (not version_upgrade[0] and force)):
|
|
||||||
pre_upgrade(version_upgrade[1], version_upgrade[2], bench=bench_path)
|
|
||||||
import utils, app
|
|
||||||
reload(utils)
|
|
||||||
reload(app)
|
|
||||||
|
|
||||||
if patch:
|
|
||||||
if not no_backup:
|
|
||||||
backup_all_sites(bench=bench_path)
|
|
||||||
patch_sites(bench=bench_path)
|
|
||||||
if build:
|
|
||||||
build_assets(bench=bench_path)
|
|
||||||
if upgrade and (version_upgrade[0] or (not version_upgrade[0] and force)):
|
|
||||||
post_upgrade(version_upgrade[1], version_upgrade[2], bench=bench_path)
|
|
||||||
if restart_supervisor or conf.get('restart_supervisor_on_update'):
|
|
||||||
restart_supervisor_processes(bench=bench_path)
|
|
||||||
|
|
||||||
print "_"*80
|
|
||||||
print "Bench: Open source installer + admin for Frappe and ERPNext (https://erpnext.com)"
|
|
||||||
print
|
|
||||||
|
|
||||||
@click.command('retry-upgrade')
|
|
||||||
@click.option('--version', default=5)
|
|
||||||
def retry_upgrade(version):
|
|
||||||
pull_all_apps()
|
|
||||||
patch_sites()
|
|
||||||
build_assets()
|
|
||||||
post_upgrade(version-1, version)
|
|
||||||
|
|
||||||
def restart_update(kwargs):
|
|
||||||
args = ['--'+k for k, v in kwargs.items() if v]
|
|
||||||
os.execv(sys.argv[0], sys.argv[:2] + args)
|
|
||||||
|
|
||||||
@click.command('restart')
|
|
||||||
def restart():
|
|
||||||
"Restart supervisor processes"
|
|
||||||
restart_supervisor_processes()
|
|
||||||
|
|
||||||
@click.command('start')
|
|
||||||
@click.option('--no-dev', is_flag=True)
|
|
||||||
def start(no_dev=False):
|
|
||||||
"Start Frappe development processes"
|
|
||||||
_start(no_dev=no_dev)
|
|
||||||
|
|
||||||
@click.command('switch-to-master')
|
|
||||||
@click.option('--upgrade',is_flag=True)
|
|
||||||
def _switch_to_master(upgrade=False):
|
|
||||||
"Switch frappe and erpnext to master branch"
|
|
||||||
switch_to_master(upgrade=upgrade)
|
|
||||||
print
|
|
||||||
print 'Switched to master'
|
|
||||||
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
|
||||||
|
|
||||||
@click.command('switch-to-develop')
|
|
||||||
@click.option('--upgrade',is_flag=True)
|
|
||||||
def _switch_to_develop(upgrade=False):
|
|
||||||
"Switch frappe and erpnext to develop branch"
|
|
||||||
switch_to_develop(upgrade=upgrade)
|
|
||||||
print
|
|
||||||
print 'Switched to develop'
|
|
||||||
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
|
||||||
|
|
||||||
@click.command('switch-to-v4')
|
|
||||||
@click.option('--upgrade',is_flag=True)
|
|
||||||
def _switch_to_v4(upgrade=False):
|
|
||||||
"Switch frappe and erpnext to v4 branch"
|
|
||||||
switch_to_v4(upgrade=upgrade)
|
|
||||||
print
|
|
||||||
print 'Switched to v4'
|
|
||||||
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
|
||||||
|
|
||||||
@click.command('switch-to-v5')
|
|
||||||
@click.option('--upgrade',is_flag=True)
|
|
||||||
def _switch_to_v5(upgrade=False):
|
|
||||||
"Switch frappe and erpnext to v4 branch"
|
|
||||||
switch_to_v5(upgrade=upgrade)
|
|
||||||
print
|
|
||||||
print 'Switched to v5'
|
|
||||||
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
|
||||||
|
|
||||||
@click.command('set-nginx-port')
|
|
||||||
@click.argument('site')
|
|
||||||
@click.argument('port', type=int)
|
|
||||||
def set_nginx_port(site, port):
|
|
||||||
"Set nginx port for site"
|
|
||||||
_set_nginx_port(site, port)
|
|
||||||
|
|
||||||
@click.command('set-ssl-certificate')
|
|
||||||
@click.argument('site')
|
|
||||||
@click.argument('ssl-certificate-path')
|
|
||||||
def _set_ssl_certificate(site, ssl_certificate_path):
|
|
||||||
"Set ssl certificate path for site"
|
|
||||||
set_ssl_certificate(site, ssl_certificate_path)
|
|
||||||
|
|
||||||
@click.command('set-ssl-key')
|
|
||||||
@click.argument('site')
|
|
||||||
@click.argument('ssl-certificate-key-path')
|
|
||||||
def _set_ssl_certificate_key(site, ssl_certificate_key_path):
|
|
||||||
"Set ssl certificate private key path for site"
|
|
||||||
set_ssl_certificate_key(site, ssl_certificate_key_path)
|
|
||||||
|
|
||||||
@click.command('set-url-root')
|
|
||||||
@click.argument('site')
|
|
||||||
@click.argument('url-root')
|
|
||||||
def set_url_root(site, url_root):
|
|
||||||
"Set url root for site"
|
|
||||||
_set_url_root(site, url_root)
|
|
||||||
|
|
||||||
@click.command('set-mariadb-host')
|
|
||||||
@click.argument('host')
|
|
||||||
def _set_mariadb_host(host):
|
|
||||||
"Set MariaDB host for bench"
|
|
||||||
set_mariadb_host(host)
|
|
||||||
|
|
||||||
@click.command('set-default-site')
|
|
||||||
@click.argument('site')
|
|
||||||
def set_default_site(site):
|
|
||||||
"Set default site for bench"
|
|
||||||
_set_default_site(site)
|
|
||||||
|
|
||||||
@click.command('backup')
|
|
||||||
@click.argument('site')
|
|
||||||
def _backup_site(site):
|
|
||||||
"backup site"
|
|
||||||
if not site in get_sites(bench='.'):
|
|
||||||
print 'site not found'
|
|
||||||
sys.exit(1)
|
|
||||||
backup_site(site, bench='.')
|
|
||||||
|
|
||||||
@click.command('backup-all-sites')
|
|
||||||
def _backup_all_sites():
|
|
||||||
"backup all sites"
|
|
||||||
backup_all_sites(bench='.')
|
|
||||||
|
|
||||||
@click.command('release')
|
|
||||||
@click.argument('app', type=click.Choice(['frappe', 'erpnext', 'erpnext_shopify', 'paypal_integration']))
|
|
||||||
@click.argument('bump-type', type=click.Choice(['major', 'minor', 'patch']))
|
|
||||||
@click.option('--develop', default='develop')
|
|
||||||
@click.option('--master', default='master')
|
|
||||||
def _release(app, bump_type, develop, master):
|
|
||||||
"Release app (internal to the Frappe team)"
|
|
||||||
from .release import release
|
|
||||||
repo = os.path.join('apps', app)
|
|
||||||
release(repo, bump_type, develop, master)
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
@click.group()
|
|
||||||
def setup():
|
|
||||||
"Setup bench"
|
|
||||||
pass
|
|
||||||
|
|
||||||
@click.command('sudoers')
|
|
||||||
@click.argument('user')
|
|
||||||
def setup_sudoers(user):
|
|
||||||
"Add commands to sudoers list for execution without password"
|
|
||||||
_setup_sudoers(user)
|
|
||||||
|
|
||||||
@click.command('nginx')
|
|
||||||
def setup_nginx():
|
|
||||||
"generate config for nginx"
|
|
||||||
make_nginx_conf(bench=".")
|
|
||||||
|
|
||||||
@click.command('supervisor')
|
|
||||||
def setup_supervisor():
|
|
||||||
"generate config for supervisor"
|
|
||||||
from bench.config.supervisor import generate_supervisor_config
|
|
||||||
generate_supervisor_config()
|
|
||||||
|
|
||||||
@click.command('redis')
|
|
||||||
def setup_redis():
|
|
||||||
"generate config for redis cache"
|
|
||||||
from bench.config.redis import generate_config
|
|
||||||
generate_config('.')
|
|
||||||
|
|
||||||
@click.command('production')
|
|
||||||
@click.argument('user')
|
|
||||||
def setup_production(user):
|
|
||||||
"setup bench for production"
|
|
||||||
_setup_production(user=user)
|
|
||||||
|
|
||||||
@click.command('auto-update')
|
|
||||||
def setup_auto_update():
|
|
||||||
"Add cronjob for bench auto update"
|
|
||||||
_setup_auto_update()
|
|
||||||
|
|
||||||
@click.command('backups')
|
|
||||||
def setup_backups():
|
|
||||||
"Add cronjob for bench backups"
|
|
||||||
_setup_backups()
|
|
||||||
|
|
||||||
@click.command('env')
|
|
||||||
def setup_env():
|
|
||||||
"Setup virtualenv for bench"
|
|
||||||
_setup_env()
|
|
||||||
|
|
||||||
@click.command('procfile')
|
|
||||||
def setup_procfile():
|
|
||||||
"Setup Procfile for bench start"
|
|
||||||
from bench.config.procfile import setup_procfile
|
|
||||||
setup_procfile('.')
|
|
||||||
|
|
||||||
@click.command('socketio')
|
|
||||||
def _setup_socketio():
|
|
||||||
"Setup node deps for socketio server"
|
|
||||||
setup_socketio()
|
|
||||||
|
|
||||||
@click.command('config')
|
|
||||||
def setup_config():
|
|
||||||
"overwrite or make config.json"
|
|
||||||
make_config('.')
|
|
||||||
|
|
||||||
setup.add_command(setup_nginx)
|
|
||||||
setup.add_command(setup_sudoers)
|
|
||||||
setup.add_command(setup_supervisor)
|
|
||||||
setup.add_command(setup_redis)
|
|
||||||
setup.add_command(setup_auto_update)
|
|
||||||
setup.add_command(setup_backups)
|
|
||||||
setup.add_command(setup_env)
|
|
||||||
setup.add_command(setup_procfile)
|
|
||||||
setup.add_command(_setup_socketio)
|
|
||||||
setup.add_command(setup_config)
|
|
||||||
setup.add_command(setup_production)
|
|
||||||
|
|
||||||
## Config
|
|
||||||
## Not DRY
|
|
||||||
@click.group()
|
|
||||||
def config():
|
|
||||||
"change bench configuration"
|
|
||||||
pass
|
|
||||||
|
|
||||||
@click.command('auto_update')
|
|
||||||
@click.argument('state', type=click.Choice(['on', 'off']))
|
|
||||||
def config_auto_update(state):
|
|
||||||
"Enable/Disable auto update for bench"
|
|
||||||
state = True if state == 'on' else False
|
|
||||||
update_config({'auto_update': state})
|
|
||||||
|
|
||||||
@click.command('restart_supervisor_on_update')
|
|
||||||
@click.argument('state', type=click.Choice(['on', 'off']))
|
|
||||||
def config_restart_supervisor_on_update(state):
|
|
||||||
"Enable/Disable auto restart of supervisor processes"
|
|
||||||
state = True if state == 'on' else False
|
|
||||||
update_config({'restart_supervisor_on_update': state})
|
|
||||||
|
|
||||||
@click.command('update_bench_on_update')
|
|
||||||
@click.argument('state', type=click.Choice(['on', 'off']))
|
|
||||||
def config_update_bench_on_update(state):
|
|
||||||
"Enable/Disable bench updates on running bench update"
|
|
||||||
state = True if state == 'on' else False
|
|
||||||
update_config({'update_bench_on_update': state})
|
|
||||||
|
|
||||||
@click.command('dns_multitenant')
|
|
||||||
@click.argument('state', type=click.Choice(['on', 'off']))
|
|
||||||
def config_dns_multitenant(state):
|
|
||||||
"Enable/Disable bench updates on running bench update"
|
|
||||||
state = True if state == 'on' else False
|
|
||||||
update_config({'dns_multitenant': state})
|
|
||||||
|
|
||||||
@click.command('serve_default_site')
|
|
||||||
@click.argument('state', type=click.Choice(['on', 'off']))
|
|
||||||
def config_serve_default_site(state):
|
|
||||||
"Configure nginx to serve the default site on port 80"
|
|
||||||
state = True if state == 'on' else False
|
|
||||||
update_config({'serve_default_site': state})
|
|
||||||
|
|
||||||
@click.command('rebase_on_pull')
|
|
||||||
@click.argument('state', type=click.Choice(['on', 'off']))
|
|
||||||
def config_rebase_on_pull(state):
|
|
||||||
"Rebase repositories on pulling"
|
|
||||||
state = True if state == 'on' else False
|
|
||||||
update_config({'rebase_on_pull': state})
|
|
||||||
|
|
||||||
@click.command('http_timeout')
|
|
||||||
@click.argument('seconds', type=int)
|
|
||||||
def config_http_timeout(seconds):
|
|
||||||
"set http timeout"
|
|
||||||
update_config({'http_timeout': seconds})
|
|
||||||
|
|
||||||
config.add_command(config_auto_update)
|
|
||||||
config.add_command(config_update_bench_on_update)
|
|
||||||
config.add_command(config_restart_supervisor_on_update)
|
|
||||||
config.add_command(config_dns_multitenant)
|
|
||||||
config.add_command(config_serve_default_site)
|
|
||||||
config.add_command(config_http_timeout)
|
|
||||||
|
|
||||||
@click.command('download-translations')
|
|
||||||
def _download_translations():
|
|
||||||
"Download latest translations"
|
|
||||||
download_translations_p()
|
|
||||||
|
|
||||||
#Bench commands
|
|
||||||
|
|
||||||
bench.add_command(init)
|
|
||||||
bench.add_command(get_app)
|
|
||||||
bench.add_command(new_app)
|
|
||||||
bench.add_command(new_site)
|
|
||||||
bench.add_command(setup)
|
|
||||||
bench.add_command(_update)
|
|
||||||
bench.add_command(restart)
|
|
||||||
bench.add_command(config)
|
|
||||||
bench.add_command(start)
|
|
||||||
bench.add_command(set_nginx_port)
|
|
||||||
bench.add_command(_set_ssl_certificate)
|
|
||||||
bench.add_command(_set_ssl_certificate_key)
|
|
||||||
bench.add_command(_set_mariadb_host)
|
|
||||||
bench.add_command(set_default_site)
|
|
||||||
bench.add_command(_switch_to_master)
|
|
||||||
bench.add_command(_switch_to_develop)
|
|
||||||
bench.add_command(_switch_to_v4)
|
|
||||||
bench.add_command(_switch_to_v5)
|
|
||||||
bench.add_command(shell)
|
|
||||||
bench.add_command(_backup_all_sites)
|
|
||||||
bench.add_command(_backup_site)
|
|
||||||
bench.add_command(_release)
|
|
||||||
bench.add_command(set_url_root)
|
|
||||||
bench.add_command(retry_upgrade)
|
|
||||||
bench.add_command(_download_translations)
|
|
||||||
|
53
bench/commands/__init__.py
Normal file
53
bench/commands/__init__.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import click
|
||||||
|
global FRAPPE_VERSION
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def bench_command(bench='.'):
|
||||||
|
"Bench manager for Frappe"
|
||||||
|
from bench.app import get_current_frappe_version
|
||||||
|
from bench.utils import setup_logging
|
||||||
|
|
||||||
|
# TODO add bench path context
|
||||||
|
global FRAPPE_VERSION
|
||||||
|
FRAPPE_VERSION = get_current_frappe_version()
|
||||||
|
setup_logging(bench=bench)
|
||||||
|
|
||||||
|
|
||||||
|
from bench.commands.make import init, get_app, new_app, new_site
|
||||||
|
bench_command.add_command(init)
|
||||||
|
bench_command.add_command(get_app)
|
||||||
|
bench_command.add_command(new_app)
|
||||||
|
bench_command.add_command(new_site)
|
||||||
|
|
||||||
|
|
||||||
|
from bench.commands.update import update, retry_upgrade, switch_to_master, switch_to_develop, switch_to_v4, switch_to_v5
|
||||||
|
bench_command.add_command(update)
|
||||||
|
bench_command.add_command(retry_upgrade)
|
||||||
|
bench_command.add_command(switch_to_master)
|
||||||
|
bench_command.add_command(switch_to_develop)
|
||||||
|
bench_command.add_command(switch_to_v4)
|
||||||
|
bench_command.add_command(switch_to_v5)
|
||||||
|
|
||||||
|
|
||||||
|
from bench.commands.utils import (start, restart, set_nginx_port, set_ssl_certificate, set_ssl_certificate_key, set_url_root,
|
||||||
|
set_mariadb_host, set_default_site, download_translations, shell, backup_site, backup_all_sites, release)
|
||||||
|
bench_command.add_command(start)
|
||||||
|
bench_command.add_command(restart)
|
||||||
|
bench_command.add_command(set_nginx_port)
|
||||||
|
bench_command.add_command(set_ssl_certificate)
|
||||||
|
bench_command.add_command(set_ssl_certificate_key)
|
||||||
|
bench_command.add_command(set_url_root)
|
||||||
|
bench_command.add_command(set_mariadb_host)
|
||||||
|
bench_command.add_command(set_default_site)
|
||||||
|
bench_command.add_command(download_translations)
|
||||||
|
bench_command.add_command(shell)
|
||||||
|
bench_command.add_command(backup_site)
|
||||||
|
bench_command.add_command(backup_all_sites)
|
||||||
|
bench_command.add_command(release)
|
||||||
|
|
||||||
|
|
||||||
|
from bench.commands.setup import setup
|
||||||
|
bench_command.add_command(setup)
|
||||||
|
|
||||||
|
from bench.commands.config import config
|
||||||
|
bench_command.add_command(config)
|
72
bench/commands/config.py
Normal file
72
bench/commands/config.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import click
|
||||||
|
from bench.config.common_site_config import update_config
|
||||||
|
|
||||||
|
## Config
|
||||||
|
## Not DRY
|
||||||
|
@click.group()
|
||||||
|
def config():
|
||||||
|
"change bench configuration"
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('auto_update')
|
||||||
|
@click.argument('state', type=click.Choice(['on', 'off']))
|
||||||
|
def config_auto_update(state):
|
||||||
|
"Enable/Disable auto update for bench"
|
||||||
|
state = True if state == 'on' else False
|
||||||
|
update_config({'auto_update': state})
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('restart_supervisor_on_update')
|
||||||
|
@click.argument('state', type=click.Choice(['on', 'off']))
|
||||||
|
def config_restart_supervisor_on_update(state):
|
||||||
|
"Enable/Disable auto restart of supervisor processes"
|
||||||
|
state = True if state == 'on' else False
|
||||||
|
update_config({'restart_supervisor_on_update': state})
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('update_bench_on_update')
|
||||||
|
@click.argument('state', type=click.Choice(['on', 'off']))
|
||||||
|
def config_update_bench_on_update(state):
|
||||||
|
"Enable/Disable bench updates on running bench update"
|
||||||
|
state = True if state == 'on' else False
|
||||||
|
update_config({'update_bench_on_update': state})
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('dns_multitenant')
|
||||||
|
@click.argument('state', type=click.Choice(['on', 'off']))
|
||||||
|
def config_dns_multitenant(state):
|
||||||
|
"Enable/Disable bench updates on running bench update"
|
||||||
|
state = True if state == 'on' else False
|
||||||
|
update_config({'dns_multitenant': state})
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('serve_default_site')
|
||||||
|
@click.argument('state', type=click.Choice(['on', 'off']))
|
||||||
|
def config_serve_default_site(state):
|
||||||
|
"Configure nginx to serve the default site on port 80"
|
||||||
|
state = True if state == 'on' else False
|
||||||
|
update_config({'serve_default_site': state})
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('rebase_on_pull')
|
||||||
|
@click.argument('state', type=click.Choice(['on', 'off']))
|
||||||
|
def config_rebase_on_pull(state):
|
||||||
|
"Rebase repositories on pulling"
|
||||||
|
state = True if state == 'on' else False
|
||||||
|
update_config({'rebase_on_pull': state})
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('http_timeout')
|
||||||
|
@click.argument('seconds', type=int)
|
||||||
|
def config_http_timeout(seconds):
|
||||||
|
"set http timeout"
|
||||||
|
update_config({'http_timeout': seconds})
|
||||||
|
|
||||||
|
|
||||||
|
config.add_command(config_auto_update)
|
||||||
|
config.add_command(config_update_bench_on_update)
|
||||||
|
config.add_command(config_restart_supervisor_on_update)
|
||||||
|
config.add_command(config_dns_multitenant)
|
||||||
|
config.add_command(config_serve_default_site)
|
||||||
|
config.add_command(config_http_timeout)
|
48
bench/commands/make.py
Normal file
48
bench/commands/make.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import click
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.argument('path')
|
||||||
|
@click.option('--apps_path', default=None, help="path to json files with apps to install after init")
|
||||||
|
@click.option('--frappe-path', default=None, help="path to frappe repo")
|
||||||
|
@click.option('--frappe-branch', default=None, help="path to frappe repo")
|
||||||
|
@click.option('--no-procfile', is_flag=True, help="Pull changes in all the apps in bench")
|
||||||
|
@click.option('--no-backups',is_flag=True, help="Run migrations for all sites in the bench")
|
||||||
|
@click.option('--no-auto-update',is_flag=True, help="Build JS and CSS artifacts for the bench")
|
||||||
|
@click.option('--verbose',is_flag=True, help="Verbose output during install")
|
||||||
|
def init(path, apps_path, frappe_path, frappe_branch, no_procfile, no_backups,
|
||||||
|
no_auto_update, verbose):
|
||||||
|
"Create a new bench"
|
||||||
|
from bench.utils import init
|
||||||
|
init(path, apps_path=apps_path, no_procfile=no_procfile, no_backups=no_backups,
|
||||||
|
no_auto_update=no_auto_update, frappe_path=frappe_path, frappe_branch=frappe_branch, verbose=verbose)
|
||||||
|
click.echo('Bench {} initialized'.format(path))
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('get-app')
|
||||||
|
@click.argument('name')
|
||||||
|
@click.argument('git-url')
|
||||||
|
@click.option('--branch', default=None, help="branch to checkout")
|
||||||
|
def get_app(name, git_url, branch):
|
||||||
|
"clone an app from the internet and set it up in your bench"
|
||||||
|
from bench.app import get_app
|
||||||
|
get_app(name, git_url, branch=branch)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('new-app')
|
||||||
|
@click.argument('app-name')
|
||||||
|
def new_app(app_name):
|
||||||
|
"start a new app"
|
||||||
|
from bench.app import new_app
|
||||||
|
new_app(app_name)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('new-site')
|
||||||
|
@click.option('--mariadb-root-password', help="MariaDB root password")
|
||||||
|
@click.option('--admin-password', help="admin password to set for site")
|
||||||
|
@click.argument('site')
|
||||||
|
def new_site(site, mariadb_root_password=None, admin_password=None):
|
||||||
|
"Create a new site in the bench"
|
||||||
|
from bench.utils import new_site
|
||||||
|
new_site(site, mariadb_root_password=mariadb_root_password, admin_password=admin_password)
|
||||||
|
|
||||||
|
|
97
bench/commands/setup.py
Normal file
97
bench/commands/setup.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import click
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def setup():
|
||||||
|
"Setup bench"
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('sudoers')
|
||||||
|
@click.argument('user')
|
||||||
|
def setup_sudoers(user):
|
||||||
|
"Add commands to sudoers list for execution without password"
|
||||||
|
from bench.utils import setup_sudoers
|
||||||
|
setup_sudoers(user)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('nginx')
|
||||||
|
def setup_nginx():
|
||||||
|
"generate config for nginx"
|
||||||
|
from bench.config.nginx import make_nginx_conf
|
||||||
|
make_nginx_conf(bench=".")
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('supervisor')
|
||||||
|
def setup_supervisor():
|
||||||
|
"generate config for supervisor"
|
||||||
|
from bench.config.supervisor import generate_supervisor_config
|
||||||
|
generate_supervisor_config()
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('redis')
|
||||||
|
def setup_redis():
|
||||||
|
"generate config for redis cache"
|
||||||
|
from bench.config.redis import generate_config
|
||||||
|
generate_config('.')
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('production')
|
||||||
|
@click.argument('user')
|
||||||
|
def setup_production(user):
|
||||||
|
"setup bench for production"
|
||||||
|
from bench.config.production_setup import setup_production
|
||||||
|
setup_production(user=user)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('auto-update')
|
||||||
|
def setup_auto_update():
|
||||||
|
"Add cronjob for bench auto update"
|
||||||
|
from bench.utils import setup_auto_update
|
||||||
|
setup_auto_update()
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('backups')
|
||||||
|
def setup_backups():
|
||||||
|
"Add cronjob for bench backups"
|
||||||
|
from bench.utils import setup_backups
|
||||||
|
setup_backups()
|
||||||
|
|
||||||
|
@click.command('env')
|
||||||
|
def setup_env():
|
||||||
|
"Setup virtualenv for bench"
|
||||||
|
from bench.utils import setup_env
|
||||||
|
setup_env()
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('procfile')
|
||||||
|
def setup_procfile():
|
||||||
|
"Setup Procfile for bench start"
|
||||||
|
from bench.config.procfile import setup_procfile
|
||||||
|
setup_procfile('.')
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('socketio')
|
||||||
|
def setup_socketio():
|
||||||
|
"Setup node deps for socketio server"
|
||||||
|
from bench.utils import setup_socketio
|
||||||
|
setup_socketio()
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('config')
|
||||||
|
def setup_config():
|
||||||
|
"overwrite or make config.json"
|
||||||
|
from bench.config.common_site_config import make_config
|
||||||
|
make_config('.')
|
||||||
|
|
||||||
|
|
||||||
|
setup.add_command(setup_sudoers)
|
||||||
|
setup.add_command(setup_nginx)
|
||||||
|
setup.add_command(setup_supervisor)
|
||||||
|
setup.add_command(setup_redis)
|
||||||
|
setup.add_command(setup_production)
|
||||||
|
setup.add_command(setup_auto_update)
|
||||||
|
setup.add_command(setup_backups)
|
||||||
|
setup.add_command(setup_env)
|
||||||
|
setup.add_command(setup_procfile)
|
||||||
|
setup.add_command(setup_socketio)
|
||||||
|
setup.add_command(setup_config)
|
156
bench/commands/update.py
Normal file
156
bench/commands/update.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import click
|
||||||
|
import sys, os
|
||||||
|
from bench.config.common_site_config import get_config
|
||||||
|
from bench.app import pull_all_apps, is_version_upgrade
|
||||||
|
from bench.utils import (update_bench, validate_upgrade, pre_upgrade, post_upgrade, before_update,
|
||||||
|
update_requirements, backup_all_sites, patch_sites, build_assets, restart_supervisor_processes)
|
||||||
|
|
||||||
|
#TODO: Not DRY
|
||||||
|
@click.command('update')
|
||||||
|
@click.option('--pull', is_flag=True, help="Pull changes in all the apps in bench")
|
||||||
|
@click.option('--patch',is_flag=True, help="Run migrations for all sites in the bench")
|
||||||
|
@click.option('--build',is_flag=True, help="Build JS and CSS artifacts for the bench")
|
||||||
|
@click.option('--bench',is_flag=True, help="Update bench")
|
||||||
|
@click.option('--requirements',is_flag=True, help="Update requirements")
|
||||||
|
@click.option('--restart-supervisor',is_flag=True, help="restart supervisor processes after update")
|
||||||
|
@click.option('--auto',is_flag=True)
|
||||||
|
@click.option('--upgrade',is_flag=True)
|
||||||
|
@click.option('--no-backup',is_flag=True)
|
||||||
|
@click.option('--force',is_flag=True)
|
||||||
|
def update(pull=False, patch=False, build=False, bench=False, auto=False, restart_supervisor=False, requirements=False, no_backup=False, upgrade=False, force=False):
|
||||||
|
"Update bench"
|
||||||
|
|
||||||
|
if not (pull or patch or build or bench or requirements):
|
||||||
|
pull, patch, build, bench, requirements = True, True, True, True, True
|
||||||
|
|
||||||
|
conf = get_config(".")
|
||||||
|
|
||||||
|
version_upgrade = is_version_upgrade()
|
||||||
|
|
||||||
|
if version_upgrade[0] and not upgrade:
|
||||||
|
print
|
||||||
|
print
|
||||||
|
print "This update will cause a major version change in Frappe/ERPNext from {0} to {1}.".format(*version_upgrade[1:])
|
||||||
|
print "This would take significant time to migrate and might break custom apps. Please run `bench update --upgrade` to confirm."
|
||||||
|
print
|
||||||
|
print "You can stay on the latest stable release by running `bench switch-to-master` or pin your bench to {0} by running `bench switch-to-v{0}`".format(version_upgrade[1])
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if conf.get('release_bench'):
|
||||||
|
print 'Release bench, cannot update'
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if auto:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if bench and conf.get('update_bench_on_update'):
|
||||||
|
update_bench()
|
||||||
|
restart_update({
|
||||||
|
'pull': pull,
|
||||||
|
'patch': patch,
|
||||||
|
'build': build,
|
||||||
|
'requirements': requirements,
|
||||||
|
'no-backup': no_backup,
|
||||||
|
'restart-supervisor': restart_supervisor,
|
||||||
|
'upgrade': upgrade
|
||||||
|
})
|
||||||
|
|
||||||
|
_update(pull, patch, build, bench, auto, restart_supervisor, requirements, no_backup, upgrade, force=force)
|
||||||
|
|
||||||
|
|
||||||
|
def _update(pull=False, patch=False, build=False, bench=False, auto=False, restart_supervisor=False, requirements=False, no_backup=False, upgrade=False, bench_path='.', force=False):
|
||||||
|
conf = get_config(bench=bench_path)
|
||||||
|
version_upgrade = is_version_upgrade(bench=bench_path)
|
||||||
|
|
||||||
|
if version_upgrade[0] and not upgrade:
|
||||||
|
raise Exception("Major Version Upgrade")
|
||||||
|
|
||||||
|
if upgrade and (version_upgrade[0] or (not version_upgrade[0] and force)):
|
||||||
|
validate_upgrade(version_upgrade[1], version_upgrade[2], bench=bench_path)
|
||||||
|
|
||||||
|
before_update(bench=bench_path, requirements=requirements)
|
||||||
|
|
||||||
|
if pull:
|
||||||
|
pull_all_apps(bench=bench_path)
|
||||||
|
|
||||||
|
if requirements:
|
||||||
|
update_requirements(bench=bench_path)
|
||||||
|
|
||||||
|
if upgrade and (version_upgrade[0] or (not version_upgrade[0] and force)):
|
||||||
|
pre_upgrade(version_upgrade[1], version_upgrade[2], bench=bench_path)
|
||||||
|
import utils, app
|
||||||
|
reload(utils)
|
||||||
|
reload(app)
|
||||||
|
|
||||||
|
if patch:
|
||||||
|
if not no_backup:
|
||||||
|
backup_all_sites(bench=bench_path)
|
||||||
|
patch_sites(bench=bench_path)
|
||||||
|
if build:
|
||||||
|
build_assets(bench=bench_path)
|
||||||
|
if upgrade and (version_upgrade[0] or (not version_upgrade[0] and force)):
|
||||||
|
post_upgrade(version_upgrade[1], version_upgrade[2], bench=bench_path)
|
||||||
|
if restart_supervisor or conf.get('restart_supervisor_on_update'):
|
||||||
|
restart_supervisor_processes(bench=bench_path)
|
||||||
|
|
||||||
|
print "_"*80
|
||||||
|
print "Bench: Open source installer + admin for Frappe and ERPNext (https://erpnext.com)"
|
||||||
|
print
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('retry-upgrade')
|
||||||
|
@click.option('--version', default=5)
|
||||||
|
def retry_upgrade(version):
|
||||||
|
pull_all_apps()
|
||||||
|
patch_sites()
|
||||||
|
build_assets()
|
||||||
|
post_upgrade(version-1, version)
|
||||||
|
|
||||||
|
|
||||||
|
def restart_update(kwargs):
|
||||||
|
args = ['--'+k for k, v in kwargs.items() if v]
|
||||||
|
os.execv(sys.argv[0], sys.argv[:2] + args)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('switch-to-master')
|
||||||
|
@click.option('--upgrade',is_flag=True)
|
||||||
|
def switch_to_master(upgrade=False):
|
||||||
|
"Switch frappe and erpnext to master branch"
|
||||||
|
from bench.app import switch_to_master
|
||||||
|
switch_to_master(upgrade=upgrade)
|
||||||
|
print
|
||||||
|
print 'Switched to master'
|
||||||
|
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('switch-to-develop')
|
||||||
|
@click.option('--upgrade',is_flag=True)
|
||||||
|
def switch_to_develop(upgrade=False):
|
||||||
|
"Switch frappe and erpnext to develop branch"
|
||||||
|
from bench.app import switch_to_develop
|
||||||
|
switch_to_develop(upgrade=upgrade)
|
||||||
|
print
|
||||||
|
print 'Switched to develop'
|
||||||
|
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('switch-to-v4')
|
||||||
|
@click.option('--upgrade',is_flag=True)
|
||||||
|
def switch_to_v4(upgrade=False):
|
||||||
|
"Switch frappe and erpnext to v4 branch"
|
||||||
|
from bench.app import switch_to_v4
|
||||||
|
switch_to_v4(upgrade=upgrade)
|
||||||
|
print
|
||||||
|
print 'Switched to v4'
|
||||||
|
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('switch-to-v5')
|
||||||
|
@click.option('--upgrade',is_flag=True)
|
||||||
|
def switch_to_v5(upgrade=False):
|
||||||
|
"Switch frappe and erpnext to v4 branch"
|
||||||
|
from bench.app import switch_to_v5
|
||||||
|
switch_to_v5(upgrade=upgrade)
|
||||||
|
print
|
||||||
|
print 'Switched to v5'
|
||||||
|
print 'Please run `bench update --patch` to be safe from any differences in database schema'
|
122
bench/commands/utils.py
Normal file
122
bench/commands/utils.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import click
|
||||||
|
import sys, os, copy
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('start')
|
||||||
|
@click.option('--no-dev', is_flag=True)
|
||||||
|
def start(no_dev=False):
|
||||||
|
"Start Frappe development processes"
|
||||||
|
from bench.utils import start
|
||||||
|
start(no_dev=no_dev)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('restart')
|
||||||
|
def restart():
|
||||||
|
"Restart supervisor processes"
|
||||||
|
from bench.utils import restart_supervisor_processes
|
||||||
|
restart_supervisor_processes()
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('set-nginx-port')
|
||||||
|
@click.argument('site')
|
||||||
|
@click.argument('port', type=int)
|
||||||
|
def set_nginx_port(site, port):
|
||||||
|
"Set nginx port for site"
|
||||||
|
from bench.utils import set_nginx_port
|
||||||
|
set_nginx_port(site, port)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('set-ssl-certificate')
|
||||||
|
@click.argument('site')
|
||||||
|
@click.argument('ssl-certificate-path')
|
||||||
|
def set_ssl_certificate(site, ssl_certificate_path):
|
||||||
|
"Set ssl certificate path for site"
|
||||||
|
from bench.utils import set_ssl_certificate
|
||||||
|
set_ssl_certificate(site, ssl_certificate_path)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('set-ssl-key')
|
||||||
|
@click.argument('site')
|
||||||
|
@click.argument('ssl-certificate-key-path')
|
||||||
|
def set_ssl_certificate_key(site, ssl_certificate_key_path):
|
||||||
|
"Set ssl certificate private key path for site"
|
||||||
|
from bench.utils import set_ssl_certificate_key
|
||||||
|
set_ssl_certificate_key(site, ssl_certificate_key_path)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('set-url-root')
|
||||||
|
@click.argument('site')
|
||||||
|
@click.argument('url-root')
|
||||||
|
def set_url_root(site, url_root):
|
||||||
|
"Set url root for site"
|
||||||
|
from bench.utils import set_url_root
|
||||||
|
set_url_root(site, url_root)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('set-mariadb-host')
|
||||||
|
@click.argument('host')
|
||||||
|
def set_mariadb_host(host):
|
||||||
|
"Set MariaDB host for bench"
|
||||||
|
from bench.utils import set_mariadb_host
|
||||||
|
set_mariadb_host(host)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('set-default-site')
|
||||||
|
@click.argument('site')
|
||||||
|
def set_default_site(site):
|
||||||
|
"Set default site for bench"
|
||||||
|
from bench.utils import set_default_site
|
||||||
|
set_default_site(site)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('download-translations')
|
||||||
|
def download_translations():
|
||||||
|
"Download latest translations"
|
||||||
|
from bench.utils import download_translations_p
|
||||||
|
download_translations_p()
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def shell(bench='.'):
|
||||||
|
if not os.environ.get('SHELL'):
|
||||||
|
print "Cannot get shell"
|
||||||
|
sys.exit(1)
|
||||||
|
if not os.path.exists('sites'):
|
||||||
|
print "sites dir doesn't exist"
|
||||||
|
sys.exit(1)
|
||||||
|
env = copy.copy(os.environ)
|
||||||
|
env['PS1'] = '(' + os.path.basename(os.path.dirname(os.path.abspath(__file__))) + ')' + env.get('PS1', '')
|
||||||
|
env['PATH'] = os.path.dirname(os.path.abspath(os.path.join('env','bin')) + ':' + env['PATH'])
|
||||||
|
os.chdir('sites')
|
||||||
|
os.execve(env['SHELL'], [env['SHELL']], env)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('backup')
|
||||||
|
@click.argument('site')
|
||||||
|
def backup_site(site):
|
||||||
|
"backup site"
|
||||||
|
from bench.utils import get_sites, backup_site
|
||||||
|
if not site in get_sites(bench='.'):
|
||||||
|
print 'site not found'
|
||||||
|
sys.exit(1)
|
||||||
|
backup_site(site, bench='.')
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('backup-all-sites')
|
||||||
|
def backup_all_sites():
|
||||||
|
"backup all sites"
|
||||||
|
from bench.utils import backup_all_sites
|
||||||
|
backup_all_sites(bench='.')
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('release')
|
||||||
|
@click.argument('app', type=click.Choice(['frappe', 'erpnext', 'erpnext_shopify', 'paypal_integration']))
|
||||||
|
@click.argument('bump-type', type=click.Choice(['major', 'minor', 'patch']))
|
||||||
|
@click.option('--develop', default='develop')
|
||||||
|
@click.option('--master', default='master')
|
||||||
|
def release(app, bump_type, develop, master):
|
||||||
|
"Release app (internal to the Frappe team)"
|
||||||
|
from .release import release
|
||||||
|
repo = os.path.join('apps', app)
|
||||||
|
release(repo, bump_type, develop, master)
|
||||||
|
|
@ -7,24 +7,23 @@
|
|||||||
mysql_conf_dir: /etc/my.cnf.d/
|
mysql_conf_dir: /etc/my.cnf.d/
|
||||||
wkhtmltopdf_version: 0.12.2.1
|
wkhtmltopdf_version: 0.12.2.1
|
||||||
|
|
||||||
vars_prompt:
|
|
||||||
- name: mysql_root_password
|
|
||||||
prompt: "MySQL Root Password"
|
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
|
||||||
# install pre-requisites
|
# install pre-requisites
|
||||||
|
- name: add epel repo
|
||||||
|
yum: name="https://dl.fedoraproject.org/pub/epel/{{ ansible_lsb.major_release }}/x86_64/e/epel-release-*.rpm" state=present
|
||||||
|
become: yes
|
||||||
|
become_user: root
|
||||||
|
|
||||||
- name: development tools package
|
- name: development tools package
|
||||||
yum: name="@Development tools" state=present
|
yum: name="@Development tools" state=present
|
||||||
|
become: yes
|
||||||
|
become_user: root
|
||||||
|
|
||||||
- name: install prequisites
|
- name: install prequisites
|
||||||
yum: pkg={{ item }} state=present
|
yum: pkg={{ item }} state=present
|
||||||
with_items:
|
with_items:
|
||||||
# basic installs
|
# basic installs
|
||||||
- python-setuptools
|
|
||||||
- python-devel
|
|
||||||
- python-pip
|
|
||||||
|
|
||||||
- redis
|
- redis
|
||||||
- nodejs
|
- nodejs
|
||||||
- npm
|
- npm
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
---
|
---
|
||||||
- hosts: localhost
|
- hosts: localhost
|
||||||
|
vars_prompt:
|
||||||
|
- name: mysql_root_password
|
||||||
|
prompt: "MySQL Root Password"
|
||||||
|
when: ansible_distribution == 'Ubuntu'
|
||||||
|
|
||||||
- include: macosx.yml
|
- include: macosx.yml
|
||||||
when: ansible_distribution == 'MacOSX'
|
when: ansible_distribution == 'MacOSX'
|
||||||
- include: ubuntu.yml
|
- include: ubuntu.yml
|
||||||
|
@ -7,10 +7,6 @@
|
|||||||
mysql_conf_dir: /etc/mysql/conf.d/
|
mysql_conf_dir: /etc/mysql/conf.d/
|
||||||
wkhtmltopdf_version: 0.12.2.1
|
wkhtmltopdf_version: 0.12.2.1
|
||||||
|
|
||||||
vars_prompt:
|
|
||||||
- name: mysql_root_password
|
|
||||||
prompt: "MySQL Root Password"
|
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
|
||||||
# install pre-requisites
|
# install pre-requisites
|
||||||
@ -19,10 +15,6 @@
|
|||||||
with_items:
|
with_items:
|
||||||
# basic installs
|
# basic installs
|
||||||
- build-essential
|
- build-essential
|
||||||
- python-setuptools
|
|
||||||
- python-dev
|
|
||||||
- python-pip
|
|
||||||
|
|
||||||
- redis-server
|
- redis-server
|
||||||
- nodejs
|
- nodejs
|
||||||
- npm
|
- npm
|
||||||
|
@ -9,27 +9,47 @@ bench_repo = '/usr/local/frappe/bench-repo'
|
|||||||
|
|
||||||
def install_bench(args):
|
def install_bench(args):
|
||||||
# pre-requisites for bench repo cloning
|
# pre-requisites for bench repo cloning
|
||||||
|
success = run_os_command({
|
||||||
|
'apt-get': [
|
||||||
|
'sudo apt-get update',
|
||||||
|
'sudo apt-get install -y git build-essential python-setuptools python-dev'
|
||||||
|
],
|
||||||
|
'yum': [
|
||||||
|
'sudo yum groupinstall -y "Development tools"',
|
||||||
|
'sudo yum install -y git python-setuptools python-devel'
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
if not find_executable("git"):
|
||||||
|
success = run_os_command({
|
||||||
|
'brew': 'brew install git'
|
||||||
|
})
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
print 'Could not install pre-requisites. Please check for errors or install them manually.'
|
||||||
|
return
|
||||||
|
|
||||||
|
# secure pip installation
|
||||||
|
if not os.path.exists("get-pip.py"):
|
||||||
|
run_os_command({
|
||||||
|
'apt-get': 'wget https://bootstrap.pypa.io/get-pip.py',
|
||||||
|
'yum': 'wget https://bootstrap.pypa.io/get-pip.py'
|
||||||
|
})
|
||||||
|
|
||||||
run_os_command({
|
run_os_command({
|
||||||
"apt-get": "sudo apt-get update",
|
'apt-get': 'sudo python get-pip.py',
|
||||||
"yum": "yum groupinstall 'Development Tools'"
|
'yum': 'sudo python get-pip.py',
|
||||||
})
|
})
|
||||||
|
|
||||||
success = run_os_command({
|
success = run_os_command({
|
||||||
"apt-get": "sudo apt-get install -y git build-essential python-setuptools python-dev python-pip",
|
'pip': 'sudo pip install ansible'
|
||||||
"yum": "sudo yum install -y git python-setuptools python-devel python-pip",
|
|
||||||
"brew": "brew install git"
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
print "Could not install pre-requisites. Please check for errors or install them manually."
|
could_not_install('Ansible')
|
||||||
return
|
|
||||||
|
|
||||||
success = run_os_command({
|
|
||||||
"pip": "sudo pip install ansible"
|
|
||||||
})
|
|
||||||
|
|
||||||
if is_sudo_user():
|
if is_sudo_user():
|
||||||
raise Exception("Please run this script as a non-root user with sudo privileges, but without using sudo")
|
raise Exception('Please run this script as a non-root user with sudo privileges, but without using sudo')
|
||||||
|
|
||||||
# clone bench repo
|
# clone bench repo
|
||||||
clone_bench_repo()
|
clone_bench_repo()
|
||||||
@ -43,23 +63,23 @@ def install_python27():
|
|||||||
if version == (2, 7):
|
if version == (2, 7):
|
||||||
return
|
return
|
||||||
|
|
||||||
print "Installing Python 2.7"
|
print 'Installing Python 2.7'
|
||||||
|
|
||||||
# install python 2.7
|
# install python 2.7
|
||||||
success = run_os_command({
|
success = run_os_command({
|
||||||
"apt-get": "sudo apt-get install -y python2.7",
|
'apt-get': 'sudo apt-get install -y python2.7',
|
||||||
"yum": "sudo yum install -y python27",
|
'yum': 'sudo yum install -y python27',
|
||||||
"brew": "brew install python"
|
'brew': 'brew install python'
|
||||||
})
|
})
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
could_not_install("Python 2.7")
|
could_not_install('Python 2.7')
|
||||||
|
|
||||||
# replace current python with python2.7
|
# replace current python with python2.7
|
||||||
os.execvp("python2.7", ([] if is_sudo_user() else ["sudo"]) + ["python2.7", __file__] + sys.argv[1:])
|
os.execvp('python2.7', ([] if is_sudo_user() else ['sudo']) + ['python2.7', __file__] + sys.argv[1:])
|
||||||
|
|
||||||
def clone_bench_repo():
|
def clone_bench_repo():
|
||||||
"""Clones the bench repository in the user folder"""
|
'''Clones the bench repository in the user folder'''
|
||||||
|
|
||||||
if os.path.exists(bench_repo):
|
if os.path.exists(bench_repo):
|
||||||
return 0
|
return 0
|
||||||
@ -76,30 +96,35 @@ def clone_bench_repo():
|
|||||||
})
|
})
|
||||||
|
|
||||||
success = run_os_command(
|
success = run_os_command(
|
||||||
{"git": "git clone https://github.com/frappe/bench {bench_repo} --depth 1 --branch new-install".format(bench_repo=bench_repo)}
|
{'git': 'git clone https://github.com/frappe/bench {bench_repo} --depth 1 --branch new-install'.format(bench_repo=bench_repo)}
|
||||||
)
|
)
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def run_os_command(command_map):
|
def run_os_command(command_map):
|
||||||
"""command_map is a dictionary of {"executable": command}. For ex. {"apt-get": "sudo apt-get install -y python2.7"} """
|
'''command_map is a dictionary of {'executable': command}. For ex. {'apt-get': 'sudo apt-get install -y python2.7'} '''
|
||||||
success = False
|
success = True
|
||||||
for executable, command in command_map.items():
|
for executable, commands in command_map.items():
|
||||||
if find_executable(executable):
|
if find_executable(executable):
|
||||||
returncode = subprocess.check_call(command.split())
|
if isinstance(commands, basestring):
|
||||||
success = ( returncode == 0 )
|
commands = [commands]
|
||||||
|
|
||||||
|
for command in commands:
|
||||||
|
returncode = subprocess.check_call(command, shell=True)
|
||||||
|
success = success and ( returncode == 0 )
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def could_not_install(package):
|
def could_not_install(package):
|
||||||
raise Exception("Could not install {0}. Please install it manually.".format(package))
|
raise Exception('Could not install {0}. Please install it manually.'.format(package))
|
||||||
|
|
||||||
def is_sudo_user():
|
def is_sudo_user():
|
||||||
return os.geteuid() == 0
|
return os.geteuid() == 0
|
||||||
|
|
||||||
def run_playbook(playbook_name, sudo=False):
|
def run_playbook(playbook_name, sudo=False):
|
||||||
args = ["ansible-playbook", "-c", "local", playbook_name]
|
args = ['ansible-playbook', '-c', 'local', playbook_name]
|
||||||
if sudo:
|
if sudo:
|
||||||
args.append('-K')
|
args.append('-K')
|
||||||
|
|
||||||
@ -111,12 +136,12 @@ def parse_commandline_args():
|
|||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Frappe Installer')
|
parser = argparse.ArgumentParser(description='Frappe Installer')
|
||||||
parser.add_argument('--develop', dest='develop', action='store_true', default=False,
|
parser.add_argument('--develop', dest='develop', action='store_true', default=False,
|
||||||
help="Install developer setup")
|
help='Install developer setup')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
import argparse
|
import argparse
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
7
requirements.txt
Normal file
7
requirements.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Click
|
||||||
|
jinja2
|
||||||
|
virtualenv
|
||||||
|
requests
|
||||||
|
honcho
|
||||||
|
semantic_version
|
||||||
|
GitPython==0.3.2.rc1
|
24
setup.py
24
setup.py
@ -1,22 +1,28 @@
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
from pip.req import parse_requirements
|
||||||
|
import re
|
||||||
|
import ast
|
||||||
|
|
||||||
|
# get version from __version__ variable in bench/__init__.py
|
||||||
|
_version_re = re.compile(r'__version__\s+=\s+(.*)')
|
||||||
|
|
||||||
|
with open('bench/__init__.py', 'rb') as f:
|
||||||
|
version = str(ast.literal_eval(_version_re.search(
|
||||||
|
f.read().decode('utf-8')).group(1)))
|
||||||
|
|
||||||
|
requirements = parse_requirements("requirements.txt", session="")
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='bench',
|
name='bench',
|
||||||
description='Metadata driven, full-stack web framework',
|
description='Metadata driven, full-stack web framework',
|
||||||
author='Frappe Technologies',
|
author='Frappe Technologies',
|
||||||
author_email='info@frappe.io',
|
author_email='info@frappe.io',
|
||||||
|
version=version,
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=[
|
install_requires=[str(ir.req) for ir in requirements],
|
||||||
'Click',
|
dependency_links=[str(ir._link) for ir in requirements if ir._link],
|
||||||
'jinja2',
|
|
||||||
'virtualenv',
|
|
||||||
'requests',
|
|
||||||
'honcho',
|
|
||||||
'semantic_version',
|
|
||||||
'GitPython==0.3.2.RC1'
|
|
||||||
],
|
|
||||||
entry_points='''
|
entry_points='''
|
||||||
[console_scripts]
|
[console_scripts]
|
||||||
bench=bench.cli:cli
|
bench=bench.cli:cli
|
||||||
|
Loading…
Reference in New Issue
Block a user