#!/usr/bin/env python # -*- coding: utf-8 -*- from re import compile as RECompile from json import loads as json_decode if "MemWeb" not in globals(): class MemWeb:pass class Anonymous(MemWeb.Abstracts.Common): re_key = RECompile(r'^[a-z0-9_]+$') re_command = RECompile(r'^([^ ]+)(.+)?$') re_parameters = RECompile(r' +(\-{1,2})?("(([^\\"]+|\\")*)"|\'(([^\\\']+|\\\')*)\'|([^= ]+))( *=( *("(([^\\"]+|\\")*)"|\'(([^\\\']+|\\\')*)\'|([^ ]+)))?)?') def __set_basic_data(self): self.__default_overwrite = self.settings(("commands_overwrite", "overwrite")) self.__show_add_ok = self.settings(("terminal_show_add_ok_message", "show_ok_message")) self.__show_add_error = self.settings(("terminal_show_add_error_message", "show_error_message")) self.__show_add_exception = self.settings(("terminal_show_add_exception_message", "show_exception_message")) def __init__(self, mem_web, inputs = None): super().__init__(mem_web, "terminal") self._print("info", "mem_web_terminal_building") self.__commands = [] self.__thread = None self.__set_basic_data() self._print("ok", "mem_web_terminal_built") def _start(self, end): if self.__started:return self.__set_basic_data() for key in ("default_commands_files", "commands_files", "commands"): self.add(self.settings(key), True) help_command = self.get_command("help") if help_command: help_command["synonyms"] += ["?"] (self.__thread, error) = self.mem_web.threads.add(self.__execute, { "bucle" : True, "start_now" : True, "key" : "terminal" }) end(0) def _close(self, end): if not self.__started:return self.mem_web.threads.remove(self.__thread) end(0) def __execute(self, thread): (key, inputs) = self.re_command.match(input()).groups() for command in self.__commands: if key in command["synonyms"]: parameters = [] attributes = {} special = [] if inputs: def callback(matches): _type = len(matches.group(1) or "") base = matches.group(3) or matches.group(5) or matches.group(7) value = matches.group(11) or matches.group(13) or matches.group(15) if _type: special.append((_type, base, value)) if value != None: attributes[base] = value else: parameters.append(base) self.re_parameters.sub(callback, inputs) if len(special): for _type, name, parameter in special: ok = False for subcommand in self.__commands: if subcommand["special"] and name in subcommand["synonyms"]: subcommand["special"](key, command, _type, name, parameter) ok = True break not ok and self._print("warn", "mem_web_terminal_special_unknown", { "type" : _type, "name" : name, "parameter" : parameter, "key" : key, "real_key" : command["synonyms"][0] }) else: command["method"](parameters, attributes) return self._print("warn", "mem_web_terminal_command_unknown", { "key" : key }) def key_exists(self, key): key = key.lower() for i, command in enumerate(self.__commands): if key in command["synonyms"]: return i return None def __get_method(self, data, key): if key not in data: return None method = globals() if "root" in data: method = data["root"] elif data[key][0] == "mem_web": method = self.mem_web data[key] = data[key][1:] for i, key in enumerate(data[key]): try: if not i and isinstance(method, dict): if key in method: method = method[key] continue elif hasattr(method, key): method = getattr(method, key) continue except: pass method = None break return method def add(self, inputs, overwrite = None, show_errors = None): if isinstance(inputs, (list, tuple)): for subset in inputs: self.add(subset, overwrite, show_errors) elif isinstance(inputs, dict): has_show_errors = isinstance(show_errors, bool) if not isinstance(overwrite, bool): overwrite = self.__default_overwrite for key, data in inputs.items(): error = ( (( 1 << 0 if key == None else 1 << 1 if not isinstance(key, str) else 1 << 2 if not key else 0) << 0) | (( 1 << 0 if data == None else 1 << 1 if not isinstance(data, dict) else ( (( 0 if "synonyms" not in data else 1 << 1 if data["synonyms"] == None else 1 << 2 if not isinstance(data["synonyms"], (str, list, tuple)) else 0) << 0) | (( 1 << 0 if "method" not in data else 1 << 1 if data["method"] == None else 1 << 2 if not isinstance(data["method"], (str, list, tuple)) else 0) << 3) | (( 0 if "root" not in data else 1 << 1 if data["root"] == None else 1 << 2 if MemWeb.is_object(data["root"]) or MemWeb.is_class(data["root"]) else 0) << 6) | (( 0 if "parameters" not in data else 1 << 1 if data["parameters"] == None else 1 << 2 if not isinstance(data["parameters"], (str, list, tuple)) else 0) << 9) | (( 0 if "special" not in data else 1 << 1 if data["special"] == None else 1 << 2 if not isinstance(data["special"], (str, list, tuple)) else 0) << 12) | 0) << 2) << 3) | 0) << 1 if not error: key_i = self.key_exists(key) if "synonyms" not in data: data["synonyms"] = [] elif isinstance(data["synonyms"], str): data["synonyms"] = (data["synonyms"],) elif isinstance(data["synonyms"], tuple): data["synonyms"] = list(data["synonyms"]) data["synonyms"] = [subkey.lower() for subkey in [key] + data["synonyms"]] for subkey in ("method", "special"): if subkey in data and isinstance(data[subkey], str): data[subkey] = data[subkey].split(".") data["parameters"] = [subkey.lower() for subkey in ( tuple() if "parameters" not in data else (data["parameters"],) if isinstance(data["parameters"], str) else data["parameters"])] if not overwrite and key_i != None: error |= 1 << 21 for i, subkey in enumerate(("synonyms", "method", "special", "parameters")): if subkey in data: error |= (MemWeb.reduce([( 1 << 0 if key == None else 1 << 1 if not isinstance(key, str) else 1 << 2 if not key else 1 << 3 if not self.re_key.match(key) else 0) for key in data[subkey]], lambda a, b, *_: a | b, 0)[0]) << (22 + i * 4) if not error: for i, subkey in enumerate(("method", "special")): if subkey in data: processed_key = subkey + "_processed" data[processed_key] = self.__get_method(data, subkey) error |= ( (0 if i else 1 << 0) if data[processed_key] == None else 1 << 1 if not callable(data[processed_key]) else 0) << (38 + i * 2) if not error: if key_i == None: key_i = len(self.__commands) self.__commands.append(None) self.__commands[key_i] = { "i" : key_i, "method" : data["method_processed"], "raw_method" : data["method"], "synonyms" : data["synonyms"], "parameters" : data["parameters"], "special" : data["special_processed"] if "special" in data else None } self.validate( error, ( "exception", "key_null", "key_not_string", "key_empty", "data_null", "data_not_dictionary", "synonyms_not_data", "synonyms_null", "synonyms_bad_type", "method_not_data", "method_null", "method_bad_type", "root_not_data", "root_null", "root_not_object_class", "parameters_not_data", "parameters_null", "parameters_bad_type", "special_not_data", "special_null", "special_bad_type", "command_key_exists", "some_synonym_null", "some_synonym_not_string", "some_synonym_empty", "some_synonym_bad_characters", "some_method_key_null", "some_method_key_not_string", "some_method_key_empty", "some_method_key_bad_characters", "some_special_key_null", "some_special_key_not_string", "some_special_key_empty", "some_special_key_bad_characters", "some_parameter_key_null", "some_parameter_key_not_string", "some_parameter_key_empty", "some_parameter_key_bad_characters", "method_null", "method_not_function", "special_null", "special_not_function" ), { "key" : key, "action" : data["method"] if "method" in data else None }, (show_errors if has_show_errors else self.__show_add_error) and "mem_web_terminal_add_error", (show_errors if has_show_errors else True) and self.__show_add_ok and "mem_web_terminal_add_ok" ) elif isinstance(inputs, str): if MemWeb.re_json.match(inputs.strip()): try: self.add(json_decode(inputs), overwrite, show_errors) except Exception as exception: self.exception(exception, self.__show_add_exception and "mem_web_terminal_add_exception") else: json = self.mem_web.load_file(inputs)[0] if json and MemWeb.re_json.match(json.strip()): try: self.add(json_decode(json), overwrite, show_errors) except Exception as exception: self.exception(exception, self.__show_add_exception and "mem_web_terminal_add_exception") def _echo(self, parameters, attributes): print(" ".join(parameters)) def _close_application(self, *_): self.mem_web.close() def get_command(self, keys): keys = MemWeb.get_keys(keys) if len(keys): for command in self.__commands: for key in keys: if key in command["synonyms"]: return command return None def _help(self, *_): self._print("help", "mem_web_terminal_help", { "commands" : "".join(["\n - " + command["synonyms"][0] + ( " (" + ", ".join(command["synonyms"][1:]) + ")" if len(command["synonyms"]) > 1 else "" ) for command in self.__commands]) + "\n", "help_key" : (self.get_command("help") or {"synonyms" : [None]})["synonyms"][0] }) def _help_special(self, key, command, _type, name, parameter): if parameter: if parameter in command["parameters"]: self._print("help", ( "mem_web_help_" + command["synonyms"][0] + "_" + parameter, "mem_web_help_" + command["synonyms"][0] + "_parameter", "help_" + command["synonyms"][0] + "_" + parameter, "help_" + command["synonyms"][0] + "_parameter" ), { "special_type" : _type, "real_key" : command["synonyms"][0], "key" : key, "synonyms" : ", ".join(command["synonyms"][1:]), "parameter" : parameter }) else: self._print("warn", "mem_web_terminal_command_unknown_parameter", { "special_type" : _type, "real_key" : command["synonyms"][0], "key" : key, "synonyms" : ", ".join(command["synonyms"][1:]), "parameter" : parameter, "parameters" : "".join(["\n - " + subkey for subkey in command["parameters"]]) + "\n" }) else: self._print("help", ( "mem_web_help_" + command["synonyms"][0], "help_" + command["synonyms"][0] ), { "special_type" : _type, "real_key" : command["synonyms"][0], "key" : key, "synonyms" : ", ".join(command["synonyms"][1:]), "parameters" : "".join(["\n - " + subkey for subkey in command["parameters"]]) + "\n" }) MemWeb.Terminal = Anonymous del globals()["Anonymous"]