diff --git a/core/doctype/custom_script/custom_script.py b/core/doctype/custom_script/custom_script.py index 939e4e63ff..9981b3ed3b 100644 --- a/core/doctype/custom_script/custom_script.py +++ b/core/doctype/custom_script/custom_script.py @@ -17,29 +17,11 @@ class DocType: def on_trash(self): webnotes.clear_cache(doctype=self.doc.dt) -def get_custom_server_script(doctype, plugin=None): - import os, MySQLdb - custom_script = webnotes.cache().get_value("_server_script:" + doctype) - - if not custom_script: - try: - script_path = get_custom_server_script_path(doctype, plugin) - if os.path.exists(script_path): - with open(script_path, 'r') as f: - custom_script = f.read() - else: - custom_script = "Does Not Exist" - webnotes.cache().set_value("_server_script:" + doctype, custom_script) - except (webnotes.DoesNotExistError, MySQLdb.OperationalError): - # this happens when syncing - return None - - return None if custom_script == "Does Not Exist" else custom_script - def make_custom_server_script_file(doctype, script=None): import os + from webnotes.plugins import get_path - file_path = get_custom_server_script_path(doctype) + file_path = get_path(None, "DocType", doctype) if os.path.exists(file_path): raise IOError(file_path + " already exists") @@ -58,24 +40,4 @@ class CustomDocType(DocType): {script}""".format(script=script or "\tpass") with open(file_path, "w") as f: - f.write(custom_script) - -def get_custom_server_script_path(doctype, plugin=None): - from webnotes.modules import scrub, get_plugin_path - from webnotes.utils import get_site_base_path - import os - - # check if doctype exists - opts = webnotes.conn.get_value("DocType", doctype, ["name", "module", "plugin"]) - if not opts: - raise webnotes.DoesNotExistError("""DocType "{doctype}" does not exist""".format(doctype=doctype)) - - name, module, doctype_plugin = opts - if not plugin: - plugin = doctype_plugin or os.path.basename(get_site_base_path()) - - # site_abs_path/plugin_name/module_name/doctype/doctype_name/doctype_name.py - path = os.path.join(get_plugin_path(scrub(plugin)), scrub(module), - "doctype", scrub(doctype), scrub(doctype) + ".py") - - return path + f.write(custom_script) \ No newline at end of file diff --git a/core/doctype/report/report.py b/core/doctype/report/report.py index 95d735d80d..7b710bedda 100644 --- a/core/doctype/report/report.py +++ b/core/doctype/report/report.py @@ -29,8 +29,12 @@ class DocType: self.export_doc() def export_doc(self): - # export + from webnotes.modules.export_file import export_to_files if self.doc.is_standard == 'Yes' and (conf.get('developer_mode') or 0) == 1: - from webnotes.modules.export_file import export_to_files export_to_files(record_list=[['Report', self.doc.name]], - record_module=webnotes.conn.get_value("DocType", self.doc.ref_doctype, "module")) \ No newline at end of file + record_module=webnotes.conn.get_value("DocType", self.doc.ref_doctype, "module")) + elif self.doc.is_standard == 'No' and self.doc.report_type == "Script Report": + from webnotes.plugins import get_plugin_name + export_to_files(record_list=[['Report', self.doc.name]], + record_module=webnotes.conn.get_value("DocType", self.doc.ref_doctype, "module"), + plugin=get_plugin_name("Report", self.doc.name), create_init=False) \ No newline at end of file diff --git a/webnotes/model/code.py b/webnotes/model/code.py index 2690760bfe..cf45c7d37a 100644 --- a/webnotes/model/code.py +++ b/webnotes/model/code.py @@ -19,7 +19,7 @@ def get_server_obj(doc, doclist = [], basedoctype = ''): # for test import webnotes from webnotes.modules import scrub, get_doctype_module - from core.doctype.custom_script.custom_script import get_custom_server_script + from webnotes.plugins import get_code_and_execute # get doctype details module = get_doctype_module(doc.doctype) or "core" @@ -33,13 +33,10 @@ def get_server_obj(doc, doclist = [], basedoctype = ''): return DocType(doc, doclist) # custom? - custom_script = get_custom_server_script(doc.doctype) - - if custom_script: - opts = {"DocType": DocType} - exec custom_script in opts - return opts["CustomDocType"](doc, doclist) - + namespace = {"DocType": DocType} + get_code_and_execute(module, "DocType", doc.doctype, namespace=namespace) + if namespace.get("CustomDocType"): + return namespace["CustomDocType"](doc, doclist) else: return DocType(doc, doclist) diff --git a/webnotes/model/doctype.py b/webnotes/model/doctype.py index 6b1e3c20cb..9066390413 100644 --- a/webnotes/model/doctype.py +++ b/webnotes/model/doctype.py @@ -228,11 +228,11 @@ def cache_name(doctype, processed): return "doctype:" + doctype + suffix def clear_cache(doctype=None): - + import webnotes.plugins def clear_single(dt): webnotes.cache().delete_value(cache_name(dt, False)) webnotes.cache().delete_value(cache_name(dt, True)) - webnotes.cache().delete_value("_server_script:" + dt) + webnotes.plugins.clear_cache("DocType", dt) if doctype_cache and doctype in doctype_cache: del doctype_cache[dt] diff --git a/webnotes/modules/__init__.py b/webnotes/modules/__init__.py index 73cbefa103..f438f44a8b 100644 --- a/webnotes/modules/__init__.py +++ b/webnotes/modules/__init__.py @@ -32,10 +32,6 @@ def get_module_path(module): return os.path.join(app_path, 'lib', m) else: return os.path.join(app_path, 'app', m) - -def get_plugin_path(plugin): - from webnotes.utils import get_site_path - return get_site_path(webnotes.conf.get("plugins_path"), scrub(plugin)) def get_doc_path(module, doctype, name): dt, dn = scrub_dt_dn(doctype, name) diff --git a/webnotes/modules/export_file.py b/webnotes/modules/export_file.py index 90f0ae41a3..32cb193304 100644 --- a/webnotes/modules/export_file.py +++ b/webnotes/modules/export_file.py @@ -5,12 +5,13 @@ from __future__ import unicode_literals import webnotes, os import webnotes.model.doc -from webnotes.modules import scrub, get_module_path, lower_case_files_for, scrub_dt_dn, get_plugin_path +from webnotes.modules import scrub, get_module_path, lower_case_files_for, scrub_dt_dn +from webnotes.plugins import get_plugin_path def export_doc(doc): export_to_files([[doc.doctype, doc.name]]) -def export_to_files(record_list=None, record_module=None, verbose=0, plugin=None): +def export_to_files(record_list=None, record_module=None, verbose=0, plugin=None, create_init=None): """ Export record_list to files. record_list is a list of lists ([doctype],[docname] ) , """ @@ -21,21 +22,22 @@ def export_to_files(record_list=None, record_module=None, verbose=0, plugin=None if record_list: for record in record_list: write_document_file(webnotes.model.doc.get(record[0], record[1]), - record_module, plugin=plugin) + record_module, plugin=plugin, create_init=create_init) -def write_document_file(doclist, record_module=None, plugin=None): +def write_document_file(doclist, record_module=None, plugin=None, create_init=None): from webnotes.modules.utils import pprint_doclist doclist = [filter_fields(d.fields) for d in doclist] module = record_module or get_module_name(doclist) - code_type = doclist[0]['doctype'] in lower_case_files_for + if create_init is None: + create_init = doclist[0]['doctype'] in lower_case_files_for # create folder - folder = create_folder(module, doclist[0]['doctype'], doclist[0]['name'], code_type, plugin=plugin) + folder = create_folder(module, doclist[0]['doctype'], doclist[0]['name'], create_init, plugin=plugin) # write the data file - fname = (code_type and scrub(doclist[0]['name'])) or doclist[0]['name'] + fname = (doclist[0]['doctype'] in lower_case_files_for and scrub(doclist[0]['name'])) or doclist[0]['name'] with open(os.path.join(folder, fname +'.txt'),'w+') as txtfile: txtfile.write(pprint_doclist(doclist)) @@ -71,7 +73,7 @@ def get_module_name(doclist): return module -def create_folder(module, dt, dn, code_type, plugin=None): +def create_folder(module, dt, dn, create_init, plugin=None): if plugin: module_path = os.path.join(get_plugin_path(plugin), scrub(module)) else: @@ -85,7 +87,7 @@ def create_folder(module, dt, dn, code_type, plugin=None): webnotes.create_folder(folder) # create init_py_files - if code_type: + if create_init: create_init_py(module_path, dt, dn) return folder diff --git a/webnotes/plugins.py b/webnotes/plugins.py new file mode 100644 index 0000000000..93c8ebe194 --- /dev/null +++ b/webnotes/plugins.py @@ -0,0 +1,110 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes + +def get_code_and_execute(module, doctype, docname, plugin=None, namespace=None): + code = get_code(module, doctype, docname, plugin) + return exec_code(code, namespace) + +def exec_code(code, namespace=None): + if namespace is None: namespace = {} + + if code: + exec code in namespace + + return namespace + +def get_code(module, doctype, docname, plugin=None): + import MySQLdb + + try: + code = read_file(module, doctype, docname, plugin, cache=True) + except MySQLdb.OperationalError: + # this happens when syncing + return None + + return code + +def get_cache_key(doctype, docname, extn="py"): + return "Plugin File:{doctype}:{docname}:{extn}".format(doctype=doctype, docname=docname, extn=extn) + +def get_plugin_name(doctype, docname): + import os + from webnotes.utils import get_site_base_path + plugin = None + + meta = webnotes.get_doctype(doctype) + if meta.get_field("plugin"): + plugin = webnotes.conn.get_value(doctype, docname, "plugin") + if not plugin: + plugin = os.path.basename(get_site_base_path()) + + return plugin + +def read_file(module, doctype, docname, plugin=None, extn="py", cache=False): + import os + content = None + + if cache: + content = webnotes.cache().get_value(get_cache_key(doctype, docname, extn)) + + if not content: + path = get_path(module, doctype, docname, plugin, extn) + if os.path.exists(path): + with open(path, 'r') as f: + content = f.read() or "Does Not Exist" + + if cache: + webnotes.cache().set_value(get_cache_key(doctype, docname, extn), content) + + return None if (content == "Does Not Exist") else content + +def get_path(module, doctype, docname, plugin=None, extn="py"): + from webnotes.modules import scrub + import os + + if not module: module = webnotes.conn.get_value(doctype, docname, "module") + if not plugin: plugin = get_plugin_name(doctype, docname) + + # site_abs_path/plugins/module/doctype/docname/docname.py + return os.path.join(get_plugin_path(scrub(plugin)), scrub(module), + scrub(doctype), scrub(docname), scrub(docname) + "." + extn) + +def get_plugin_path(plugin=None): + from webnotes.modules import scrub + from webnotes.utils import get_site_path + return get_site_path(webnotes.conf.get("plugins_path"), scrub(plugin)) + +def remove_init_files(): + import os + from webnotes.utils import get_site_path, cstr + for path, folders, files in os.walk(get_site_path(webnotes.conf.get("plugins_path"))): + for f in files: + # cstr(f) is required when filenames are non-ascii + if cstr(f) in ("__init__.py", "__init__.pyc"): + os.remove(os.path.join(path, f)) + +def clear_cache(doctype=None, docname=None): + import os + from webnotes.utils import get_site_path + + def titlecase(txt): + return txt.replace("_", " ").title() + + def clear_single(dt, dn): + dt = titlecase(dt) + dn = titlecase(dn) + webnotes.cache().delete_value(get_cache_key(dt, dn, "py")) + webnotes.cache().delete_value(get_cache_key(dt, dn, "js")) + + if not (doctype and docname): + for path, folders, files in os.walk(get_site_path(webnotes.conf.get("plugins_path"))): + if files: + dt = os.path.basename(os.path.dirname(path)) + dn = os.path.basename(path) + clear_single(dt, dn) + else: + clear_single(doctype, docname) + \ No newline at end of file diff --git a/webnotes/sessions.py b/webnotes/sessions.py index b3dfab409f..b4c671ab28 100644 --- a/webnotes/sessions.py +++ b/webnotes/sessions.py @@ -14,6 +14,7 @@ import json from webnotes.utils import cint import webnotes.model.doctype import webnotes.defaults +import webnotes.plugins @webnotes.whitelist() def clear(user=None): @@ -26,6 +27,9 @@ def clear_cache(user=None): # clear doctype cache webnotes.model.doctype.clear_cache() + + # clear plugins code cache + webnotes.plugins.clear_cache() if user: cache.delete_value("bootinfo:" + user) diff --git a/webnotes/widgets/query_report.py b/webnotes/widgets/query_report.py index 9d806f174a..f3668d258b 100644 --- a/webnotes/widgets/query_report.py +++ b/webnotes/widgets/query_report.py @@ -11,33 +11,50 @@ from webnotes import _ from webnotes.modules import scrub, get_module_path from webnotes.utils import flt, cint import webnotes.widgets.reportview +import webnotes.plugins @webnotes.whitelist() def get_script(report_name): report = webnotes.doc("Report", report_name) - doctype = webnotes.conn.get_value("DocType", report.ref_doctype, "module") - script_path = os.path.join(get_module_path(doctype), - "report", scrub(report.name), scrub(report.name) + ".js") + module = webnotes.conn.get_value("DocType", report.ref_doctype, "module") + module_path = get_module_path(module) + report_folder = os.path.join(module_path, "report", scrub(report.name)) + script_path = os.path.join(report_folder, scrub(report.name) + ".js") + script = None + if os.path.exists(script_path): + with open(script_path, "r") as script: + script = script.read() + + if not script and report.is_standard == "No": + script = webnotes.plugins.read_file(module, "Report", report.name, extn="js", cache=True) + + if not script and report.javascript: + script = report.javascript + + if not script: + script = "wn.query_reports['%s']={}" % report_name + # load translations if webnotes.lang != "en": from webnotes.translate import get_lang_data - locale_path = os.path.join(get_module_path(webnotes.conn.get_value(doctype)),"report", scrub(report.name)) - messages = get_lang_data(locale_path, - webnotes.lang, 'js') - webnotes.response["__messages"] = messages + if os.path.exists(report_folder): + messages = get_lang_data(report_folder, webnotes.lang, 'js') + webnotes.response["__messages"] = messages + else: + # TODO check if language files get exported here + plugins_report_folder = webnotes.plugins.get_path(module, "Report", report.name) + if os.path.exists(plugins_report_folder): + messages = get_lang_data(plugins_report_folder, webnotes.lang, 'js') + webnotes.response["__messages"] = messages - if os.path.exists(script_path): - with open(script_path, "r") as script: - return script.read() - elif report.javascript: - return report.javascript - else: - return "wn.query_reports['%s']={}" % report_name + return script @webnotes.whitelist() def run(report_name, filters=None): + from webnotes.plugins import get_code_and_execute + report = webnotes.doc("Report", report_name) if filters and isinstance(filters, basestring): @@ -58,9 +75,13 @@ def run(report_name, filters=None): result = [list(t) for t in webnotes.conn.sql(report.query, filters)] columns = [c[0] for c in webnotes.conn.get_description()] else: - method_name = scrub(webnotes.conn.get_value("DocType", report.ref_doctype, "module")) \ - + ".report." + scrub(report.name) + "." + scrub(report.name) + ".execute" - columns, result = webnotes.get_method(method_name)(filters or {}) + module = webnotes.conn.get_value("DocType", report.ref_doctype, "module") + if report.is_standard=="Yes": + method_name = scrub(module) + ".report." + scrub(report.name) + "." + scrub(report.name) + ".execute" + columns, result = webnotes.get_method(method_name)(filters or {}) + else: + namespace = get_code_and_execute(module, "Report", report.name) + columns, result = namespace["execute"](filters or {}) result = get_filtered_data(report.ref_doctype, columns, result) @@ -91,7 +112,7 @@ def get_filtered_data(ref_doctype, columns, data): linked_doctypes = get_linked_doctypes(columns) match_filters = get_user_match_filters(linked_doctypes, ref_doctype) - + if match_filters: matched_columns = get_matched_columns(linked_doctypes, match_filters) for row in data: diff --git a/wnf.py b/wnf.py index 76e898c85b..4a2f3fdca4 100755 --- a/wnf.py +++ b/wnf.py @@ -265,6 +265,7 @@ def update(remote=None, branch=None, site=None): def latest(site=None, verbose=True): import webnotes.modules.patch_handler import webnotes.model.sync + import webnotes.plugins webnotes.connect(site=site) @@ -277,6 +278,10 @@ def latest(site=None, verbose=True): # sync webnotes.model.sync.sync_all() + + # remove __init__.py from plugins + webnotes.plugins.remove_init_files() + except webnotes.modules.patch_handler.PatchError, e: print "\n".join(webnotes.local.patch_log_list) raise e