MemWeb/Python/Application/MemWeb.Terminal.py

394 lines
16 KiB
Python
Raw Normal View History

#!/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 |= (
2024-05-04 09:13:39 +00:00
(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"]