From 59647e07845918ea410253ccc1704072c3ef400b Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Mon, 20 Apr 2020 22:08:48 +0530 Subject: [PATCH 01/23] chore: skip restart on bench setup requirements Signed-off-by: Chinmay D. Pai --- bench/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/utils.py b/bench/utils.py index 84ce6e71..bfaba366 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -572,7 +572,7 @@ def update_requirements(bench_path='.'): update_env_pip(bench_path) for app in get_apps(): - install_app(app, bench_path=bench_path, skip_assets=True) + install_app(app, bench_path=bench_path, skip_assets=True, postprocess=False) def update_node_packages(bench_path='.'): From 74028074df18d7794761402dced742b6346b423a Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 12 May 2020 11:00:15 +0530 Subject: [PATCH 02/23] fix(get-app): allow ssh urls --- bench/app.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bench/app.py b/bench/app.py index 8b165b2b..fec7a551 100755 --- a/bench/app.py +++ b/bench/app.py @@ -100,7 +100,9 @@ def remove_from_excluded_apps_txt(app, bench_path='.'): def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False, postprocess=True, overwrite=False): if not os.path.exists(git_url): - if not check_url(git_url, raise_err=False): + if git_url.startswith('git@'): + pass + elif not check_url(git_url, raise_err=False): orgs = ['frappe', 'erpnext'] for org in orgs: url = 'https://api.github.com/repos/{org}/{app}'.format(org=org, app=git_url) From 30473d353560b8bc0aeb7c5eb8b7c420ca2f3a21 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 14 May 2020 17:45:28 +0530 Subject: [PATCH 03/23] feat: added specific checks for git URLs API Added: bench.utils.is_git_url Reference: https://github.com/jonschlinkert/is-git-url --- bench/app.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bench/app.py b/bench/app.py index fec7a551..d3f01f0d 100755 --- a/bench/app.py +++ b/bench/app.py @@ -71,6 +71,11 @@ def check_url(url, raise_err=True): return True +def is_git_url(url): + # modified to allow without the tailing .git from https://github.com/jonschlinkert/is-git-url.git + pattern = r"(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$" + return bool(re.fullmatch(pattern, url)) + def get_excluded_apps(bench_path='.'): try: with open(os.path.join(bench_path, 'sites', 'excluded_apps.txt')) as f: @@ -100,9 +105,7 @@ def remove_from_excluded_apps_txt(app, bench_path='.'): def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False, postprocess=True, overwrite=False): if not os.path.exists(git_url): - if git_url.startswith('git@'): - pass - elif not check_url(git_url, raise_err=False): + if not is_git_url(git_url): orgs = ['frappe', 'erpnext'] for org in orgs: url = 'https://api.github.com/repos/{org}/{app}'.format(org=org, app=git_url) From 7f93674c52876c47583f84e56a038d763793ce70 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 14 May 2020 20:08:48 +0530 Subject: [PATCH 04/23] test: handle if branch switching breaks --- bench/tests/test_init.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bench/tests/test_init.py b/bench/tests/test_init.py index d1dd7662..cf92d630 100755 --- a/bench/tests/test_init.py +++ b/bench/tests/test_init.py @@ -136,13 +136,15 @@ class TestBenchInit(TestBenchBase): bench_path = os.path.join(self.benches_path, "test-bench") app_path = os.path.join(bench_path, "apps", "frappe") - bench.utils.exec_cmd("bench switch-to-branch version-12 frappe --upgrade", cwd=bench_path) + successful_switch = not bench.utils.exec_cmd("bench switch-to-branch version-12 frappe --upgrade", cwd=bench_path) app_branch_after_switch = str(git.Repo(path=app_path).active_branch) - self.assertEqual("version-12", app_branch_after_switch) + if successful_switch: + self.assertEqual("version-12", app_branch_after_switch) - bench.utils.exec_cmd("bench switch-to-branch develop frappe --upgrade", cwd=bench_path) + successful_switch = not bench.utils.exec_cmd("bench switch-to-branch develop frappe --upgrade", cwd=bench_path) app_branch_after_second_switch = str(git.Repo(path=app_path).active_branch) - self.assertEqual("develop", app_branch_after_second_switch) + if successful_switch: + self.assertEqual("develop", app_branch_after_second_switch) if __name__ == '__main__': From 4ae8ae21f791b6a15266c1c0eb5ea870bd77895f Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 14 May 2020 20:12:26 +0530 Subject: [PATCH 05/23] fix: PY2 compatible regex --- bench/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/app.py b/bench/app.py index d3f01f0d..0f95932e 100755 --- a/bench/app.py +++ b/bench/app.py @@ -74,7 +74,7 @@ def check_url(url, raise_err=True): def is_git_url(url): # modified to allow without the tailing .git from https://github.com/jonschlinkert/is-git-url.git pattern = r"(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$" - return bool(re.fullmatch(pattern, url)) + return bool(re.match(pattern, url)) def get_excluded_apps(bench_path='.'): try: From 9f467d88e4685b6ce22e4364f9956bcb0b9b19eb Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 May 2020 11:42:31 +0530 Subject: [PATCH 06/23] fix: force checkout during switch_branch and quiet fetch --- bench/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bench/app.py b/bench/app.py index 0f95932e..92512e3a 100755 --- a/bench/app.py +++ b/bench/app.py @@ -395,7 +395,7 @@ def switch_branch(branch, apps=None, bench_path='.', upgrade=False, check_upgrad bench.utils.log("Fetching upstream {0}for {1}".format("unshallow " if unshallow_flag else "", app)) bench.utils.exec_cmd("git remote set-branches upstream '*'", cwd=app_dir) - bench.utils.exec_cmd("git fetch --all{0}".format(" --unshallow" if unshallow_flag else ""), cwd=app_dir) + bench.utils.exec_cmd("git fetch --all{0} --quiet".format(" --unshallow" if unshallow_flag else ""), cwd=app_dir) if check_upgrade: version_upgrade = is_version_upgrade(app=app, bench_path=bench_path, branch=branch) @@ -404,7 +404,7 @@ def switch_branch(branch, apps=None, bench_path='.', upgrade=False, check_upgrad sys.exit(1) print("Switching for "+app) - bench.utils.exec_cmd("git checkout {0}".format(branch), cwd=app_dir) + bench.utils.exec_cmd("git checkout -f {0}".format(branch), cwd=app_dir) if str(repo.active_branch) == branch: switched_apps.append(app) From 34de3d03a43945ee49e8549b0e3cbf8a43010fe2 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 19 May 2020 13:09:08 +0530 Subject: [PATCH 07/23] chore: drop dead code --- bench/app.py | 4 -- bench/commands/config.py | 1 + bench/commands/setup.py | 1 - bench/config/nginx.py | 2 - bench/utils.py | 128 --------------------------------------- 5 files changed, 1 insertion(+), 135 deletions(-) diff --git a/bench/app.py b/bench/app.py index 8b165b2b..5bbfe505 100755 --- a/bench/app.py +++ b/bench/app.py @@ -359,10 +359,6 @@ def get_upstream_version(app, branch=None, bench_path='.'): raise return get_version_from_string(contents) -def get_upstream_url(app, bench_path='.'): - repo_dir = get_repo_dir(app, bench_path=bench_path) - return subprocess.check_output(['git', 'config', '--get', 'remote.upstream.url'], cwd=repo_dir).strip() - def get_repo_dir(app, bench_path='.'): return os.path.join(bench_path, 'apps', app) diff --git a/bench/commands/config.py b/bench/commands/config.py index 7d56eeb1..4d4bec59 100644 --- a/bench/commands/config.py +++ b/bench/commands/config.py @@ -80,6 +80,7 @@ def remove_common_config(keys): config.add_command(config_restart_supervisor_on_update) config.add_command(config_restart_systemd_on_update) config.add_command(config_dns_multitenant) +config.add_command(config_rebase_on_pull) config.add_command(config_serve_default_site) config.add_command(config_http_timeout) config.add_command(set_common_config) diff --git a/bench/commands/setup.py b/bench/commands/setup.py index 2e516496..ed561ffe 100755 --- a/bench/commands/setup.py +++ b/bench/commands/setup.py @@ -4,7 +4,6 @@ import sys # imports - third party imports import click -from six import PY3 # imports - module imports import bench.config.lets_encrypt diff --git a/bench/config/nginx.py b/bench/config/nginx.py index d2154112..fbb73680 100644 --- a/bench/config/nginx.py +++ b/bench/config/nginx.py @@ -172,9 +172,7 @@ def prepare_sites(config, bench_path): if not dns_multitenant: message = "Port configuration list:" - port_config_index = 0 for site in sites_configs: - port_config_index += 1 message += "\n\nSite {0} assigned port: {1}".format(site["name"], site["port"]) print(message) diff --git a/bench/utils.py b/bench/utils.py index 67ff3364..58d74324 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -10,7 +10,6 @@ import json import logging import multiprocessing import os -import platform import pwd import re import select @@ -459,14 +458,6 @@ def start(no_dev=False, concurrency=None, procfile=None): os.execv(program, command) -def check_cmd(cmd, cwd='.'): - try: - subprocess.check_call(cmd, cwd=cwd, shell=True) - return True - except subprocess.CalledProcessError: - return False - - def get_git_version(): '''returns git version from `git --version` extracts version number from string `get version 1.9.1` etc''' @@ -505,15 +496,6 @@ def get_cmd_output(cmd, cwd='.', _raise=True): return safe_decode(output) -def safe_encode(what, encoding = 'utf-8'): - try: - what = what.encode(encoding) - except Exception: - pass - - return what - - def restart_supervisor_processes(bench_path='.', web_workers=False): from .config.common_site_config import get_config conf = get_config(bench_path=bench_path) @@ -634,21 +616,6 @@ def update_npm_packages(bench_path='.'): exec_cmd('npm install', cwd=bench_path) -def install_requirements(req_file, user=False): - if os.path.exists(req_file): - if user: - python = sys.executable - else: - python = os.path.join("env", "bin", "python") - - if in_virtual_env(): - user = False - - user_flag = "--user" if user else "" - - exec_cmd("{python} -m pip install {user_flag} -q -U -r {req_file}".format(python=python, user_flag=user_flag, req_file=req_file)) - - def backup_site(site, bench_path='.'): bench.set_frappe_version(bench_path=bench_path) @@ -742,19 +709,6 @@ def fix_prod_setup_perms(bench_path='.', frappe_user=None): os.chown(path, uid, gid) -def fix_file_perms(): - for dir_path, dirs, files in os.walk('.'): - for _dir in dirs: - os.chmod(os.path.join(dir_path, _dir), 0o755) - for _file in files: - os.chmod(os.path.join(dir_path, _file), 0o644) - bin_dir = './env/bin' - if os.path.exists(bin_dir): - for _file in os.listdir(bin_dir): - if not _file.startswith('activate'): - os.chmod(os.path.join(bin_dir, _file), 0o755) - - def get_current_frappe_version(bench_path='.'): from .app import get_current_frappe_version as fv return fv(bench_path=bench_path) @@ -785,13 +739,6 @@ def run_frappe_cmd(*args, **kwargs): sys.exit(return_code) -def get_frappe_cmd_output(*args, **kwargs): - bench_path = kwargs.get('bench_path', '.') - f = get_env_cmd('python', bench_path=bench_path) - sites_dir = os.path.join(bench_path, 'sites') - return subprocess.check_output((f, '-m', 'frappe.utils.bench_helper', 'frappe') + args, cwd=sites_dir) - - def validate_upgrade(from_ver, to_ver, bench_path='.'): if to_ver >= 6: if not find_executable('npm') and not (find_executable('node') or find_executable('nodejs')): @@ -901,13 +848,6 @@ def log_line(data, stream): return sys.stdout.write(data) -def get_output(*cmd): - s = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - out = s.stdout.read() - s.stdout.close() - return out - - def get_bench_name(bench_path): return os.path.basename(os.path.abspath(bench_path)) @@ -984,78 +924,10 @@ def find_benches(directory=None): return benches -def in_virtual_env(): - # type: () -> bool - """Returns a boolean, whether running in venv with no system site-packages. - pip really does the best job at this: virtualenv_no_global at https://raw.githubusercontent.com/pypa/pip/master/src/pip/_internal/utils/virtualenv.py - """ - - def running_under_venv(): - # handles PEP 405 compliant virtual environments. - return sys.prefix != getattr(sys, "base_prefix", sys.prefix) - - def running_under_regular_virtualenv(): - # pypa/virtualenv case - return hasattr(sys, 'real_prefix') - - def _no_global_under_venv(): - # type: () -> bool - """Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion - PEP 405 specifies that when system site-packages are not supposed to be - visible from a virtual environment, `pyvenv.cfg` must contain the following - line: - include-system-site-packages = false - Additionally, log a warning if accessing the file fails. - """ - def _get_pyvenv_cfg_lines(): - pyvenv_cfg_file = os.path.join(sys.prefix, 'pyvenv.cfg') - try: - with open(pyvenv_cfg_file) as f: - return f.read().splitlines() # avoids trailing newlines - except IOError: - return None - - _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX = re.compile( - r"include-system-site-packages\s*=\s*(?Ptrue|false)" - ) - cfg_lines = _get_pyvenv_cfg_lines() - if cfg_lines is None: - # We're not in a "sane" venv, so assume there is no system - # site-packages access (since that's PEP 405's default state). - return True - - for line in cfg_lines: - match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line) - if match is not None and match.group('value') == 'false': - return True - return False - - def _no_global_under_regular_virtualenv(): - # type: () -> bool - """Check if "no-global-site-packages.txt" exists beside site.py - This mirrors logic in pypa/virtualenv for determining whether system - site-packages are visible in the virtual environment. - """ - site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) - no_global_site_packages_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt') - return os.path.exists(no_global_site_packages_file) - - if running_under_regular_virtualenv(): - return _no_global_under_regular_virtualenv() - - if running_under_venv(): - return _no_global_under_venv() - - return False - - def migrate_env(python, backup=False): from bench.config.common_site_config import get_config from bench.app import get_apps - logger = logging.getLogger(__name__) - logger.setLevel(logging.DEBUG) - nvenv = 'env' path = os.getcwd() python = which(python) From 0be833ad850e5d68fefd906bb3e0607127849d4b Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 19 May 2020 13:11:57 +0530 Subject: [PATCH 08/23] fix: cleaner and intuitive bench logs --- bench/app.py | 11 +++++----- bench/cli.py | 9 ++++++--- bench/commands/__init__.py | 3 --- bench/utils.py | 41 ++++++++++++++++++++++++++------------ 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/bench/app.py b/bench/app.py index 8b165b2b..de7f8c4e 100755 --- a/bench/app.py +++ b/bench/app.py @@ -23,8 +23,7 @@ from bench.config.common_site_config import get_config from bench.utils import CommandFailedError, build_assets, check_git_for_shallow_clone, exec_cmd, get_cmd_output, get_frappe, restart_supervisor_processes, restart_systemd_processes, run_frappe_cmd -logging.basicConfig(level="INFO") -logger = logging.getLogger(__name__) +logger = logging.getLogger(bench.PROJECT_NAME) class InvalidBranchException(Exception): pass @@ -135,7 +134,7 @@ Do you want to continue and overwrite it?'''.format(repo_name)): install_app(app=app_name, bench_path=bench_path, verbose=verbose, skip_assets=skip_assets) sys.exit() - logger.info('Getting app {0}'.format(repo_name)) + logger.log( 'Getting app {0}'.format(repo_name)) exec_cmd("git clone {git_url} {branch} {shallow_clone} --origin upstream".format( git_url=git_url, shallow_clone=shallow_clone, @@ -160,7 +159,7 @@ def get_app_name(bench_path, repo_name): def new_app(app, bench_path='.'): # For backwards compatibility app = app.lower().replace(" ", "_").replace("-", "_") - logger.info('creating new app {}'.format(app)) + logger.log( 'creating new app {}'.format(app)) apps = os.path.abspath(os.path.join(bench_path, 'apps')) bench.set_frappe_version(bench_path=bench_path) @@ -173,7 +172,7 @@ def new_app(app, bench_path='.'): def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess=True, skip_assets=False): - logger.info("installing {}".format(app)) + logger.log( "installing {}".format(app)) pip_path = os.path.join(bench_path, "env", "bin", "pip") quiet_flag = "-q" if not verbose else "" @@ -267,7 +266,7 @@ Here are your choices: add_to_excluded_apps_txt(app, bench_path=bench_path) print("Skipping pull for app {}, since remote doesn't exist, and adding it to excluded apps".format(app)) continue - logger.info('pulling {0}'.format(app)) + logger.log( 'pulling {0}'.format(app)) if reset: exec_cmd("git fetch --all", cwd=app_dir) exec_cmd("git reset --hard {remote}/{branch}".format( diff --git a/bench/cli.py b/bench/cli.py index 09c001d8..0cc53310 100755 --- a/bench/cli.py +++ b/bench/cli.py @@ -14,9 +14,8 @@ import bench from bench.app import get_apps from bench.commands import bench_command from bench.config.common_site_config import get_config -from bench.utils import PatchError, bench_cache_file, check_latest_version, drop_privileges, find_parent_bench, generate_command_cache, get_cmd_output, get_env_cmd, get_frappe, is_bench_directory, is_dist_editable, is_root, log +from bench.utils import PatchError, bench_cache_file, check_latest_version, drop_privileges, find_parent_bench, generate_command_cache, get_cmd_output, get_env_cmd, get_frappe, is_bench_directory, is_dist_editable, is_root, log, setup_logging -logger = logging.getLogger(bench.PROJECT_NAME) from_command_line = False change_uid_msg = "You should not run this command as root" @@ -24,8 +23,11 @@ change_uid_msg = "You should not run this command as root" def cli(): global from_command_line from_command_line = True + command = " ".join(sys.argv) change_working_directory() + logger = setup_logging() or logging.getLogger(bench.PROJECT_NAME) + logger.info(command) check_uid() change_dir() change_uid() @@ -56,7 +58,8 @@ def cli(): try: bench_command() - except PatchError: + except BaseException as e: + logger.warn("{0} executed with exit code {1}".format(command, getattr(e, "code", None))) sys.exit(1) diff --git a/bench/commands/__init__.py b/bench/commands/__init__.py index 8ee317d9..2b073b65 100755 --- a/bench/commands/__init__.py +++ b/bench/commands/__init__.py @@ -14,10 +14,7 @@ def print_bench_version(ctx, param, value): @click.option('--version', is_flag=True, is_eager=True, callback=print_bench_version, expose_value=False) def bench_command(bench_path='.'): import bench - from bench.utils import setup_logging - bench.set_frappe_version(bench_path=bench_path) - setup_logging(bench_path=bench_path) from bench.commands.make import init, get_app, new_app, remove_app, exclude_app_for_update, include_app_for_update, pip diff --git a/bench/utils.py b/bench/utils.py index 67ff3364..9bd65ad3 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -39,7 +39,7 @@ class PatchError(Exception): class CommandFailedError(Exception): pass -logger = logging.getLogger(__name__) +logger = logging.getLogger(bench.PROJECT_NAME) bench_cache_file = '.bench.cmd' folders_in_bench = ('apps', 'sites', 'config', 'logs', 'config/pids') sudoers_file = '/etc/sudoers.d/frappe' @@ -139,7 +139,7 @@ def init(path, apps_path=None, no_procfile=False, no_backups=False, if e.errno == errno.EEXIST: pass - setup_logging() + setup_logging(bench_path=path) setup_env(bench_path=path, python=python) @@ -297,8 +297,13 @@ def clone_apps_from(bench_path, clone_from, update_app=True): def exec_cmd(cmd, cwd='.'): import shlex print("{0}$ {1}{2}".format(color.silver, cmd, color.nc)) + cwd_info = "cd {0} && ".format(cwd) if cwd != "." else "" + cmd_log = "{0}{1}".format(cwd_info, cmd) + logger.debug(cmd_log) cmd = shlex.split(cmd) - return subprocess.call(cmd, cwd=cwd, universal_newlines=True) + return_code = subprocess.call(cmd, cwd=cwd, universal_newlines=True) + if return_code: + logger.warn("{0} executed with exit code {1}".format(cmd_log, return_code)) def which(executable, raise_err = False): @@ -372,7 +377,7 @@ def get_sites(bench_path='.'): def setup_backups(bench_path='.'): from bench.config.common_site_config import get_config - logger.info('setting up backups') + logger.log('setting up backups') bench_dir = os.path.abspath(bench_path) user = get_config(bench_path=bench_dir).get('frappe_user') @@ -424,6 +429,13 @@ def setup_sudoers(user): def setup_logging(bench_path='.'): + LOG_LEVEL = 15 + logging.addLevelName(LOG_LEVEL, "LOG") + def logv(self, message, *args, **kws): + if self.isEnabledFor(LOG_LEVEL): + self._log(LOG_LEVEL, message, args, **kws) + logging.Logger.log = logv + if os.path.exists(os.path.join(bench_path, 'logs')): logger = logging.getLogger(bench.PROJECT_NAME) log_file = os.path.join(bench_path, 'logs', 'bench.log') @@ -433,6 +445,8 @@ def setup_logging(bench_path='.'): logger.addHandler(hdlr) logger.setLevel(logging.DEBUG) + return logger + def get_process_manager(): for proc_man in ['honcho', 'foreman', 'forego']: @@ -1070,9 +1084,9 @@ def migrate_env(python, backup=False): redis = '{redis} -p {port}'.format(redis=which('redis-cli'), port=rredis.port) - logger.debug('Clearing Redis Cache...') + logger.log('Clearing Redis Cache...') exec_cmd('{redis} FLUSHALL'.format(redis = redis)) - logger.debug('Clearing Redis DataBase...') + logger.log('Clearing Redis DataBase...') exec_cmd('{redis} FLUSHDB'.format(redis = redis)) except: logger.warn('Please ensure Redis Connections are running or Daemonized.') @@ -1086,7 +1100,7 @@ def migrate_env(python, backup=False): source = os.path.join(path, 'env') target = parch - logger.debug('Backing up Virtual Environment') + logger.log('Backing up Virtual Environment') stamp = datetime.now().strftime('%Y%m%d_%H%M%S') dest = os.path.join(path, str(stamp)) @@ -1094,17 +1108,18 @@ def migrate_env(python, backup=False): shutil.move(dest, target) # Create virtualenv using specified python + venv_creation, packages_setup = 1, 1 try: - logger.debug('Setting up a New Virtual {} Environment'.format(python)) - exec_cmd('{virtualenv} --python {python} {pvenv}'.format(virtualenv=virtualenv, python=python, pvenv=pvenv)) + logger.log('Setting up a New Virtual {} Environment'.format(python)) + venv_creation = exec_cmd('{virtualenv} --python {python} {pvenv}'.format(virtualenv=virtualenv, python=python, pvenv=pvenv)) apps = ' '.join(["-e {}".format(os.path.join("apps", app)) for app in get_apps()]) - exec_cmd('{0} install -q -U {1}'.format(pip, apps)) + packages_setup = exec_cmd('{0} install -q -U {1}'.format(pip, apps)) - logger.debug('Migration Successful to {}'.format(python)) + logger.log('Migration Successful to {}'.format(python)) except: - logger.debug('Migration Error') - raise + if venv_creation or packages_setup: + logger.warn('Migration Error') def is_dist_editable(dist): From 53919b624e17e108006d66bddb0981658aeefaf0 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 19 May 2020 13:47:48 +0530 Subject: [PATCH 09/23] fix: add log filter to handler --- bench/app.py | 8 ++++---- bench/utils.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/bench/app.py b/bench/app.py index de7f8c4e..4beaf988 100755 --- a/bench/app.py +++ b/bench/app.py @@ -134,7 +134,7 @@ Do you want to continue and overwrite it?'''.format(repo_name)): install_app(app=app_name, bench_path=bench_path, verbose=verbose, skip_assets=skip_assets) sys.exit() - logger.log( 'Getting app {0}'.format(repo_name)) + logger.log('Getting app {0}'.format(repo_name)) exec_cmd("git clone {git_url} {branch} {shallow_clone} --origin upstream".format( git_url=git_url, shallow_clone=shallow_clone, @@ -159,7 +159,7 @@ def get_app_name(bench_path, repo_name): def new_app(app, bench_path='.'): # For backwards compatibility app = app.lower().replace(" ", "_").replace("-", "_") - logger.log( 'creating new app {}'.format(app)) + logger.log('creating new app {}'.format(app)) apps = os.path.abspath(os.path.join(bench_path, 'apps')) bench.set_frappe_version(bench_path=bench_path) @@ -172,7 +172,7 @@ def new_app(app, bench_path='.'): def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess=True, skip_assets=False): - logger.log( "installing {}".format(app)) + logger.log("installing {}".format(app)) pip_path = os.path.join(bench_path, "env", "bin", "pip") quiet_flag = "-q" if not verbose else "" @@ -266,7 +266,7 @@ Here are your choices: add_to_excluded_apps_txt(app, bench_path=bench_path) print("Skipping pull for app {}, since remote doesn't exist, and adding it to excluded apps".format(app)) continue - logger.log( 'pulling {0}'.format(app)) + logger.log('pulling {0}'.format(app)) if reset: exec_cmd("git fetch --all", cwd=app_dir) exec_cmd("git reset --hard {remote}/{branch}".format( diff --git a/bench/utils.py b/bench/utils.py index 9bd65ad3..2e6b31fa 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -436,13 +436,26 @@ def setup_logging(bench_path='.'): self._log(LOG_LEVEL, message, args, **kws) logging.Logger.log = logv + class log_filter(object): + def __init__(self, level): + self.__level = level + + def filter(self, logRecord): + return logRecord.levelno == self.__level + if os.path.exists(os.path.join(bench_path, 'logs')): logger = logging.getLogger(bench.PROJECT_NAME) log_file = os.path.join(bench_path, 'logs', 'bench.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr = logging.FileHandler(log_file) hdlr.setFormatter(formatter) + + log_hndlr = logging.StreamHandler(sys.stdout) + log_hndlr.setFormatter(logging.Formatter('%(message)s')) + log_hndlr.addFilter(log_filter(LOG_LEVEL)) + logger.addHandler(hdlr) + logger.addHandler(log_hndlr) logger.setLevel(logging.DEBUG) return logger From dd047002a1915b39867295d195c3f269f11fc57e Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 19 May 2020 14:14:01 +0530 Subject: [PATCH 10/23] fix: dont run ayrn install while setting up py reqs --- bench/app.py | 4 ++-- bench/commands/setup.py | 16 ++++++++++------ bench/utils.py | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/bench/app.py b/bench/app.py index 8b165b2b..90853c45 100755 --- a/bench/app.py +++ b/bench/app.py @@ -20,7 +20,7 @@ from six.moves import reload_module # imports - module imports import bench from bench.config.common_site_config import get_config -from bench.utils import CommandFailedError, build_assets, check_git_for_shallow_clone, exec_cmd, get_cmd_output, get_frappe, restart_supervisor_processes, restart_systemd_processes, run_frappe_cmd +from bench.utils import color, CommandFailedError, build_assets, check_git_for_shallow_clone, exec_cmd, get_cmd_output, get_frappe, restart_supervisor_processes, restart_systemd_processes, run_frappe_cmd logging.basicConfig(level="INFO") @@ -173,7 +173,7 @@ def new_app(app, bench_path='.'): def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess=True, skip_assets=False): - logger.info("installing {}".format(app)) + print('\n{0}Installing {1}{2}'.format(color.yellow, app, color.nc)) pip_path = os.path.join(bench_path, "env", "bin", "pip") quiet_flag = "-q" if not verbose else "" diff --git a/bench/commands/setup.py b/bench/commands/setup.py index 2e516496..973eeff2 100755 --- a/bench/commands/setup.py +++ b/bench/commands/setup.py @@ -128,13 +128,17 @@ def setup_socketio(): @click.option("--node", help="Update only Node packages", default=False, is_flag=True) @click.option("--python", help="Update only Python packages", default=False, is_flag=True) def setup_requirements(node=False, python=False): - if not node: - from bench.utils import update_requirements as setup_python_packages - setup_python_packages() + if not (node or python): + from bench.utils import update_requirements + update_requirements() - if not python: - from bench.utils import update_node_packages as setup_node_packages - setup_node_packages() + elif not node: + from bench.utils import update_python_packages + update_python_packages() + + elif not python: + from bench.utils import update_node_packages + update_node_packages() @click.command("manager", help="Setup bench-manager.local site with the bench_manager app installed on it") diff --git a/bench/utils.py b/bench/utils.py index 67ff3364..5740d50a 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -564,15 +564,26 @@ def update_env_pip(bench_path): def update_requirements(bench_path='.'): from bench.app import get_apps, install_app - print('Updating Python libraries...') + print('Installing applications...') - # update env pip update_env_pip(bench_path) for app in get_apps(): install_app(app, bench_path=bench_path, skip_assets=True) +def update_python_packages(bench_path='.'): + from bench.app import get_apps + pip_path = os.path.join(bench_path, "env", "bin", "pip") + print('Updating Python libraries...') + + update_env_pip(bench_path) + for app in get_apps(): + print('\n{0}Installing python dependencies for {1}{2}'.format(color.yellow, app, color.nc)) + app_path = os.path.join(bench_path, "apps", app) + exec_cmd("{0} install -q -U -e {1}".format(pip_path, app_path), cwd=bench_path) + + def update_node_packages(bench_path='.'): print('Updating node packages...') from bench.app import get_develop_version From a4a9b59f4256d5f28ecc572cf5e7e777635e176a Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Tue, 19 May 2020 18:17:38 +0530 Subject: [PATCH 11/23] fix: build assets regardless of postprocess Signed-off-by: Chinmay D. Pai --- bench/app.py | 5 +++-- bench/utils.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bench/app.py b/bench/app.py index 8b165b2b..1ae32e1f 100755 --- a/bench/app.py +++ b/bench/app.py @@ -187,9 +187,10 @@ def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess= add_to_appstxt(app, bench_path=bench_path) + if not skip_assets: + build_assets(bench_path=bench_path, app=app) + if postprocess: - if not skip_assets: - build_assets(bench_path=bench_path, app=app) conf = get_config(bench_path=bench_path) if conf.get('restart_supervisor_on_update'): diff --git a/bench/utils.py b/bench/utils.py index d460f37c..37d3e770 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -285,7 +285,7 @@ def clone_apps_from(bench_path, clone_from, update_app=True): subprocess.check_output(['git', 'reset', '--hard'], cwd=app_path) subprocess.check_output(['git', 'pull', '--rebase', remote, branch], cwd=app_path) - install_app(app, bench_path) + install_app(app, bench_path, postprocess=False) with open(os.path.join(clone_from, 'sites', 'apps.txt'), 'r') as f: apps = f.read().splitlines() From e52dc985c73ee55e46528007d5cae383459f2215 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Tue, 19 May 2020 18:23:59 +0530 Subject: [PATCH 12/23] chore: rename postprocess to restart_bench Signed-off-by: Chinmay D. Pai --- bench/app.py | 6 +++--- bench/utils.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bench/app.py b/bench/app.py index 1ae32e1f..abea32ce 100755 --- a/bench/app.py +++ b/bench/app.py @@ -98,7 +98,7 @@ def remove_from_excluded_apps_txt(app, bench_path='.'): apps.remove(app) return write_excluded_apps_txt(apps, bench_path=bench_path) -def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False, postprocess=True, overwrite=False): +def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False, restart_bench=True, overwrite=False): if not os.path.exists(git_url): if not check_url(git_url, raise_err=False): orgs = ['frappe', 'erpnext'] @@ -172,7 +172,7 @@ def new_app(app, bench_path='.'): install_app(app, bench_path=bench_path) -def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess=True, skip_assets=False): +def install_app(app, bench_path=".", verbose=False, no_cache=False, restart_bench=True, skip_assets=False): logger.info("installing {}".format(app)) pip_path = os.path.join(bench_path, "env", "bin", "pip") @@ -190,7 +190,7 @@ def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess= if not skip_assets: build_assets(bench_path=bench_path, app=app) - if postprocess: + if restart_bench: conf = get_config(bench_path=bench_path) if conf.get('restart_supervisor_on_update'): diff --git a/bench/utils.py b/bench/utils.py index 37d3e770..7e7770a1 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -285,7 +285,7 @@ def clone_apps_from(bench_path, clone_from, update_app=True): subprocess.check_output(['git', 'reset', '--hard'], cwd=app_path) subprocess.check_output(['git', 'pull', '--rebase', remote, branch], cwd=app_path) - install_app(app, bench_path, postprocess=False) + install_app(app, bench_path, restart_bench=False) with open(os.path.join(clone_from, 'sites', 'apps.txt'), 'r') as f: apps = f.read().splitlines() @@ -570,7 +570,7 @@ def update_requirements(bench_path='.'): update_env_pip(bench_path) for app in get_apps(): - install_app(app, bench_path=bench_path, skip_assets=True, postprocess=False) + install_app(app, bench_path=bench_path, skip_assets=True, restart_bench=False) def update_node_packages(bench_path='.'): From af8dd8f98fd639b8cefd141b8b1132b21eeb07a1 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 20 May 2020 12:56:57 +0530 Subject: [PATCH 13/23] Fix: IUS release repo --- bench/playbooks/roles/common/tasks/redhat_family.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/playbooks/roles/common/tasks/redhat_family.yml b/bench/playbooks/roles/common/tasks/redhat_family.yml index d41097c6..ef172fe0 100644 --- a/bench/playbooks/roles/common/tasks/redhat_family.yml +++ b/bench/playbooks/roles/common/tasks/redhat_family.yml @@ -4,7 +4,7 @@ become: yes become_user: root yum: - name: https://centos7.iuscommunity.org/ius-release.rpm + name: https://repo.ius.io/ius-release-el7.rpm state: present - name: "Setup prerequisites using yum" From 1bb07166d40025465bc96f3add271a77a4eb07d2 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 21 May 2020 11:07:14 +0530 Subject: [PATCH 14/23] chore: drop check_url --- bench/app.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/bench/app.py b/bench/app.py index 977fa7c6..0abfc9bd 100755 --- a/bench/app.py +++ b/bench/app.py @@ -59,18 +59,6 @@ def write_appstxt(apps, bench_path='.'): with open(os.path.join(bench_path, 'sites', 'apps.txt'), 'w') as f: return f.write('\n'.join(apps)) -def check_url(url, raise_err=True): - from six.moves.urllib.parse import urlparse - - parsed = urlparse(url) - if not parsed.scheme: - if raise_err: - raise TypeError('{url} Not a valid URL'.format(url=url)) - else: - return False - - return True - def is_git_url(url): # modified to allow without the tailing .git from https://github.com/jonschlinkert/is-git-url.git pattern = r"(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$" From 4480ea21acc131b6f0074f137bba9c297c04155a Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 21 May 2020 12:45:28 +0530 Subject: [PATCH 15/23] chore(logging) set logging level to INFO --- bench/app.py | 1 + bench/utils.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bench/app.py b/bench/app.py index 1c873c77..3946ec59 100755 --- a/bench/app.py +++ b/bench/app.py @@ -127,6 +127,7 @@ Do you want to continue and overwrite it?'''.format(repo_name)): install_app(app=app_name, bench_path=bench_path, verbose=verbose, skip_assets=skip_assets) sys.exit() + print('\n{0}Getting {1}{2}'.format(color.yellow, repo_name, color.nc)) logger.log('Getting app {0}'.format(repo_name)) exec_cmd("git clone {git_url} {branch} {shallow_clone} --origin upstream".format( git_url=git_url, diff --git a/bench/utils.py b/bench/utils.py index abcf2d2e..92044745 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -455,7 +455,7 @@ def setup_logging(bench_path='.'): logger.addHandler(hdlr) logger.addHandler(log_hndlr) - logger.setLevel(logging.DEBUG) + logger.setLevel(logging.INFO) return logger From 7dc5fdb7b3041d5a6258f8ddfc254b2dc6955605 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 21 May 2020 13:14:16 +0530 Subject: [PATCH 16/23] chore: update APIs, remove duplicate logs --- bench/cli.py | 6 ++++-- bench/utils.py | 13 ++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index 0cc53310..bf0b5231 100755 --- a/bench/cli.py +++ b/bench/cli.py @@ -59,8 +59,10 @@ def cli(): try: bench_command() except BaseException as e: - logger.warn("{0} executed with exit code {1}".format(command, getattr(e, "code", None))) - sys.exit(1) + return_code = getattr(e, "code", 0) + if return_code: + logger.warning("{0} executed with exit code {1}".format(command, return_code)) + sys.exit(return_code) def check_uid(): diff --git a/bench/utils.py b/bench/utils.py index 92044745..749a6e18 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -302,7 +302,7 @@ def exec_cmd(cmd, cwd='.'): cmd = shlex.split(cmd) return_code = subprocess.call(cmd, cwd=cwd, universal_newlines=True) if return_code: - logger.warn("{0} executed with exit code {1}".format(cmd_log, return_code)) + logger.warning("{0} executed with exit code {1}".format(cmd_log, return_code)) def which(executable, raise_err = False): @@ -449,13 +449,8 @@ def setup_logging(bench_path='.'): hdlr = logging.FileHandler(log_file) hdlr.setFormatter(formatter) - log_hndlr = logging.StreamHandler(sys.stdout) - log_hndlr.setFormatter(logging.Formatter('%(message)s')) - log_hndlr.addFilter(log_filter(LOG_LEVEL)) - logger.addHandler(hdlr) - logger.addHandler(log_hndlr) - logger.setLevel(logging.INFO) + logger.setLevel(logging.DEBUG) return logger @@ -985,7 +980,7 @@ def migrate_env(python, backup=False): logger.log('Clearing Redis DataBase...') exec_cmd('{redis} FLUSHDB'.format(redis = redis)) except: - logger.warn('Please ensure Redis Connections are running or Daemonized.') + logger.warning('Please ensure Redis Connections are running or Daemonized.') # Backup venv: restore using `virtualenv --relocatable` if needed if backup: @@ -1015,7 +1010,7 @@ def migrate_env(python, backup=False): logger.log('Migration Successful to {}'.format(python)) except: if venv_creation or packages_setup: - logger.warn('Migration Error') + logger.warning('Migration Error') def is_dist_editable(dist): From 0ba5a09975129b2cd926f5419cf47eea3e5e2279 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 21 May 2020 13:15:19 +0530 Subject: [PATCH 17/23] chore: remove unused class --- bench/utils.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/bench/utils.py b/bench/utils.py index 749a6e18..7914eecd 100755 --- a/bench/utils.py +++ b/bench/utils.py @@ -435,20 +435,12 @@ def setup_logging(bench_path='.'): self._log(LOG_LEVEL, message, args, **kws) logging.Logger.log = logv - class log_filter(object): - def __init__(self, level): - self.__level = level - - def filter(self, logRecord): - return logRecord.levelno == self.__level - if os.path.exists(os.path.join(bench_path, 'logs')): logger = logging.getLogger(bench.PROJECT_NAME) log_file = os.path.join(bench_path, 'logs', 'bench.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr = logging.FileHandler(log_file) hdlr.setFormatter(formatter) - logger.addHandler(hdlr) logger.setLevel(logging.DEBUG) From 2c5d1188b8a197dae5a45ac882d059afa5f69220 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 22 May 2020 17:17:35 +0530 Subject: [PATCH 18/23] chore: bump bench to v5.1.0 --- bench/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/__init__.py b/bench/__init__.py index f4ceb0c0..dd6d2c46 100644 --- a/bench/__init__.py +++ b/bench/__init__.py @@ -1,4 +1,4 @@ -VERSION = "5.0.0" +VERSION = "5.1.0" PROJECT_NAME = "frappe-bench" FRAPPE_VERSION = None From cac837547c67fdfd89d3c7f4d916000600732e2b Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Wed, 27 May 2020 19:56:45 +0530 Subject: [PATCH 19/23] fix: maintain worker and worker.error logfile in dev mode --- bench/config/templates/Procfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bench/config/templates/Procfile b/bench/config/templates/Procfile index e557f561..f810506e 100644 --- a/bench/config/templates/Procfile +++ b/bench/config/templates/Procfile @@ -11,9 +11,9 @@ watch: bench watch {% endif %} {% if use_rq -%} schedule: bench schedule -worker_short: bench worker --queue short --quiet -worker_long: bench worker --queue long --quiet -worker_default: bench worker --queue default --quiet +worker_short: bench worker --queue short 1>> logs/worker.log 2>> logs/worker.error.log +worker_long: bench worker --queue long 1>> logs/worker.log 2>> logs/worker.error.log +worker_default: bench worker --queue default 1>> logs/worker.log 2>> logs/worker.error.log {% else %} workerbeat: sh -c 'cd sites && exec ../env/bin/python -m frappe.celery_app beat -s scheduler.schedule' worker: sh -c 'cd sites && exec ../env/bin/python -m frappe.celery_app worker -n jobs@%h -Ofair --soft-time-limit 360 --time-limit 390' From 649997efba90d3f1bbaa7364a4647a6a6106d5be Mon Sep 17 00:00:00 2001 From: gavin Date: Thu, 28 May 2020 20:15:04 +0530 Subject: [PATCH 20/23] docs: re-link installation docs --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 0b2d03da..6d4be94d 100755 --- a/README.md +++ b/README.md @@ -147,6 +147,11 @@ For more information and advanced setup instructions, check out the [Easy Instal ### Manual Installation Although not recommended, some might want to manually setup a bench instance locally for development. To quickly get started on installing bench the hard way, you can follow [Installing Bench and Frappe](https://frappe.io/docs/user/en/installation). + + ```sh + $ pip install frappe-bench + ``` +Next you'll have to set up the pre-requisites for setting up a Frappe Environment. Checkout [docs/installation](https://github.com/frappe/bench/blob/master/docs/installation.md) for more information on this. For more extensive distribution-dependent documentation, check out the following guides: From a728416c08450e19c6e251d23d5429ee4fb36a68 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 29 May 2020 10:31:52 +0530 Subject: [PATCH 21/23] fix: update bench install methods --- README.md | 13 +++++++------ docs/installation.md | 7 ++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6d4be94d..9c521edb 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- +

Bench

@@ -141,17 +141,18 @@ In case the setup fails, the log file is saved under `/tmp/logs/install_bench.lo - Create an Issue in this repository with the log file attached. - Search for an existing issue or post the log file on the [Frappe/ERPNext Discuss Forum](https://discuss.erpnext.com/c/bench) with the tag `installation_problem` under "Install/Update" category. -For more information and advanced setup instructions, check out the [Easy Install Documentation](https://github.com/frappe/bench/blob/master/docs/easy_install.md). +For more information and advanced setup instructions, check out the [Easy Install Documentation](https://github.com/frappe/bench/blob/develop/docs/easy_install.md). ### Manual Installation Although not recommended, some might want to manually setup a bench instance locally for development. To quickly get started on installing bench the hard way, you can follow [Installing Bench and Frappe](https://frappe.io/docs/user/en/installation). - + ```sh $ pip install frappe-bench ``` -Next you'll have to set up the pre-requisites for setting up a Frappe Environment. Checkout [docs/installation](https://github.com/frappe/bench/blob/master/docs/installation.md) for more information on this. + +Next you'll have to set up the pre-requisites for setting up a Frappe Environment. Checkout [docs/installation](https://github.com/frappe/bench/blob/develop/docs/installation.md) for more information on this. For more extensive distribution-dependent documentation, check out the following guides: @@ -205,12 +206,12 @@ For more extensive distribution-dependent documentation, check out the following ``` -For more in-depth information on commands and their usage, follow [Commands and Usage](https://github.com/frappe/bench/blob/master/docs/commands_and_usage.md). As for a consolidated list of bench commands, check out [Bench Usage](https://github.com/frappe/bench/blob/master/docs/bench_usage.md). +For more in-depth information on commands and their usage, follow [Commands and Usage](https://github.com/frappe/bench/blob/develop/docs/commands_and_usage.md). As for a consolidated list of bench commands, check out [Bench Usage](https://github.com/frappe/bench/blob/develop/docs/bench_usage.md). ## Custom Bench Commands -If you wish to extend the capabilities of bench with your own custom Frappe Application, you may follow [Adding Custom Bench Commands](https://github.com/frappe/bench/blob/master/docs/bench_custom_cmd.md). +If you wish to extend the capabilities of bench with your own custom Frappe Application, you may follow [Adding Custom Bench Commands](https://github.com/frappe/bench/blob/develop/docs/bench_custom_cmd.md). ## Bench Manager diff --git a/docs/installation.md b/docs/installation.md index a7e0f06a..3d4d004e 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -30,9 +30,6 @@ To manually install frappe/erpnext, you can follow this [this wiki](https://gith #### 2. Install Bench -Install bench as a *non root* user, +Install the latest bench using pip - git clone https://github.com/frappe/bench ~/.bench - pip3 install --user -e ~/.bench - -Note: Please do not remove the bench directory the above commands will create + pip3 install frappe-bench From 5a6c8262a18914509a16ee7f58e98db7cd7e1ac7 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 29 May 2020 10:39:15 +0530 Subject: [PATCH 22/23] docs: minor restructure for manual installation --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9c521edb..51ecdade 100755 --- a/README.md +++ b/README.md @@ -146,13 +146,14 @@ For more information and advanced setup instructions, check out the [Easy Instal ### Manual Installation -Although not recommended, some might want to manually setup a bench instance locally for development. To quickly get started on installing bench the hard way, you can follow [Installing Bench and Frappe](https://frappe.io/docs/user/en/installation). +Some might want to manually setup a bench instance locally for development. To quickly get started on installing bench the hard way, you can follow the guide on [Installing Bench and the Frappe Framework](https://frappe.io/docs/user/en/installation). - ```sh - $ pip install frappe-bench - ``` +You'll have to set up the system dependencies required for setting up a Frappe Environment. Checkout [docs/installation](https://github.com/frappe/bench/blob/develop/docs/installation.md) for more information on this. If you've already set up, install bench via pip: -Next you'll have to set up the pre-requisites for setting up a Frappe Environment. Checkout [docs/installation](https://github.com/frappe/bench/blob/develop/docs/installation.md) for more information on this. + +```sh +$ pip install frappe-bench +``` For more extensive distribution-dependent documentation, check out the following guides: From e26a0a9b37237bcf97a3a0df9bb66937e56b6439 Mon Sep 17 00:00:00 2001 From: gavin Date: Tue, 2 Jun 2020 13:32:20 +0530 Subject: [PATCH 23/23] chore: fixed image src --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51ecdade..d9c2d1bb 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- +

Bench