# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt from __future__ import unicode_literals """ Execute Patch Files To run directly python lib/wnf.py patch patch1, patch2 etc python lib/wnf.py patch -f patch1, patch2 etc where patch1, patch2 is module name """ import webnotes, os class PatchError(Exception): pass def run_all(): """run all pending patches""" executed = [p[0] for p in webnotes.conn.sql("""select patch from `tabPatch Log`""")] for patch in get_all_patches(): if patch and (patch not in executed): if not run_single(patchmodule = patch): log(patch + ': failed: STOPPED') raise PatchError(patch) def get_all_patches(): patches = [] for app in webnotes.get_installed_apps(): patches.extend(webnotes.get_file_items(webnotes.get_pymodule_path(app, "patches.txt"))) return patches def reload_doc(args): import webnotes.modules run_single(method = webnotes.modules.reload_doc, methodargs = args) def run_single(patchmodule=None, method=None, methodargs=None, force=False): from webnotes import conf # don't write txt files conf.developer_mode = 0 if force or method or not executed(patchmodule): return execute_patch(patchmodule, method, methodargs) else: return True def execute_patch(patchmodule, method=None, methodargs=None): """execute the patch""" success = False block_user(True) webnotes.conn.begin() try: log('Executing %s in %s' % (patchmodule or str(methodargs), webnotes.conn.cur_db_name)) if patchmodule: if patchmodule.startswith("execute:"): exec patchmodule.split("execute:")[1] in globals() else: webnotes.get_attr(patchmodule + ".execute")() update_patch_log(patchmodule) elif method: method(**methodargs) webnotes.conn.commit() success = True except Exception, e: webnotes.conn.rollback() tb = webnotes.get_traceback() log(tb) import os if webnotes.request: add_to_patch_log(tb) block_user(False) if success: log('Success') return success def add_to_patch_log(tb): """add error log to patches/patch.log""" import conf, os # TODO use get_site_base_path with open(os.path.join(os.path.dirname(conf.__file__), 'app', 'patches','patch.log'),'a') as patchlog: patchlog.write('\n\n' + tb) def update_patch_log(patchmodule): """update patch_file in patch log""" if webnotes.conn.table_exists("__PatchLog"): webnotes.conn.sql("""INSERT INTO `__PatchLog` VALUES (%s, now())""", \ patchmodule) else: webnotes.doc({"doctype": "Patch Log", "patch": patchmodule}).insert() def executed(patchmodule): """return True if is executed""" if webnotes.conn.table_exists("__PatchLog"): done = webnotes.conn.sql("""select patch from __PatchLog where patch=%s""", patchmodule) else: done = webnotes.conn.get_value("Patch Log", {"patch": patchmodule}) if done: print "Patch %s executed in %s" % (patchmodule, webnotes.conn.cur_db_name) return done def block_user(block): """stop/start execution till patch is run""" webnotes.conn.begin() msg = "Patches are being executed in the system. Please try again in a few moments." webnotes.conn.set_global('__session_status', block and 'stop' or None) webnotes.conn.set_global('__session_status_message', block and msg or None) webnotes.conn.commit() def setup(): webnotes.conn.sql("""CREATE TABLE IF NOT EXISTS `__PatchLog` ( patch TEXT, applied_on DATETIME) engine=InnoDB""") def log(msg): if getattr(webnotes.local, "patch_log_list", None) is None: webnotes.local.patch_log_list = [] webnotes.local.patch_log_list.append(msg)