Skip to content

Commit

Permalink
fix: move update to utils
Browse files Browse the repository at this point in the history
  - update.py
    * chore: drop auto_update options
    * fix: reloading bench modules post requirements setup (seemed
    unecessary and randomly crashed `bench start` process)
    * docs: added help for commands
    * chore: deprecated switch-to-master function

  - utils.py
    * sorted imports for readability
    * formatting and consistency
    * dropped unused setup_auto_update
    * dropped broken pre_upgrade function

Signed-off-by: Gavin D'souza <gavin18d@gmail.com>
  • Loading branch information
gavindsouza committed Feb 18, 2020
1 parent f1ea6fc commit 2713a2e
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 156 deletions.
157 changes: 29 additions & 128 deletions bench/commands/update.py
Original file line number Diff line number Diff line change
@@ -1,160 +1,61 @@
import click
import sys
# imports - standard imports
import os
from bench.config.common_site_config import get_config, update_config
from bench.app import pull_all_apps, is_version_upgrade, validate_branch
from bench.utils import (update_bench, validate_upgrade, pre_upgrade, post_upgrade, before_update,
update_requirements, update_node_packages, backup_all_sites, patch_sites, build_assets,
restart_supervisor_processes, restart_systemd_processes, is_bench_directory)
from bench import patches
import sys

# imports - third party imports
import click
from six.moves import reload_module

# imports - module imports
from bench.app import pull_all_apps
from bench.utils import post_upgrade, patch_sites, build_assets


@click.command('update')
@click.option('--pull', is_flag=True, help="Pull changes in all the apps in bench")
@click.command('update', help="Updates bench tool and if executed in a bench directory, without any flags will backup, pull, setup requirements, build, run patches and restart bench. Using specific flags will only do certain tasks instead of all")
@click.option('--pull', is_flag=True, help="Pull updates for 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('--restart-systemd', is_flag=True, help="restart systemd units after update")
@click.option('--auto', is_flag=True)
@click.option('--no-backup', is_flag=True)
@click.option('--force', is_flag=True)
@click.option('--build', is_flag=True, help="Build JS and CSS assets for the bench")
@click.option('--bench', is_flag=True, help="Update bench CLI tool")
@click.option('--requirements', is_flag=True, help="Update requirements. If run alone, equivalent to `bench setup requirements`")
@click.option('--restart-supervisor', is_flag=True, help="Restart supervisor processes after update")
@click.option('--restart-systemd', is_flag=True, help="Restart systemd units after update")
@click.option('--no-backup', is_flag=True, help="If this flag is set, sites won't be backed up prior to updates. Note: This is not recommended in production.")
@click.option('--force', is_flag=True, help="Forces major version upgrades")
@click.option('--reset', is_flag=True, help="Hard resets git branch's to their new states overriding any changes and overriding rebase on pull")
def update(pull=False, patch=False, build=False, bench=False, auto=False, restart_supervisor=False, restart_systemd=False, requirements=False, no_backup=False, force=False, reset=False):
"Update bench"

if not is_bench_directory():
"""Update only bench if bench update called from outside a bench"""
update_bench(bench_repo=True, requirements=True)
sys.exit()

if not (pull or patch or build or bench or requirements):
pull, patch, build, bench, requirements = True, True, True, True, True

if auto:
sys.exit(1)

patches.run(bench_path='.')
conf = get_config(".")

if bench and conf.get('update_bench_on_update'):
update_bench(bench_repo=True, requirements=False)
restart_update({
'pull': pull,
'patch': patch,
'build': build,
'requirements': requirements,
'no-backup': no_backup,
'restart-supervisor': restart_supervisor,
'reset': reset
})

if conf.get('release_bench'):
print('Release bench, cannot update')
sys.exit(1)

validate_branch()

version_upgrade = is_version_upgrade()
if version_upgrade[0]:
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.")
click.confirm('Do you want to continue?', abort=True)

_update(pull, patch, build, bench, auto, restart_supervisor, restart_systemd, requirements, no_backup, force=force, reset=reset)
def update(pull, patch, build, bench, requirements, restart_supervisor, restart_systemd, no_backup, force, reset):
from bench.utils import update
update(pull=pull, patch=patch, build=build, bench=bench, requirements=requirements, restart_supervisor=restart_supervisor, restart_systemd=restart_systemd, backup= not no_backup, force=force, reset=reset)

def _update(pull=False, patch=False, build=False, update_bench=False, auto=False, restart_supervisor=False,
restart_systemd=False, requirements=False, no_backup=False, bench_path='.', force=False, reset=False):
conf = get_config(bench_path=bench_path)
version_upgrade = is_version_upgrade(bench_path=bench_path)

if version_upgrade[0] or (not version_upgrade[0] and force):
validate_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)

before_update(bench_path=bench_path, requirements=requirements)

conf.update({ "maintenance_mode": 1, "pause_scheduler": 1 })
update_config(conf, bench_path=bench_path)

if not no_backup:
print('Backing up sites...')
backup_all_sites(bench_path=bench_path)

if pull:
pull_all_apps(bench_path=bench_path, reset=reset)

if requirements:
update_requirements(bench_path=bench_path)
update_node_packages(bench_path=bench_path)

if version_upgrade[0] or (not version_upgrade[0] and force):
pre_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)
import bench.utils, bench.app
print('Reloading bench...')
reload_module(bench.utils)
reload_module(bench.app)

if patch:
print('Patching sites...')
patch_sites(bench_path=bench_path)
if build:
build_assets(bench_path=bench_path)
if version_upgrade[0] or (not version_upgrade[0] and force):
post_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)
if restart_supervisor or conf.get('restart_supervisor_on_update'):
restart_supervisor_processes(bench_path=bench_path)
if restart_systemd or conf.get('restart_systemd_on_update'):
restart_systemd_processes(bench_path=bench_path)

conf.update({ "maintenance_mode": 0, "pause_scheduler": 0 })
update_config(conf, bench_path=bench_path)

print("_"*80)
print("Bench: Deployment tool for Frappe and ERPNext (https://erpnext.org).")
print("Open source depends on your contributions, so please contribute bug reports, patches, fixes or cash and be a part of the community")
print()

@click.command('retry-upgrade')
@click.command('retry-upgrade', help="Retry a failed 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 list(kwargs.items()) if v]
os.execv(sys.argv[0], sys.argv[:2] + args)

@click.command('switch-to-branch')
@click.command('switch-to-branch', help="Switch all apps to specified branch, or specify apps separated by space")
@click.argument('branch')
@click.argument('apps', nargs=-1)
@click.option('--upgrade',is_flag=True)
def switch_to_branch(branch, apps, upgrade=False):
"Switch all apps to specified branch, or specify apps separated by space"
from bench.app import switch_to_branch
switch_to_branch(branch=branch, apps=list(apps), upgrade=upgrade)
print('Switched to ' + branch)
print('Please run `bench update --patch` to be safe from any differences in database schema')

@click.command('switch-to-master')

@click.command('switch-to-master', help="[DEPRECATED]: Switch frappe and erpnext to master branch")
def switch_to_master():
"Switch frappe and erpnext to master branch"
from bench.app import switch_to_master
switch_to_master(apps=['frappe', 'erpnext'])
print()
print('Switched to master')
print('Please run `bench update --patch` to be safe from any differences in database schema')
from bench.utils import log
log("`switch-to-master` has been deprecated as master branches were renamed to version-11")


@click.command('switch-to-develop')
def switch_to_develop(upgrade=False):
"Switch frappe and erpnext to develop branch"
from bench.app import switch_to_develop
switch_to_develop(apps=['frappe', 'erpnext'])
print()
print('Switched to develop')
print('Please run `bench update --patch` to be safe from any differences in database schema')
print('Switched to develop\nPlease run `bench update --patch` to be safe from any differences in database schema')
149 changes: 121 additions & 28 deletions bench/utils.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
import errno, glob, grp, itertools, json, logging, multiprocessing, os, platform, pwd, re, select, shutil, site, subprocess, sys
# imports - standard imports
import errno
import glob
import grp
import itertools
import json
import logging
import multiprocessing
import os
import platform
import pwd
import re
import select
import shutil
import site
import subprocess
import sys
import time
from datetime import datetime
from distutils.spawn import find_executable

# imports - third party imports
import click
import requests
import semantic_version
from six import iteritems
from six.moves import reload_module
from six.moves.urllib.parse import urlparse

# imports - module imports
import bench
from bench import env


class PatchError(Exception):
Expand Down Expand Up @@ -70,9 +90,11 @@ def get_frappe(bench_path='.'):
def get_env_cmd(cmd, bench_path='.'):
return os.path.abspath(os.path.join(bench_path, 'env', 'bin', cmd))

def init(path, apps_path=None, no_procfile=False, no_backups=False, no_auto_update=False,
frappe_path=None, frappe_branch=None, wheel_cache_dir=None, verbose=False, clone_from=None,
skip_redis_config_generation=False, clone_without_update=False, ignore_exist = False, skip_assets=False, python='python3'):
def init(path, apps_path=None, no_procfile=False, no_backups=False,
frappe_path=None, frappe_branch=None, verbose=False, clone_from=None,
skip_redis_config_generation=False, clone_without_update=False, ignore_exist=False, skip_assets=False,
python='python3'):
"""Initialize a new bench directory"""
from bench.app import get_app, install_apps_from_path
from bench.config import redis
from bench.config.common_site_config import make_config
Expand Down Expand Up @@ -127,10 +149,99 @@ def init(path, apps_path=None, no_procfile=False, no_backups=False, no_auto_upda
setup_procfile(path)
if not no_backups:
setup_backups(bench_path=path)
if not no_auto_update:
setup_auto_update(bench_path=path)

copy_patches_txt(path)

def restart_update(kwargs):
args = ['--'+k for k, v in list(kwargs.items()) if v]
os.execv(sys.argv[0], sys.argv[:2] + args)

def update(pull=False, patch=False, build=False, bench=False, restart_supervisor=False,
restart_systemd=False, requirements=False, backup=True, force=False, reset=False):
"""command: bench update"""

if not is_bench_directory():
"""Update only bench CLI if bench update called from outside a bench"""
update_bench(bench_repo=True, requirements=True)
sys.exit(0)

from bench import patches
from bench.app import is_version_upgrade, pull_all_apps, validate_branch
from bench.config.common_site_config import get_config, update_config

bench_path = os.path.abspath(".")
patches.run(bench_path=bench_path)
conf = get_config(bench_path)

if conf.get('release_bench'):
print('Release bench detected, cannot update!')
sys.exit(1)

if not (pull or patch or build or bench or requirements):
pull, patch, build, bench, requirements = True, True, True, True, True

if bench and conf.get('update_bench_on_update'):
update_bench(bench_repo=True, requirements=False)
restart_update({
'pull': pull,
'patch': patch,
'build': build,
'requirements': requirements,
'backup': backup,
'restart-supervisor': restart_supervisor,
'reset': reset
})

validate_branch()
version_upgrade = is_version_upgrade()

if version_upgrade[0]:
if force:
print("Force flag has been used for a major version change in Frappe and it's apps. \nThis will take significant time to migrate and might break custom apps.")
else:
print("This update will cause a major version change in Frappe/ERPNext from {0} to {1}. \nThis would take significant time to migrate and might break custom apps.".format(*version_upgrade[1:]))
click.confirm('Do you want to continue?', abort=True)

if version_upgrade[0] or (not version_upgrade[0] and force):
validate_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)

before_update(bench_path=bench_path, requirements=requirements)

conf.update({ "maintenance_mode": 1, "pause_scheduler": 1 })
update_config(conf, bench_path=bench_path)

if backup:
print('Backing up sites...')
backup_all_sites(bench_path=bench_path)

if pull:
pull_all_apps(bench_path=bench_path, reset=reset)

if requirements:
update_requirements(bench_path=bench_path)
update_node_packages(bench_path=bench_path)

if patch:
print('Patching sites...')
patch_sites(bench_path=bench_path)

if build:
build_assets(bench_path=bench_path)

if version_upgrade[0] or (not version_upgrade[0] and force):
post_upgrade(version_upgrade[1], version_upgrade[2], bench_path=bench_path)

if restart_supervisor or conf.get('restart_supervisor_on_update'):
restart_supervisor_processes(bench_path=bench_path)

if restart_systemd or conf.get('restart_systemd_on_update'):
restart_systemd_processes(bench_path=bench_path)

conf.update({ "maintenance_mode": 0, "pause_scheduler": 0 })
update_config(conf, bench_path=bench_path)

print("_" * 80 + "\nBench: Deployment tool for Frappe and Frappe Applications (https://frappe.io/bench).\nOpen source depends on your contributions, so please contribute bug reports, patches, fixes or cash and be a part of the community")

def copy_patches_txt(bench_path):
shutil.copy(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'patches', 'patches.txt'),
os.path.join(bench_path, 'patches.txt'))
Expand Down Expand Up @@ -246,12 +357,6 @@ def get_sites(bench_path='.'):
def get_bench_dir(bench_path='.'):
return os.path.abspath(bench_path)

def setup_auto_update(bench_path='.'):
logger.info('setting up auto update')
add_to_crontab('0 10 * * * cd {bench_dir} && {bench} update --auto >> {logfile} 2>&1'.format(bench_dir=get_bench_dir(bench_path=bench_path),
bench=os.path.join(get_bench_dir(bench_path=bench_path), 'env', 'bin', 'bench'),
logfile=os.path.join(get_bench_dir(bench_path=bench_path), 'logs', 'auto_update_log.log')))

def setup_backups(bench_path='.'):
logger.info('setting up backups')
bench_dir = get_bench_dir(bench_path=bench_path)
Expand Down Expand Up @@ -302,6 +407,8 @@ def update_bench(bench_repo=True, requirements=True):
logger.info("Bench Updated!")

def setup_sudoers(user):
from bench import env

if not os.path.exists('/etc/sudoers.d'):
os.makedirs('/etc/sudoers.d')

Expand Down Expand Up @@ -690,20 +797,6 @@ def validate_upgrade(from_ver, to_ver, bench_path='.'):
if not find_executable('npm') and not (find_executable('node') or find_executable('nodejs')):
raise Exception("Please install nodejs and npm")

def pre_upgrade(from_ver, to_ver, bench_path='.'):
pip = os.path.join(bench_path, 'env', 'bin', 'pip')

if from_ver <= 4 and to_ver >= 5:
from .migrate_to_v5 import remove_shopping_cart
apps = ('frappe', 'erpnext')
remove_shopping_cart(bench_path=bench_path)

for app in apps:
cwd = os.path.abspath(os.path.join(bench_path, 'apps', app))
if os.path.exists(cwd):
exec_cmd("git clean -dxf", cwd=cwd)
exec_cmd("{pip} install --upgrade -e {app}".format(pip=pip, app=cwd))

def post_upgrade(from_ver, to_ver, bench_path='.'):
from .config.common_site_config import get_config
from .config import redis
Expand Down Expand Up @@ -1042,4 +1135,4 @@ def migrate_env(python, backup=False):
log.debug('Migration Successful to {}'.format(python))
except:
log.debug('Migration Error')
raise
raise

0 comments on commit 2713a2e

Please sign in to comment.