diff --git a/frappe/commands/site.py b/frappe/commands/site.py index f8ff07db1d..90765ae2e3 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -103,11 +103,11 @@ def _new_site(db_name, site, mariadb_root_username=None, mariadb_root_password=N @click.option('--install-app', multiple=True, help='Install app after installation') @click.option('--with-public-files', help='Restores the public files of the site, given path to its tar file') @click.option('--with-private-files', help='Restores the private files of the site, given path to its tar file') -@click.option('--force', is_flag=True, default=False, help='Ignore the site downgrade warning, if applicable') +@click.option('--force', is_flag=True, default=False, help='Ignore the validations and downgrade warnings. This action is not recommended') @pass_context 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_files, is_downgrade + from frappe.installer import extract_sql_gzip, extract_files, is_downgrade, validate_database_sql force = context.force or force # Extract the gzip file if user has passed *.sql.gz file instead of *.sql file @@ -127,6 +127,7 @@ def restore(context, sql_file_path, mariadb_root_username=None, mariadb_root_pas else: decompressed_file_name = sql_file_path + validate_database_sql(decompressed_file_name, _raise=force) site = get_site(context) frappe.init(site=site) @@ -305,15 +306,16 @@ def migrate_to(context, frappe_provider): @click.command('run-patch') @click.argument('module') +@click.option('--force', is_flag=True) @pass_context -def run_patch(context, module): +def run_patch(context, module, force): "Run a particular patch" import frappe.modules.patch_handler for site in context.sites: frappe.init(site=site) try: frappe.connect() - frappe.modules.patch_handler.run_single(module, force=context.force) + frappe.modules.patch_handler.run_single(module, force=force or context.force) finally: frappe.destroy() if not context.sites: diff --git a/frappe/exceptions.py b/frappe/exceptions.py index 60c17f6d5c..267f5410af 100644 --- a/frappe/exceptions.py +++ b/frappe/exceptions.py @@ -110,3 +110,4 @@ class DocumentAlreadyRestored(Exception): pass class InvalidAuthorizationHeader(CSRFTokenError): pass class InvalidAuthorizationPrefix(CSRFTokenError): pass class InvalidAuthorizationToken(CSRFTokenError): pass +class InvalidDatabaseFile(ValidationError): pass \ No newline at end of file diff --git a/frappe/installer.py b/frappe/installer.py index df767a3294..51113beae8 100755 --- a/frappe/installer.py +++ b/frappe/installer.py @@ -406,3 +406,30 @@ def is_downgrade(sql_file_path, verbose=False): print("Your site will be downgraded from Frappe {0} to {1}".format(current_version, backup_version)) return downgrade + + +def validate_database_sql(path, _raise=True): + """Check if file has contents and if DefaultValue table exists + + Args: + path (str): Path of the decompressed SQL file + _raise (bool, optional): Raise exception if invalid file. Defaults to True. + """ + _raise = False + error_message = "" + + if not os.path.getsize(path): + error_message = f"{path} is an empty file!" + _raise = True + + if not _raise: + with open(path, "r") as f: + for line in f: + if 'tabDefaultValue' in line: + error_message = "Table `tabDefaultValue` not found in file." + _raise = True + + if error_message and _raise: + import click + click.secho(error_message, fg="red") + raise frappe.InvalidDatabaseFile