def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False): "Run tests" import frappe.test_runner from frappe.utils import sel tests = test site = get_site(context) frappe.init(site=site) if frappe.conf.run_selenium_tests and False: sel.start(context.verbose, driver) try: ret = frappe.test_runner.main( app, module, doctype, context.verbose, tests=tests, force=context.force, profile=profile ) if len(ret.failures) == 0 and len(ret.errors) == 0: ret = 0 finally: pass if frappe.conf.run_selenium_tests: sel.close() sys.exit(ret)
def restore(context, sql_file_path, mariadb_root_username=None, mariadb_root_password=None, db_name=None, verbose=None, install_app=None, admin_password=None, force=None, with_public_files=None, with_private_files=None): "Restore site database from an sql file" from frappe.installer import extract_sql_gzip, extract_tar_files # Extract the gzip file if user has passed *.sql.gz file instead of *.sql file if not os.path.exists(sql_file_path): sql_file_path = '../' + sql_file_path if not os.path.exists(sql_file_path): print('Invalid path {0}' + sql_file_path[3:]) sys.exit(1) if sql_file_path.endswith('sql.gz'): sql_file_path = extract_sql_gzip(os.path.abspath(sql_file_path)) site = get_site(context) frappe.init(site=site) _new_site(frappe.conf.db_name, site, mariadb_root_username=mariadb_root_username, mariadb_root_password=mariadb_root_password, admin_password=admin_password, verbose=context.verbose, install_apps=install_app, source_sql=sql_file_path, force=context.force) # Extract public and/or private files to the restored site, if user has given the path if with_public_files: public = extract_tar_files(site, with_public_files, 'public') os.remove(public) if with_private_files: private = extract_tar_files(site, with_private_files, 'private') os.remove(private)
def list_apps(context): "List apps in site" site = get_site(context) frappe.init(site=site) frappe.connect() print("\n".join(frappe.get_installed_apps())) frappe.destroy()
def scheduler(context, state, site=None): from frappe.installer import update_site_config import frappe.utils.scheduler if not site: site = get_site(context) try: frappe.init(site=site) if state == "pause": update_site_config("pause_scheduler", 1) elif state == "resume": update_site_config("pause_scheduler", 0) elif state == "disable": frappe.connect() frappe.utils.scheduler.disable_scheduler() frappe.db.commit() elif state == "enable": frappe.connect() frappe.utils.scheduler.enable_scheduler() frappe.db.commit() print "Scheduler {0}d for site {1}".format(state, site) finally: frappe.destroy()
def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False, coverage=False, junit_xml_output=False, ui_tests = False, doctype_list_path=None, skip_test_records=False, skip_before_tests=False, failfast=False): "Run tests" import frappe.test_runner tests = test site = get_site(context) frappe.init(site=site) frappe.flags.skip_before_tests = skip_before_tests frappe.flags.skip_test_records = skip_test_records if coverage: # Generate coverage report only for app that is being tested source_path = os.path.join(get_bench_path(), 'apps', app or 'frappe') cov = Coverage(source=[source_path], omit=['*.html', '*.js', '*.css']) cov.start() ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests, force=context.force, profile=profile, junit_xml_output=junit_xml_output, ui_tests = ui_tests, doctype_list_path = doctype_list_path, failfast=failfast) if coverage: cov.stop() cov.save() if len(ret.failures) == 0 and len(ret.errors) == 0: ret = 0 if os.environ.get('CI'): sys.exit(ret)
def _set_limits(context, site, limits): import datetime if not limits: return if not site: site = get_site(context) with frappe.init_site(site): frappe.connect() new_limits = {} for limit, value in limits: if limit not in ('daily_emails', 'emails', 'space', 'users', 'email_group', 'expiry', 'support_email', 'support_chat', 'upgrade_url'): frappe.throw(_('Invalid limit {0}').format(limit)) if limit=='expiry' and value: try: datetime.datetime.strptime(value, '%Y-%m-%d') except ValueError: raise ValueError("Incorrect data format, should be YYYY-MM-DD") elif limit=='space': value = float(value) elif limit in ('users', 'emails', 'email_group', 'daily_emails'): value = int(value) new_limits[limit] = value update_limits(new_limits)
def import_csv(context, path, only_insert=False, submit_after_import=False, ignore_encoding_errors=False, no_email=True): "Import CSV using data import tool" from frappe.core.page.data_import_tool import importer from frappe.utils.csvutils import read_csv_content site = get_site(context) if not os.path.exists(path): path = os.path.join('..', path) if not os.path.exists(path): print('Invalid path {0}'.format(path)) sys.exit(1) with open(path, 'r') as csvfile: content = read_csv_content(csvfile.read()) frappe.init(site=site) frappe.connect() try: importer.upload(content, submit_after_import=submit_after_import, no_email=no_email, ignore_encoding_errors=ignore_encoding_errors, overwrite=not only_insert, via_console=True) frappe.db.commit() except Exception: print(frappe.get_traceback()) frappe.destroy()
def scheduler(context, state, site=None): from frappe.installer import update_site_config import frappe.utils.scheduler if not site: site = get_site(context) try: frappe.init(site=site) if state == 'pause': update_site_config('pause_scheduler', 1) elif state == 'resume': update_site_config('pause_scheduler', 0) elif state == 'disable': frappe.connect() frappe.utils.scheduler.disable_scheduler() frappe.db.commit() elif state == 'enable': frappe.connect() frappe.utils.scheduler.enable_scheduler() frappe.db.commit() print('Scheduler {0}d for site {1}'.format(state, site)) finally: frappe.destroy()
def import_csv(context, path, only_insert=False, submit_after_import=False, ignore_encoding_errors=False): "Import CSV using data import tool" from frappe.core.page.data_import_tool import importer from frappe.utils.csvutils import read_csv_content site = get_site(context) with open(path, "r") as csvfile: content = read_csv_content(csvfile.read()) frappe.init(site=site) frappe.connect() try: importer.upload( content, submit_after_import=submit_after_import, ignore_encoding_errors=ignore_encoding_errors, overwrite=not only_insert, via_console=True, ) frappe.db.commit() except Exception: print frappe.get_traceback() frappe.destroy()
def show_pending_jobs(context, site=None): "Get diagnostic info about background jobs" if not site: site = get_site(context) from frappe.utils.doctor import pending_jobs as _pending_jobs return _pending_jobs(site=site)
def disable_user(context, email): site = get_site(context) with frappe.init_site(site): frappe.connect() user = frappe.get_doc("User", email) user.enabled = 0 user.save(ignore_permissions=True) frappe.db.commit()
def console(context): "Start ipython console for a site" site = get_site(context) frappe.init(site=site) frappe.connect() frappe.local.lang = frappe.db.get_default("lang") import IPython IPython.embed()
def add_to_email_queue(context, email): "Add an email to the Email Queue" site = get_site(context) with frappe.init_site(site): frappe.connect() kwargs = json.loads(email) kwargs['delayed'] = True frappe.sendmail(**kwargs) frappe.db.commit()
def import_translations(context, lang, path): "Update translated strings" import frappe.translate site = get_site(context) try: frappe.init(site=site) frappe.connect() frappe.translate.import_translations(lang, path) finally: frappe.destroy()
def update_translations(context, lang, untranslated_file, translated_file): "Update translated strings" import frappe.translate site = get_site(context) try: frappe.init(site=site) frappe.connect() frappe.translate.update_translations(lang, untranslated_file, translated_file) finally: frappe.destroy()
def get_untranslated(context, lang, untranslated_file, all=None): "Get untranslated strings for language" import frappe.translate site = get_site(context) try: frappe.init(site=site) frappe.connect() frappe.translate.get_untranslated(lang, untranslated_file, get_all=all) finally: frappe.destroy()
def set_maintenance_mode(context, state, site=None): from frappe.installer import update_site_config if not site: site = get_site(context) try: frappe.init(site=site) update_site_config('maintenance_mode', 1 if (state == 'on') else 0) finally: frappe.destroy()
def set_training_mode(context, state, site=None): if not site: site = get_site(context) try: frappe.init(site=site) frappe.connect() frappe.db.set_value("BioTrack Settings", None, "is_training", 1 if (state == 'on') else 0) frappe.db.commit() print "Training mode set for site {}".format(site) finally: frappe.destroy()
def add_to_email_queue(context, email_path): "Add an email to the Email Queue" site = get_site(context) if os.path.isdir(email_path): with frappe.init_site(site): frappe.connect() for email in os.listdir(email_path): with open(os.path.join(email_path, email)) as email_data: kwargs = json.load(email_data) kwargs['delayed'] = True frappe.sendmail(**kwargs) frappe.db.commit()
def run_setup_wizard_ui_test(context, app=None, profile=False): "Run setup wizard UI test" import frappe.test_runner site = get_site(context) frappe.init(site=site) frappe.connect() ret = frappe.test_runner.run_setup_wizard_ui_test(app=app, verbose=context.verbose, profile=profile) if len(ret.failures) == 0 and len(ret.errors) == 0: ret = 0 if os.environ.get('CI'): sys.exit(ret)
def update(context): app = __name__.split('.')[0] app_dir = os.path.join('.', '../apps', app) if os.path.exists(os.path.join(app_dir, '.git')): print "Pulling app..." s = subprocess.Popen(['git', 'pull'], cwd=app_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out = s.stdout.read() s.stdout.close() print out site = get_site(context) frappe.init(site=site) frappe.connect() migrate() frappe.destroy()
def clear_limits(context, site, limits): """Clears given limit from the site config, and removes limit from site config if its empty""" from frappe.limits import clear_limit as _clear_limit if not limits: return if not site: site = get_site(context) with frappe.init_site(site): _clear_limit(limits) # Remove limits from the site_config, if it's empty limits = get_limits() if not limits: update_site_config('limits', 'None', validate=False)
def _bulk_rename(context, doctype, path): "Rename multiple records via CSV file" from frappe.model.rename_doc import bulk_rename from frappe.utils.csvutils import read_csv_content site = get_site(context) with open(path, 'r') as csvfile: rows = read_csv_content(csvfile.read()) frappe.init(site=site) frappe.connect() bulk_rename(doctype, rows, via_console = True) frappe.destroy()
def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False, junit_xml_output=False, ui_tests = False): "Run tests" import frappe.test_runner tests = test site = get_site(context) frappe.init(site=site) ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests, force=context.force, profile=profile, junit_xml_output=junit_xml_output, ui_tests = ui_tests) if len(ret.failures) == 0 and len(ret.errors) == 0: ret = 0 if os.environ.get('CI'): sys.exit(ret)
def mysql(context): "Start Mariadb console for a site" site = get_site(context) frappe.init(site=site) msq = find_executable("mysql") os.execv( msq, [ msq, "-u", frappe.conf.db_name, "-p" + frappe.conf.db_password, frappe.conf.db_name, "-h", frappe.conf.db_host or "localhost", "-A", ], )
def restore(context, sql_file_path, mariadb_root_username=None, mariadb_root_password=None, db_name=None, verbose=None, install_app=None, admin_password=None, force=None, with_public_files=None, with_private_files=None): "Restore site database from an sql file" from frappe.installer import extract_sql_gzip, extract_tar_files # Extract the gzip file if user has passed *.sql.gz file instead of *.sql file if sql_file_path.endswith('sql.gz'): sql_file_path = extract_sql_gzip(os.path.abspath(sql_file_path)) site = get_site(context) frappe.init(site=site) db_name = db_name or frappe.conf.db_name or hashlib.sha1(site).hexdigest()[:10] _new_site(db_name, site, mariadb_root_username=mariadb_root_username, mariadb_root_password=mariadb_root_password, admin_password=admin_password, verbose=context.verbose, install_apps=install_app, source_sql=sql_file_path, force=context.force) # Extract public and/or private files to the restored site, if user has given the path if with_public_files: extract_tar_files(site, with_public_files, 'public') if with_private_files: extract_tar_files(site, with_private_files, 'private')
def reinstall(context): "Reinstall site ie. wipe all data and start over" site = get_site(context) try: frappe.init(site=site) frappe.connect() frappe.clear_cache() installed = frappe.get_installed_apps() frappe.clear_cache() except Exception: installed = [] finally: if frappe.db: frappe.db.close() frappe.destroy() frappe.init(site=site) _new_site(frappe.conf.db_name, site, verbose=context.verbose, force=True, reinstall=True, install_apps=installed)
def set_last_active_for_user(context, user=None): "Set users last active date to current datetime" from frappe.core.doctype.user.user import get_system_users from frappe.utils.user import set_last_active_to_now site = get_site(context) with frappe.init_site(site): frappe.connect() if not user: user = get_system_users(limit=1) if len(user) > 0: user = user[0] else: return set_last_active_to_now(user) frappe.db.commit()
def mariadb(context): """ Enter into mariadb console for a given site. """ import os site = get_site(context) frappe.init(site=site) # This is assuming you're within the bench instance. mysql = find_executable('mysql') os.execv(mysql, [ mysql, '-u', frappe.conf.db_name, '-p'+frappe.conf.db_password, frappe.conf.db_name, '-h', frappe.conf.db_host or "localhost", '--pager=less -SFX', "-A"])
def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False, coverage=False, junit_xml_output=False, ui_tests = False, doctype_list_path=None, skip_test_records=False, skip_before_tests=False, failfast=False): "Run tests" import frappe.test_runner tests = test site = get_site(context) allow_tests = frappe.get_conf(site).allow_tests if not (allow_tests or os.environ.get('CI')): click.secho('Testing is disabled for the site!', bold=True) click.secho('You can enable tests by entering following command:') click.secho('bench --site {0} set-config allow_tests true'.format(site), fg='green') return frappe.init(site=site) frappe.flags.skip_before_tests = skip_before_tests frappe.flags.skip_test_records = skip_test_records if coverage: # Generate coverage report only for app that is being tested source_path = os.path.join(get_bench_path(), 'apps', app or 'frappe') cov = Coverage(source=[source_path], omit=['*.html', '*.js', '*.xml', '*.css', '*/doctype/*/*_dashboard.py', '*/patches/*']) cov.start() ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests, force=context.force, profile=profile, junit_xml_output=junit_xml_output, ui_tests = ui_tests, doctype_list_path = doctype_list_path, failfast=failfast) if coverage: cov.stop() cov.save() if len(ret.failures) == 0 and len(ret.errors) == 0: ret = 0 if os.environ.get('CI'): sys.exit(ret)
def run_ui_tests(context, app, headless=False, parallel=True, ci_build_id=None): "Run UI tests" site = get_site(context) app_base_path = os.path.abspath(os.path.join(frappe.get_app_path(app), '..')) site_url = frappe.utils.get_site_url(site) admin_password = frappe.get_conf(site).admin_password # override baseUrl using env variable site_env = f'CYPRESS_baseUrl={site_url}' password_env = f'CYPRESS_adminPassword={admin_password}' if admin_password else '' os.chdir(app_base_path) node_bin = subprocess.getoutput("npm bin") cypress_path = f"{node_bin}/cypress" plugin_path = f"{node_bin}/../cypress-file-upload" testing_library_path = f"{node_bin}/../@testing-library" # check if cypress in path...if not, install it. if not ( os.path.exists(cypress_path) and os.path.exists(plugin_path) and os.path.exists(testing_library_path) and cint(subprocess.getoutput("npm view cypress version")[:1]) >= 6 ): # install cypress click.secho("Installing Cypress...", fg="yellow") frappe.commands.popen("yarn add cypress@^6 cypress-file-upload@^5 @testing-library/cypress@^8 --no-lockfile") # run for headless mode run_or_open = 'run --browser firefox --record' if headless else 'open' command = '{site_env} {password_env} {cypress} {run_or_open}' formatted_command = command.format(site_env=site_env, password_env=password_env, cypress=cypress_path, run_or_open=run_or_open) if parallel: formatted_command += ' --parallel' if ci_build_id: formatted_command += f' --ci-build-id {ci_build_id}' click.secho("Running Cypress...", fg="yellow") frappe.commands.popen(formatted_command, cwd=app_base_path, raise_err=True)
def mariadb(context): """ Enter into mariadb console for a given site. """ import os import os.path as osp site = get_site(context) frappe.init(site=site) # This is assuming you're within the bench instance. path = os.getcwd() mysql = osp.join(path, '..', 'env', 'bin', 'mycli') args = [ mysql, '-u', frappe.conf.db_name, '-p', frappe.conf.db_password, '-h', frappe.conf.db_host or "localhost", '-D', frappe.conf.db_name, '-R', '{site}> '.format(site=site), '--auto-vertical-output', '--warn' ] os.execv(mysql, args)
def run_ui_tests(context, app, headless=False): "Run UI tests" site = get_site(context) app_base_path = os.path.abspath(os.path.join(frappe.get_app_path(app), '..')) site_url = frappe.utils.get_site_url(site) admin_password = frappe.get_conf(site).admin_password # override baseUrl using env variable site_env = 'CYPRESS_baseUrl={}'.format(site_url) password_env = 'CYPRESS_adminPassword={}'.format(admin_password) if admin_password else '' # run for headless mode run_or_open = 'run' if headless else 'open' # Brian - This may not work, simply substituting "npm" for "yarn" # Here's some info on the cypress CLI https://docs.cypress.io/guides/guides/command-line.html command = '{site_env} {password_env} npm run cypress:{run_or_open}' formatted_command = command.format(site_env=site_env, password_env=password_env, run_or_open=run_or_open) frappe.commands.popen(formatted_command, cwd=app_base_path, raise_err=True)
def run_ui_tests(context, app=None, ci=False): "Run UI tests" import subprocess site = get_site(context) frappe.init(site=site) if app is None: app = ",".join(frappe.get_installed_apps()) cmd = [ './node_modules/.bin/nightwatch', '--config', './apps/frappe/frappe/nightwatch.js', '--app', app, '--site', site ] if ci: cmd.extend(['--env', 'ci_server']) bench_path = frappe.utils.get_bench_path() subprocess.call(cmd, cwd=bench_path)
def ready_for_migration(context, site=None): from frappe.utils.doctor import get_pending_jobs if not site: site = get_site(context) try: frappe.init(site=site) pending_jobs = get_pending_jobs(site=site) if pending_jobs: print('NOT READY for migration: site {0} has pending background jobs'.format(site)) sys.exit(1) else: print('READY for migration: site {0} does not have any background jobs'.format(site)) return 0 finally: frappe.destroy()
def mariadb(context): """ Enter into mariadb console for a given site. """ import os site = get_site(context) frappe.init(site=site) # This is assuming you're within the bench instance. mysql = find_executable('mysql') os.execv(mysql, [ mysql, '-u', frappe.conf.db_name, '-p'+frappe.conf.db_password, frappe.conf.db_name, '-h', frappe.conf.db_host or "localhost", '--pager=less -SFX', '--safe-updates', "-A"])
def run_ui_tests(context, app, headless=False): "Run UI tests" site = get_site(context) app_base_path = os.path.abspath( os.path.join(frappe.get_app_path(app), '..')) site_url = frappe.utils.get_site_url(site) admin_password = frappe.get_conf(site).admin_password # override baseUrl using env variable site_env = 'CYPRESS_baseUrl={}'.format(site_url) password_env = 'CYPRESS_adminPassword={}'.format( admin_password) if admin_password else '' # run for headless mode run_or_open = 'run' if headless else 'open' command = '{site_env} {password_env} yarn run cypress {run_or_open}' formatted_command = command.format(site_env=site_env, password_env=password_env, run_or_open=run_or_open) frappe.commands.popen(formatted_command, cwd=app_base_path, raise_err=True)
def _set_limits(context, site, limits): import datetime if not limits: return if not site: site = get_site(context) with frappe.init_site(site): frappe.connect() new_limits = {} for limit, value in limits: if limit not in ('daily_emails', 'emails', 'space', 'users', 'email_group', 'currency', 'expiry', 'support_email', 'support_chat', 'upgrade_url', 'subscription_id', 'subscription_type', 'current_plan', 'subscription_base_price', 'upgrade_plan', 'upgrade_base_price', 'cancellation_url', 'subscription_status', 'support_tickets_limit'): frappe.throw(_('Invalid limit {0}').format(limit)) if limit == 'expiry' and value: try: datetime.datetime.strptime(value, '%Y-%m-%d') except ValueError: raise ValueError( "Incorrect data format, should be YYYY-MM-DD") elif limit in ('space', 'subscription_base_price', 'upgrade_base_price'): value = float(value) elif limit in ('users', 'emails', 'email_group', 'daily_emails'): value = int(value) new_limits[limit] = value update_limits(new_limits)
def import_csv( context, path, only_insert=False, submit_after_import=False, ignore_encoding_errors=False, no_email=True, ): "Import CSV using data import" from frappe.core.doctype.data_import_legacy import importer from frappe.utils.csvutils import read_csv_content site = get_site(context) if not os.path.exists(path): path = os.path.join("..", path) if not os.path.exists(path): print("Invalid path {0}".format(path)) sys.exit(1) with open(path, "r") as csvfile: content = read_csv_content(csvfile.read()) frappe.init(site=site) frappe.connect() try: importer.upload( content, submit_after_import=submit_after_import, no_email=no_email, ignore_encoding_errors=ignore_encoding_errors, overwrite=not only_insert, via_console=True, ) frappe.db.commit() except Exception: print(frappe.get_traceback()) frappe.destroy()
def console(context): "Start ipython console for a site" site = get_site(context) frappe.init(site=site) frappe.connect() frappe.local.lang = frappe.db.get_default("lang") import IPython all_apps = frappe.get_installed_apps() failed_to_import = [] for app in all_apps: try: locals()[app] = __import__(app) except ModuleNotFoundError: failed_to_import.append(app) print("Apps in this namespace:\n{}".format(", ".join(all_apps))) if failed_to_import: print("\nFailed to import:\n{}".format(", ".join(failed_to_import))) IPython.embed(display_banner="", header="", colors="neutral")
def run_ui_tests(context, app=None, test=False, test_list=False, profile=False): "Run UI tests" import frappe.test_runner site = get_site(context) frappe.init(site=site) frappe.connect() ret = frappe.test_runner.run_ui_tests(app=app, test=test, test_list=test_list, verbose=context.verbose, profile=profile) if len(ret.failures) == 0 and len(ret.errors) == 0: ret = 0 if os.environ.get('CI'): sys.exit(ret)
def jupyter(context): try: from pip import main except ImportError: from pip._internal import main reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze']) installed_packages = [r.decode().split('==')[0] for r in reqs.split()] if 'jupyter' not in installed_packages: main(['install', 'jupyter']) site = get_site(context) frappe.init(site=site) jupyter_notebooks_path = os.path.abspath( frappe.get_site_path('jupyter_notebooks')) sites_path = os.path.abspath(frappe.get_site_path('..')) try: os.stat(jupyter_notebooks_path) except OSError: print('Creating folder to keep jupyter notebooks at {}'.format( jupyter_notebooks_path)) os.mkdir(jupyter_notebooks_path) bin_path = os.path.abspath('../env/bin') print(''' Stating Jupyter notebook Run the following in your first cell to connect notebook to frappe ``` import frappe frappe.init(site='{site}', sites_path='{sites_path}') frappe.connect() frappe.local.lang = frappe.db.get_default('lang') frappe.db.connect() ``` '''.format(site=site, sites_path=sites_path)) os.execv('{0}/jupyter'.format(bin_path), [ '{0}/jupyter'.format(bin_path), 'notebook', jupyter_notebooks_path, ])
def reinstall(context, admin_password=None, yes=False): "Reinstall site ie. wipe all data and start over" if not yes: click.confirm('This will wipe your database. Are you sure you want to reinstall?', abort=True) site = get_site(context) try: frappe.init(site=site) frappe.connect() frappe.clear_cache() installed = frappe.get_installed_apps() frappe.clear_cache() except Exception: installed = [] finally: if frappe.db: frappe.db.close() frappe.destroy() frappe.init(site=site) _new_site(frappe.conf.db_name, site, verbose=context.verbose, force=True, reinstall=True, install_apps=installed, admin_password=admin_password)
def run_ui_tests(context, app, headless=False): "Run UI tests" site = get_site(context) app_base_path = os.path.abspath( os.path.join(frappe.get_app_path(app), '..')) site_url = frappe.utils.get_site_url(site) admin_password = frappe.get_conf(site).admin_password # override baseUrl using env variable site_env = 'CYPRESS_baseUrl={}'.format(site_url) password_env = 'CYPRESS_adminPassword={}'.format( admin_password) if admin_password else '' os.chdir(app_base_path) node_bin = subprocess.getoutput("npm bin") cypress_path = "{0}/cypress".format(node_bin) plugin_path = "{0}/cypress-file-upload".format(node_bin) # check if cypress in path...if not, install it. if not (os.path.exists(cypress_path) or os.path.exists(plugin_path)) \ or not subprocess.getoutput("npm view cypress version").startswith("6."): # install cypress click.secho("Installing Cypress...", fg="yellow") frappe.commands.popen( "yarn add cypress@^6 cypress-file-upload@^5 --no-lockfile") # run for headless mode run_or_open = 'run --browser firefox --record --key 4a48f41c-11b3-425b-aa88-c58048fa69eb' if headless else 'open' command = '{site_env} {password_env} {cypress} {run_or_open}' formatted_command = command.format(site_env=site_env, password_env=password_env, cypress=cypress_path, run_or_open=run_or_open) click.secho("Running Cypress...", fg="yellow") frappe.commands.popen(formatted_command, cwd=app_base_path, raise_err=True)
def restore(context, sql_file_path, mariadb_root_username=None, mariadb_root_password=None, db_name=None, verbose=None, install_app=None, admin_password=None, force=None, with_public_files=None, with_private_files=None): "Restore site database from an sql file" from frappe.installer import extract_sql_gzip, extract_tar_files # Extract the gzip file if user has passed *.sql.gz file instead of *.sql file if sql_file_path.endswith('sql.gz'): sql_file_path = extract_sql_gzip(os.path.abspath(sql_file_path)) site = get_site(context) frappe.init(site=site) db_name = db_name or frappe.conf.db_name or hashlib.sha1( site).hexdigest()[:10] _new_site(db_name, site, mariadb_root_username=mariadb_root_username, mariadb_root_password=mariadb_root_password, admin_password=admin_password, verbose=context.verbose, install_apps=install_app, source_sql=sql_file_path, force=context.force) # Extract public and/or private files to the restored site, if user has given the path if with_public_files: extract_tar_files(site, with_public_files, 'public') if with_private_files: extract_tar_files(site, with_private_files, 'private')
def make_demo(context, site, domain='Manufacturing', days=100, resume=False, reinstall=False): "Reinstall site and setup demo" from frappe.commands.site import _reinstall from frappe.installer import install_app site = get_site(context) if resume: with frappe.init_site(site): frappe.connect() from erpnext.demo import demo demo.simulate(days=days) else: if reinstall: _reinstall(site, yes=True) with frappe.init_site(site=site): frappe.connect() if not 'erpnext' in frappe.get_installed_apps(): install_app('erpnext') # import needs site from erpnext.demo import demo demo.make(domain, days)
def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False, junit_xml_output=False): "Run tests" import frappe.test_runner from frappe.utils import sel tests = test site = get_site(context) frappe.init(site=site) if frappe.conf.run_selenium_tests and False: sel.start(context.verbose, driver) try: ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests, force=context.force, profile=profile, junit_xml_output=junit_xml_output) if len(ret.failures) == 0 and len(ret.errors) == 0: ret = 0 finally: pass if frappe.conf.run_selenium_tests: sel.close() sys.exit(ret)
def restore( context, sql_file_path, db_root_username=None, db_root_password=None, db_name=None, verbose=None, install_app=None, admin_password=None, force=None, with_public_files=None, with_private_files=None, ): "Restore site database from an sql file" from frappe.installer import ( _new_site, extract_files, extract_sql_from_archive, is_downgrade, is_partial, validate_database_sql, ) force = context.force or force decompressed_file_name = extract_sql_from_archive(sql_file_path) # check if partial backup if is_partial(decompressed_file_name): click.secho( "Partial Backup file detected. You cannot use a partial file to restore a Frappe Site.", fg="red", ) click.secho( "Use `bench partial-restore` to restore a partial backup to an existing site.", fg="yellow") sys.exit(1) # check if valid SQL file validate_database_sql(decompressed_file_name, _raise=not force) site = get_site(context) frappe.init(site=site) # dont allow downgrading to older versions of frappe without force if not force and is_downgrade(decompressed_file_name, verbose=True): warn_message = ( "This is not recommended and may lead to unexpected behaviour. " "Do you want to continue anyway?") click.confirm(warn_message, abort=True) _new_site( frappe.conf.db_name, site, db_root_username=db_root_username, db_root_password=db_root_password, admin_password=admin_password, verbose=context.verbose, install_apps=install_app, source_sql=decompressed_file_name, force=True, db_type=frappe.conf.db_type, ) # Extract public and/or private files to the restored site, if user has given the path if with_public_files: public = extract_files(site, with_public_files) os.remove(public) if with_private_files: private = extract_files(site, with_private_files) os.remove(private) # Removing temporarily created file if decompressed_file_name != sql_file_path: os.remove(decompressed_file_name) success_message = "Site {0} has been restored{1}".format( site, " with files" if (with_public_files or with_private_files) else "") click.secho(success_message, fg="green")
def restore(context, sql_file_path, mariadb_root_username=None, mariadb_root_password=None, db_name=None, verbose=None, install_app=None, admin_password=None, force=None, with_public_files=None, with_private_files=None): "Restore site database from an sql file" from frappe.installer import extract_sql_gzip, extract_tar_files, is_downgrade force = context.force or force # Extract the gzip file if user has passed *.sql.gz file instead of *.sql file if not os.path.exists(sql_file_path): base_path = '..' sql_file_path = os.path.join(base_path, sql_file_path) if not os.path.exists(sql_file_path): print('Invalid path {0}'.format(sql_file_path[3:])) sys.exit(1) elif sql_file_path.startswith(os.sep): base_path = os.sep else: base_path = '.' if sql_file_path.endswith('sql.gz'): decompressed_file_name = extract_sql_gzip( os.path.abspath(sql_file_path)) else: decompressed_file_name = sql_file_path site = get_site(context) frappe.init(site=site) # dont allow downgrading to older versions of frappe without force if not force and is_downgrade(decompressed_file_name, verbose=True): warn_message = "This is not recommended and may lead to unexpected behaviour. Do you want to continue anyway?" click.confirm(warn_message, abort=True) _new_site(frappe.conf.db_name, site, mariadb_root_username=mariadb_root_username, mariadb_root_password=mariadb_root_password, admin_password=admin_password, verbose=context.verbose, install_apps=install_app, source_sql=decompressed_file_name, force=True, db_type=frappe.conf.db_type) # Extract public and/or private files to the restored site, if user has given the path if with_public_files: with_public_files = os.path.join(base_path, with_public_files) public = extract_tar_files(site, with_public_files, 'public') os.remove(public) if with_private_files: with_private_files = os.path.join(base_path, with_private_files) private = extract_tar_files(site, with_private_files, 'private') os.remove(private) # Removing temporarily created file if decompressed_file_name != sql_file_path: os.remove(decompressed_file_name) success_message = "Site {0} has been restored{1}".format( site, " with files" if (with_public_files or with_private_files) else "") click.secho(success_message, fg="green")
def transform_database(context, table, engine, row_format, failfast): "Transform site database through given parameters" site = get_site(context) check_table = [] add_line = False skipped = 0 frappe.init(site=site) if frappe.conf.db_type and frappe.conf.db_type != "mariadb": click.secho( "This command only has support for MariaDB databases at this point", fg="yellow") sys.exit(1) if not (engine or row_format): click.secho("Values for `--engine` or `--row_format` must be set") sys.exit(1) frappe.connect() if table == "all": information_schema = frappe.qb.Schema("information_schema") queried_tables = frappe.qb.from_( information_schema.tables).select("table_name").where( (information_schema.tables.row_format != row_format) & (information_schema.tables.table_schema == frappe.conf.db_name)).run() tables = [x[0] for x in queried_tables] else: tables = [x.strip() for x in table.split(",")] total = len(tables) for current, table in enumerate(tables): values_to_set = "" if engine: values_to_set += f" ENGINE={engine}" if row_format: values_to_set += f" ROW_FORMAT={row_format}" try: frappe.db.sql(f"ALTER TABLE `{table}`{values_to_set}") update_progress_bar("Updating table schema", current - skipped, total) add_line = True except Exception as e: check_table.append([table, e.args]) skipped += 1 if failfast: break if add_line: print() for errored_table in check_table: table, err = errored_table err_msg = f"{table}: ERROR {err[0]}: {err[1]}" click.secho(err_msg, fg="yellow") frappe.destroy()
def take(context, name): site = get_site(context) frappe.init(site=site) frappe.connect() SnapshotGenerator(name).take() frappe.db.close()
def delete(context, name): site = get_site(context) frappe.init(site=site) SnapshotGenerator(name).delete()
def list(context): site = get_site(context) frappe.init(site=site) for name, filename in get_snapshots_data().items(): print name
def restore(context, sql_file_path, mariadb_root_username=None, mariadb_root_password=None, db_name=None, verbose=None, install_app=None, admin_password=None, force=None, with_public_files=None, with_private_files=None): "Restore site database from an sql file" from frappe.installer import extract_sql_gzip, extract_tar_files # Extract the gzip file if user has passed *.sql.gz file instead of *.sql file if not os.path.exists(sql_file_path): base_path = '..' sql_file_path = os.path.join(base_path, sql_file_path) if not os.path.exists(sql_file_path): print('Invalid path {0}'.format(sql_file_path[3:])) sys.exit(1) elif sql_file_path.startswith(os.sep): base_path = os.sep else: base_path = '.' if sql_file_path.endswith('sql.gz'): decompressed_file_name = extract_sql_gzip( os.path.abspath(sql_file_path)) else: decompressed_file_name = sql_file_path site = get_site(context) frappe.init(site=site) _new_site(frappe.conf.db_name, site, mariadb_root_username=mariadb_root_username, mariadb_root_password=mariadb_root_password, admin_password=admin_password, verbose=context.verbose, install_apps=install_app, source_sql=decompressed_file_name, force=True) # Extract public and/or private files to the restored site, if user has given the path if with_public_files: with_public_files = os.path.join(base_path, with_public_files) public = extract_tar_files(site, with_public_files, 'public') os.remove(public) if with_private_files: with_private_files = os.path.join(base_path, with_private_files) private = extract_tar_files(site, with_private_files, 'private') os.remove(private) # Removing temporarily created file if decompressed_file_name != sql_file_path: os.remove(decompressed_file_name) success_message = "Site {0} has been restored{1}".format( site, " with files" if (with_public_files or with_private_files) else "") click.secho(success_message, fg="green")
def reinstall(context, admin_password=None, yes=False): "Reinstall site ie. wipe all data and start over" site = get_site(context) _reinstall(site, admin_password, yes, verbose=context.verbose)
def mysql(context): "Start Mariadb console for a site" site = get_site(context) frappe.init(site=site) msq = find_executable('mysql') os.execv(msq, [msq, '-u', frappe.conf.db_name, '-p'+frappe.conf.db_password, frappe.conf.db_name, '-h', frappe.conf.db_host or "localhost", "-A"])
def doctor(context, site=None): "Get diagnostic info about background workers" from frappe.utils.doctor import doctor as _doctor if not site: site = get_site(context, raise_err=False) return _doctor(site=site)