Reformatted code base using black.

This commit is contained in:
Goffi 2024-06-19 18:44:57 +02:00
commit 53fdaa9d09
2 changed files with 12604 additions and 8966 deletions

View file

@ -45,7 +45,7 @@ try:
import yaml
except ImportError:
raise exceptions.MissingModule(
'Missing module PyYAML, please download/install it. You can use '
"Missing module PyYAML, please download/install it. You can use "
'"pip install pyyaml"'
)
@ -59,8 +59,6 @@ except ImportError:
from yaml import Loader, Dumper
PLUGIN_INFO = {
C.PI_NAME: "Applications Manager",
C.PI_IMPORT_NAME: "APP_MANAGER",
@ -73,7 +71,8 @@ PLUGIN_INFO = {
Manage external applications using packagers, OS virtualization/containers or other
software management tools.
"""),
"""
),
}
APP_FILE_PREFIX = "libervia_app_"
@ -92,7 +91,6 @@ class AppManager:
# instance id to app data map
self._instances = {}
self.persistent_data = persistent.LazyPersistentBinaryDict("app_manager")
host.bridge.add_method(
@ -128,30 +126,28 @@ class AppManager:
)
# application has been started succeesfully,
# args: name, instance_id, extra
host.bridge.add_signal(
"application_started", ".plugin", signature="sss"
)
host.bridge.add_signal("application_started", ".plugin", signature="sss")
# application went wrong with the application
# args: name, instance_id, extra
host.bridge.add_signal(
"application_error", ".plugin", signature="sss"
host.bridge.add_signal("application_error", ".plugin", signature="sss")
yaml.add_constructor("!libervia_conf", self._libervia_conf_constr, Loader=Loader)
yaml.add_constructor(
"!libervia_generate_pwd", self._libervia_generate_pwd_constr, Loader=Loader
)
yaml.add_constructor(
"!libervia_conf", self._libervia_conf_constr, Loader=Loader)
yaml.add_constructor(
"!libervia_generate_pwd", self._libervia_generate_pwd_constr, Loader=Loader)
yaml.add_constructor(
"!libervia_param", self._libervia_param_constr, Loader=Loader)
"!libervia_param", self._libervia_param_constr, Loader=Loader
)
def unload(self):
log.debug("unloading applications manager")
for instances in self._started.values():
for instance in instances:
data = instance['data']
if not data['single_instance']:
data = instance["data"]
if not data["single_instance"]:
log.debug(
f"cleaning temporary directory at {data['_instance_dir_path']}")
data['_instance_dir_obj'].cleanup()
f"cleaning temporary directory at {data['_instance_dir_path']}"
)
data["_instance_dir_obj"].cleanup()
def _libervia_conf_constr(self, loader, node) -> str:
"""Get a value from Libervia configuration
@ -183,22 +179,27 @@ class AppManager:
value = self.host.memory.config_get(section, name, default)
# FIXME: "public_url" is used only here and doesn't take multi-sites into account
if name == "public_url" and (not value or value.startswith('http')):
if name == "public_url" and (not value or value.startswith("http")):
if not value:
log.warning(_(
'No value found for "public_url", using "example.org" for '
'now, please set the proper value in libervia.conf'))
log.warning(
_(
'No value found for "public_url", using "example.org" for '
"now, please set the proper value in libervia.conf"
)
)
else:
log.warning(_(
'invalid value for "public_url" ({value}), it musts not start with '
'schema ("http"), ignoring it and using "example.org" '
'instead')
.format(value=value))
log.warning(
_(
'invalid value for "public_url" ({value}), it musts not start with '
'schema ("http"), ignoring it and using "example.org" '
"instead"
).format(value=value)
)
value = "example.org"
if filter_ is None:
pass
elif filter_ == 'first':
elif filter_ == "first":
value = value[0]
elif filter_ == "not":
value = C.bool(value)
@ -232,7 +233,7 @@ class AppManager:
except KeyError:
alphabet = string.ascii_letters + string.digits
key_size = int(kwargs.get("size", 30))
key = ''.join(secrets.choice(alphabet) for __ in range(key_size))
key = "".join(secrets.choice(alphabet) for __ in range(key_size))
self._app_persistent_data[pwd_data_key] = key
else:
log.debug(f"Re-using existing key for {name!r} password.")
@ -255,7 +256,8 @@ class AppManager:
name = manager.name
if name in self._managers:
raise exceptions.ConflictError(
f"There is already a manager with the name {name}")
f"There is already a manager with the name {name}"
)
self._managers[manager.name] = manager
if manager.discover_path is not None:
self.discover(manager.discover_path, manager)
@ -269,25 +271,18 @@ class AppManager:
try:
app_type = app_data["type"]
except KeyError:
raise exceptions.DataError(
"app file doesn't have the mandatory \"type\" key"
)
raise exceptions.DataError('app file doesn\'t have the mandatory "type" key')
if not isinstance(app_type, str):
raise exceptions.DataError(
f"invalid app data type: {app_type!r}"
)
raise exceptions.DataError(f"invalid app data type: {app_type!r}")
app_type = app_type.strip()
try:
return self._managers[app_type]
except KeyError:
raise exceptions.NotFound(
f"No manager found to manage app of type {app_type!r}")
f"No manager found to manage app of type {app_type!r}"
)
def get_app_data(
self,
id_type: Optional[str],
identifier: str
) -> dict:
def get_app_data(self, id_type: Optional[str], identifier: str) -> dict:
"""Retrieve instance's app_data from identifier
@param id_type: type of the identifier, can be:
@ -300,8 +295,8 @@ class AppManager:
@raise ValueError: id_type is invalid
"""
if not id_type:
id_type = 'name'
if id_type == 'name':
id_type = "name"
if id_type == "name":
identifier = identifier.lower().strip()
try:
return next(iter(self._started[identifier]))
@ -309,7 +304,7 @@ class AppManager:
raise exceptions.NotFound(
f"No instance of {identifier!r} is currently running"
)
elif id_type == 'instance':
elif id_type == "instance":
instance_id = identifier
try:
return self._instances[instance_id]
@ -320,11 +315,7 @@ class AppManager:
else:
raise ValueError(f"invalid id_type: {id_type!r}")
def discover(
self,
dir_path: Path,
manager: AppManagerBackend|None = None
) -> None:
def discover(self, dir_path: Path, manager: AppManagerBackend | None = None) -> None:
"""Search for app configuration file.
App configuration files must start with [APP_FILE_PREFIX] and have a ``.yaml``
@ -336,19 +327,16 @@ class AppManager:
app_data = self.parse(file_path)
manager = self.get_manager(app_data)
except (exceptions.DataError, exceptions.NotFound) as e:
log.warning(
f"Can't parse {file_path}, skipping: {e}")
log.warning(f"Can't parse {file_path}, skipping: {e}")
continue
app_name = file_path.stem[len(APP_FILE_PREFIX):].strip().lower()
app_name = file_path.stem[len(APP_FILE_PREFIX) :].strip().lower()
if not app_name:
log.warning(f"invalid app file name at {file_path}")
continue
app_dict = self._apps.setdefault(app_name, {})
manager_set = app_dict.setdefault(manager, set())
manager_set.add(file_path)
log.debug(
f"{app_name!r} {manager.name} application found"
)
log.debug(f"{app_name!r} {manager.name} application found")
def parse(self, file_path: Path, params: Optional[dict] = None) -> dict:
"""Parse Libervia application file
@ -367,7 +355,7 @@ class AppManager:
if "name" not in app_data:
# note that we don't use lower() here as we want human readable name and
# uppercase may be set on purpose
app_data['name'] = file_path.stem[len(APP_FILE_PREFIX):].strip()
app_data["name"] = file_path.stem[len(APP_FILE_PREFIX) :].strip()
single_instance = app_data.setdefault("single_instance", True)
if not isinstance(single_instance, bool):
raise ValueError(
@ -429,9 +417,7 @@ class AppManager:
try:
app_file_path = next(iter(next(iter(self._apps[app_name].values()))))
except KeyError:
raise exceptions.NotFound(
f"No application found with the name {app_name!r}"
)
raise exceptions.NotFound(f"No application found with the name {app_name!r}")
log.info(f"starting {app_name!r}")
self._app_persistent_data = await self.persistent_data.get(app_name) or {}
self._app_persistent_data["last_started"] = time.time()
@ -439,13 +425,10 @@ class AppManager:
app_data = self.parse(app_file_path, extra)
await self.persistent_data.aset(app_name, self._app_persistent_data)
app_data["_started"] = False
app_data['_file_path'] = app_file_path
app_data['_name_canonical'] = app_name
single_instance = app_data['single_instance']
ret_data = {
"name": app_name,
"started": False
}
app_data["_file_path"] = app_file_path
app_data["_name_canonical"] = app_name
single_instance = app_data["single_instance"]
ret_data = {"name": app_name, "started": False}
if single_instance:
if started_data:
instance_data = started_data[0]
@ -462,14 +445,14 @@ class AppManager:
PLUGIN_INFO[C.PI_IMPORT_NAME], app_name
)
cache_path.mkdir(0o700, parents=True, exist_ok=True)
app_data['_instance_dir_path'] = cache_path
app_data["_instance_dir_path"] = cache_path
else:
dest_dir_obj = tempfile.TemporaryDirectory(prefix="libervia_app_")
app_data['_instance_dir_obj'] = dest_dir_obj
app_data['_instance_dir_path'] = Path(dest_dir_obj.name)
instance_id = ret_data["instance"] = app_data['_instance_id'] = shortuuid.uuid()
app_data["_instance_dir_obj"] = dest_dir_obj
app_data["_instance_dir_path"] = Path(dest_dir_obj.name)
instance_id = ret_data["instance"] = app_data["_instance_id"] = shortuuid.uuid()
manager = self.get_manager(app_data)
app_data['_manager'] = manager
app_data["_manager"] = manager
started_data.append(app_data)
self._instances[instance_id] = app_data
# we retrieve exposed data such as url_prefix which can be useful computed exposed
@ -482,7 +465,7 @@ class AppManager:
start = manager.start
except AttributeError:
raise exceptions.InternalError(
f"{manager.name} doesn't have the mandatory \"start\" method"
f'{manager.name} doesn\'t have the mandatory "start" method'
)
else:
defer.ensureDeferred(self.start_app(start, app_data))
@ -498,12 +481,8 @@ class AppManager:
self.host.bridge.application_error(
app_name,
instance_id,
data_format.serialise(
{
"class": str(type(e)),
"msg": str(e)
}
))
data_format.serialise({"class": str(type(e)), "msg": str(e)}),
)
else:
app_data["_started"] = True
self.host.bridge.application_started(app_name, instance_id, "")
@ -512,7 +491,8 @@ class AppManager:
def _stop(self, identifier, id_type, extra):
extra = data_format.deserialise(extra)
return defer.ensureDeferred(
self.stop(str(identifier), str(id_type) or None, extra))
self.stop(str(identifier), str(id_type) or None, extra)
)
async def stop(
self,
@ -527,15 +507,15 @@ class AppManager:
log.info(f"stopping {app_data['name']!r}")
app_name = app_data['_name_canonical']
instance_id = app_data['_instance_id']
manager = app_data['_manager']
app_name = app_data["_name_canonical"]
instance_id = app_data["_instance_id"]
manager = app_data["_manager"]
try:
stop = manager.stop
except AttributeError:
raise exceptions.InternalError(
f"{manager.name} doesn't have the mandatory \"stop\" method"
f'{manager.name} doesn\'t have the mandatory "stop" method'
)
else:
try:
@ -551,7 +531,8 @@ class AppManager:
del self._instances[instance_id]
except KeyError:
log.error(
f"INTERNAL ERROR: {instance_id!r} is not present in self._instances")
f"INTERNAL ERROR: {instance_id!r} is not present in self._instances"
)
try:
self._started[app_name].remove(app_data)
@ -590,13 +571,13 @@ class AppManager:
to handle manager specific conventions.
"""
app_data = self.get_app_data(id_type, identifier)
if app_data.get('_exposed_computed', False):
return app_data['expose']
if app_data.get("_exposed_computed", False):
return app_data["expose"]
if extra is None:
extra = {}
expose = app_data.setdefault("expose", {})
if "passwords" in expose:
passwords = expose['passwords']
passwords = expose["passwords"]
for name, value in list(passwords.items()):
if isinstance(value, list):
# if we have a list, is the sequence of keys leading to the value
@ -605,7 +586,8 @@ class AppManager:
passwords[name] = self.get_app_data_value(value, app_data)
except KeyError:
log.warning(
f"Can't retrieve exposed value for password {name!r}: {e}")
f"Can't retrieve exposed value for password {name!r}: {e}"
)
del passwords[name]
for key in ("url_prefix", "front_url"):
@ -614,9 +596,7 @@ class AppManager:
try:
expose[key] = self.get_app_data_value(value, app_data)
except KeyError:
log.warning(
f"Can't retrieve exposed value for {key!r} at {value}"
)
log.warning(f"Can't retrieve exposed value for {key!r} at {value}")
del expose[key]
front_url = expose.get("front_url")
@ -628,35 +608,35 @@ class AppManager:
path_elt = parsed_url.path.split("/", 1)
parsed_url = parsed_url._replace(
netloc=path_elt[0],
path=f"/{path_elt[1]}" if len(path_elt) > 1 else ""
path=f"/{path_elt[1]}" if len(path_elt) > 1 else "",
)
parsed_url = parsed_url._replace(scheme='https')
parsed_url = parsed_url._replace(scheme="https")
expose["front_url"] = urlunparse(parsed_url)
if extra.get("skip_compute", False):
return expose
try:
compute_expose = app_data['_manager'].compute_expose
compute_expose = app_data["_manager"].compute_expose
except AttributeError:
pass
else:
await compute_expose(app_data)
app_data['_exposed_computed'] = True
app_data["_exposed_computed"] = True
return expose
async def _do_prepare(
self,
app_data: dict,
) -> None:
name = app_data['name']
dest_path = app_data['_instance_dir_path']
name = app_data["name"]
dest_path = app_data["_instance_dir_path"]
if next(dest_path.iterdir(), None) != None:
log.debug(f"There is already a prepared dir at {dest_path}, nothing to do")
return
try:
prepare = app_data['prepare'].copy()
prepare = app_data["prepare"].copy()
except KeyError:
prepare = {}
@ -668,7 +648,7 @@ class AppManager:
log.debug(f"[{name}] [prepare] running {action!r} action")
if action == "git":
try:
git_path = which('git')[0]
git_path = which("git")[0]
except IndexError:
raise exceptions.NotFound(
"Can't find \"git\" executable, {name} can't be started without it"
@ -688,8 +668,8 @@ class AppManager:
self,
app_data: dict,
) -> None:
dest_path = app_data['_instance_dir_path']
files = app_data.get('files')
dest_path = app_data["_instance_dir_path"]
files = app_data.get("files")
if not files:
return
if not isinstance(files, dict):

View file

@ -27,7 +27,7 @@ class AppManagerBackend(abc.ABC):
"""Abstract class for App Manager."""
name: str
discover_path: Path|None = None
discover_path: Path | None = None
def __init__(self, host) -> None:
"""Initialize the App Manager.