update_manager: refactor AppDeloy class
Don't require the `app_params` argument, instead dynamically generate the configuration from a dict. This simiplifies AppDeploy initialization as the internally generated configurations can be read in the same way as those supplied in moonraker.conf. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
54081612ca
commit
e9e86c3042
|
@ -8,7 +8,6 @@ from __future__ import annotations
|
||||||
import pathlib
|
import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
from .base_deploy import BaseDeploy
|
from .base_deploy import BaseDeploy
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
CHANNEL_TO_TYPE = {
|
CHANNEL_TO_TYPE = {
|
||||||
"stable": "zip",
|
"stable": "zip",
|
||||||
"beta": "zip_beta",
|
"beta": "git_repo",
|
||||||
"dev": "git_repo"
|
"dev": "git_repo"
|
||||||
}
|
}
|
||||||
TYPE_TO_CHANNEL = {
|
TYPE_TO_CHANNEL = {
|
||||||
|
@ -38,29 +37,17 @@ TYPE_TO_CHANNEL = {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppDeploy(BaseDeploy):
|
class AppDeploy(BaseDeploy):
|
||||||
def __init__(self,
|
def __init__(self, config: ConfigHelper, cmd_helper: CommandHelper) -> None:
|
||||||
config: ConfigHelper,
|
super().__init__(config, cmd_helper, prefix="Application")
|
||||||
cmd_helper: CommandHelper,
|
|
||||||
app_params: Optional[Dict[str, Any]]
|
|
||||||
) -> None:
|
|
||||||
self.config = config
|
self.config = config
|
||||||
self.app_params = app_params
|
|
||||||
cfg_hash = self._calc_config_hash()
|
|
||||||
super().__init__(config, cmd_helper, prefix="Application",
|
|
||||||
cfg_hash=cfg_hash)
|
|
||||||
self.debug = self.cmd_helper.is_debug_enabled()
|
self.debug = self.cmd_helper.is_debug_enabled()
|
||||||
if app_params is not None:
|
self.type = config.get('type')
|
||||||
self.channel: str = app_params['channel']
|
self.channel = config.get(
|
||||||
self.path: pathlib.Path = pathlib.Path(
|
"channel", TYPE_TO_CHANNEL[self.type]
|
||||||
app_params['path']).expanduser().resolve()
|
)
|
||||||
executable: Optional[str] = app_params['executable']
|
self.path = pathlib.Path(
|
||||||
self.type = CHANNEL_TO_TYPE[self.channel]
|
config.get('path')).expanduser().resolve()
|
||||||
else:
|
executable = config.get('env', None)
|
||||||
self.type = config.get('type')
|
|
||||||
self.channel = TYPE_TO_CHANNEL[self.type]
|
|
||||||
self.path = pathlib.Path(
|
|
||||||
config.get('path')).expanduser().resolve()
|
|
||||||
executable = config.get('env', None)
|
|
||||||
if self.channel not in CHANNEL_TO_TYPE.keys():
|
if self.channel not in CHANNEL_TO_TYPE.keys():
|
||||||
raise config.error(
|
raise config.error(
|
||||||
f"Invalid Channel '{self.channel}' for config "
|
f"Invalid Channel '{self.channel}' for config "
|
||||||
|
@ -136,15 +123,6 @@ class AppDeploy(BaseDeploy):
|
||||||
self._is_valid = storage.get('is_valid', False)
|
self._is_valid = storage.get('is_valid', False)
|
||||||
return storage
|
return storage
|
||||||
|
|
||||||
def _calc_config_hash(self) -> str:
|
|
||||||
cfg_hash = self.config.get_hash()
|
|
||||||
if self.app_params is None:
|
|
||||||
return cfg_hash.hexdigest()
|
|
||||||
else:
|
|
||||||
app_bytes = json.dumps(self.app_params).encode()
|
|
||||||
cfg_hash.update(app_bytes)
|
|
||||||
return cfg_hash.hexdigest()
|
|
||||||
|
|
||||||
def _verify_path(self,
|
def _verify_path(self,
|
||||||
config: ConfigHelper,
|
config: ConfigHelper,
|
||||||
option: str,
|
option: str,
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Moonraker/Klipper update configuration
|
||||||
|
#
|
||||||
|
# Copyright (C) 2022 Eric Callahan <arksine.code@gmail.com>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import copy
|
||||||
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Dict
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from confighelper import ConfigHelper
|
||||||
|
from components.database import MoonrakerDatabase
|
||||||
|
|
||||||
|
MOONRAKER_PATH = os.path.normpath(os.path.join(
|
||||||
|
os.path.dirname(__file__), "../../.."))
|
||||||
|
KLIPPER_DEFAULT_PATH = os.path.expanduser("~/klipper")
|
||||||
|
KLIPPER_DEFAULT_EXEC = os.path.expanduser("~/klippy-env/bin/python")
|
||||||
|
|
||||||
|
BASE_CONFIG: Dict[str, Dict[str, str]] = {
|
||||||
|
"moonraker": {
|
||||||
|
"origin": "https://github.com/arksine/moonraker.git",
|
||||||
|
"requirements": "scripts/moonraker-requirements.txt",
|
||||||
|
"venv_args": "-p python3",
|
||||||
|
"install_script": "scripts/install-moonraker.sh",
|
||||||
|
"host_repo": "arksine/moonraker",
|
||||||
|
"env": sys.executable,
|
||||||
|
"path": MOONRAKER_PATH,
|
||||||
|
"managed_services": "moonraker"
|
||||||
|
},
|
||||||
|
"klipper": {
|
||||||
|
"moved_origin": "https://github.com/kevinoconnor/klipper.git",
|
||||||
|
"origin": "https://github.com/Klipper3d/klipper.git",
|
||||||
|
"requirements": "scripts/klippy-requirements.txt",
|
||||||
|
"venv_args": "-p python2",
|
||||||
|
"install_script": "scripts/install-octopi.sh",
|
||||||
|
"host_repo": "arksine/moonraker",
|
||||||
|
"managed_services": "klipper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_base_configuration(config: ConfigHelper, channel: str) -> ConfigHelper:
|
||||||
|
server = config.get_server()
|
||||||
|
base_cfg = copy.deepcopy(BASE_CONFIG)
|
||||||
|
app_type = "zip" if channel == "stable" else "git_repo"
|
||||||
|
base_cfg["moonraker"]["channel"] = channel
|
||||||
|
base_cfg["moonraker"]["type"] = app_type
|
||||||
|
base_cfg["klipper"]["channel"] = channel
|
||||||
|
base_cfg["klipper"]["type"] = app_type
|
||||||
|
db: MoonrakerDatabase = server.lookup_component('database')
|
||||||
|
base_cfg["klipper"]["path"] = db.get_item(
|
||||||
|
"moonraker", "update_manager.klipper_path", KLIPPER_DEFAULT_PATH
|
||||||
|
).result()
|
||||||
|
base_cfg["klipper"]["env"] = db.get_item(
|
||||||
|
"moonraker", "update_manager.klipper_exec", KLIPPER_DEFAULT_EXEC
|
||||||
|
).result()
|
||||||
|
return config.read_supplemental_dict(base_cfg)
|
|
@ -28,12 +28,8 @@ if TYPE_CHECKING:
|
||||||
from .update_manager import CommandHelper
|
from .update_manager import CommandHelper
|
||||||
|
|
||||||
class GitDeploy(AppDeploy):
|
class GitDeploy(AppDeploy):
|
||||||
def __init__(self,
|
def __init__(self, config: ConfigHelper, cmd_helper: CommandHelper) -> None:
|
||||||
config: ConfigHelper,
|
super().__init__(config, cmd_helper)
|
||||||
cmd_helper: CommandHelper,
|
|
||||||
app_params: Optional[Dict[str, Any]] = None
|
|
||||||
) -> None:
|
|
||||||
super().__init__(config, cmd_helper, app_params)
|
|
||||||
self.repo = GitRepo(cmd_helper, self.path, self.name,
|
self.repo = GitRepo(cmd_helper, self.path, self.name,
|
||||||
self.origin, self.moved_origin)
|
self.origin, self.moved_origin)
|
||||||
if self.type != 'git_repo':
|
if self.type != 'git_repo':
|
||||||
|
@ -41,7 +37,7 @@ class GitDeploy(AppDeploy):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def from_application(app: AppDeploy) -> GitDeploy:
|
async def from_application(app: AppDeploy) -> GitDeploy:
|
||||||
new_app = GitDeploy(app.config, app.cmd_helper, app.app_params)
|
new_app = GitDeploy(app.config, app.cmd_helper)
|
||||||
await new_app.reinstall()
|
await new_app.reinstall()
|
||||||
return new_app
|
return new_app
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
# Supplemental configuration for Moonraker's Update Manager
|
|
||||||
# component. This file should not be modified.
|
|
||||||
|
|
||||||
[update_manager moonraker]
|
|
||||||
origin: https://github.com/arksine/moonraker.git
|
|
||||||
requirements: scripts/moonraker-requirements.txt
|
|
||||||
venv_args: -p python3
|
|
||||||
install_script: scripts/install-moonraker.sh
|
|
||||||
host_repo: arksine/moonraker
|
|
||||||
|
|
||||||
[update_manager klipper]
|
|
||||||
moved_origin: https://github.com/kevinoconnor/klipper.git
|
|
||||||
origin: https://github.com/Klipper3d/klipper.git
|
|
||||||
requirements: scripts/klippy-requirements.txt
|
|
||||||
venv_args: -p python2
|
|
||||||
install_script: scripts/install-octopi.sh
|
|
||||||
host_repo: arksine/moonraker
|
|
|
@ -9,13 +9,13 @@ import asyncio
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import logging
|
import logging
|
||||||
import sys
|
|
||||||
import shutil
|
import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
import time
|
import time
|
||||||
import tempfile
|
import tempfile
|
||||||
import re
|
import re
|
||||||
from thirdparty.packagekit import enums as PkEnum
|
from thirdparty.packagekit import enums as PkEnum
|
||||||
|
from . import base_config
|
||||||
from .base_deploy import BaseDeploy
|
from .base_deploy import BaseDeploy
|
||||||
from .app_deploy import AppDeploy
|
from .app_deploy import AppDeploy
|
||||||
from .git_deploy import GitDeploy
|
from .git_deploy import GitDeploy
|
||||||
|
@ -51,13 +51,6 @@ if TYPE_CHECKING:
|
||||||
from dbus_next.aio import ProxyInterface
|
from dbus_next.aio import ProxyInterface
|
||||||
JsonType = Union[List[Any], Dict[str, Any]]
|
JsonType = Union[List[Any], Dict[str, Any]]
|
||||||
|
|
||||||
MOONRAKER_PATH = os.path.normpath(os.path.join(
|
|
||||||
os.path.dirname(__file__), "../../.."))
|
|
||||||
SUPPLEMENTAL_CFG_PATH = os.path.join(
|
|
||||||
os.path.dirname(__file__), "update_manager.conf")
|
|
||||||
KLIPPER_DEFAULT_PATH = os.path.expanduser("~/klipper")
|
|
||||||
KLIPPER_DEFAULT_EXEC = os.path.expanduser("~/klippy-env/bin/python")
|
|
||||||
|
|
||||||
# Check To see if Updates are necessary each hour
|
# Check To see if Updates are necessary each hour
|
||||||
UPDATE_REFRESH_INTERVAL = 3600.
|
UPDATE_REFRESH_INTERVAL = 3600.
|
||||||
# Perform auto refresh no later than 4am
|
# Perform auto refresh no later than 4am
|
||||||
|
@ -73,46 +66,30 @@ class UpdateManager:
|
||||||
def __init__(self, config: ConfigHelper) -> None:
|
def __init__(self, config: ConfigHelper) -> None:
|
||||||
self.server = config.get_server()
|
self.server = config.get_server()
|
||||||
self.event_loop = self.server.get_event_loop()
|
self.event_loop = self.server.get_event_loop()
|
||||||
self.app_config = config.read_supplemental_config(
|
|
||||||
SUPPLEMENTAL_CFG_PATH)
|
|
||||||
auto_refresh_enabled = config.getboolean('enable_auto_refresh', False)
|
|
||||||
self.channel = config.get('channel', "dev")
|
self.channel = config.get('channel', "dev")
|
||||||
if self.channel not in ["dev", "beta"]:
|
if self.channel not in ["dev", "beta"]:
|
||||||
raise config.error(
|
raise config.error(
|
||||||
f"Unsupported channel '{self.channel}' in section"
|
f"Unsupported channel '{self.channel}' in section"
|
||||||
" [update_manager]")
|
" [update_manager]")
|
||||||
|
self.app_config = base_config.get_base_configuration(
|
||||||
|
config, self.channel
|
||||||
|
)
|
||||||
|
auto_refresh_enabled = config.getboolean('enable_auto_refresh', False)
|
||||||
self.cmd_helper = CommandHelper(config)
|
self.cmd_helper = CommandHelper(config)
|
||||||
self.updaters: Dict[str, BaseDeploy] = {}
|
self.updaters: Dict[str, BaseDeploy] = {}
|
||||||
if config.getboolean('enable_system_updates', True):
|
if config.getboolean('enable_system_updates', True):
|
||||||
self.updaters['system'] = PackageDeploy(config, self.cmd_helper)
|
self.updaters['system'] = PackageDeploy(config, self.cmd_helper)
|
||||||
db: DBComp = self.server.lookup_component('database')
|
mcfg = self.app_config["moonraker"]
|
||||||
kpath = db.get_item("moonraker", "update_manager.klipper_path",
|
kcfg = self.app_config["klipper"]
|
||||||
KLIPPER_DEFAULT_PATH).result()
|
mclass = get_deploy_class(mcfg.get("path"))
|
||||||
kenv_path = db.get_item("moonraker", "update_manager.klipper_exec",
|
self.updaters['moonraker'] = mclass(mcfg, self.cmd_helper)
|
||||||
KLIPPER_DEFAULT_EXEC).result()
|
kclass = BaseDeploy
|
||||||
self.updaters['moonraker'] = get_deploy_class(MOONRAKER_PATH)(
|
|
||||||
self.app_config[f"update_manager moonraker"], self.cmd_helper,
|
|
||||||
{
|
|
||||||
'channel': self.channel,
|
|
||||||
'path': MOONRAKER_PATH,
|
|
||||||
'executable': sys.executable
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
os.path.exists(kpath) and
|
os.path.exists(kcfg.get("path")) and
|
||||||
os.path.exists(kenv_path)
|
os.path.exists(kcfg.get("env"))
|
||||||
):
|
):
|
||||||
self.updaters['klipper'] = get_deploy_class(kpath)(
|
kclass = get_deploy_class(kcfg.get("path"))
|
||||||
self.app_config[f"update_manager klipper"], self.cmd_helper,
|
self.updaters['klipper'] = kclass(kcfg, self.cmd_helper)
|
||||||
{
|
|
||||||
'channel': self.channel,
|
|
||||||
'path': kpath,
|
|
||||||
'executable': kenv_path
|
|
||||||
}
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.updaters['klipper'] = BaseDeploy(
|
|
||||||
self.app_config[f"update_manager klipper"], self.cmd_helper)
|
|
||||||
|
|
||||||
# TODO: The below check may be removed when invalid config options
|
# TODO: The below check may be removed when invalid config options
|
||||||
# raise a config error.
|
# raise a config error.
|
||||||
|
@ -135,8 +112,8 @@ class UpdateManager:
|
||||||
self.updaters[name] = WebClientDeploy(cfg, self.cmd_helper)
|
self.updaters[name] = WebClientDeploy(cfg, self.cmd_helper)
|
||||||
elif client_type in ["git_repo", "zip", "zip_beta"]:
|
elif client_type in ["git_repo", "zip", "zip_beta"]:
|
||||||
path = os.path.expanduser(cfg.get('path'))
|
path = os.path.expanduser(cfg.get('path'))
|
||||||
self.updaters[name] = get_deploy_class(path)(
|
dclass = get_deploy_class(path)
|
||||||
cfg, self.cmd_helper)
|
self.updaters[name] = dclass(cfg, self.cmd_helper)
|
||||||
else:
|
else:
|
||||||
raise config.error(
|
raise config.error(
|
||||||
f"Invalid type '{client_type}' for section [{section}]")
|
f"Invalid type '{client_type}' for section [{section}]")
|
||||||
|
@ -215,14 +192,12 @@ class UpdateManager:
|
||||||
db: DBComp = self.server.lookup_component('database')
|
db: DBComp = self.server.lookup_component('database')
|
||||||
db.insert_item("moonraker", "update_manager.klipper_path", kpath)
|
db.insert_item("moonraker", "update_manager.klipper_path", kpath)
|
||||||
db.insert_item("moonraker", "update_manager.klipper_exec", executable)
|
db.insert_item("moonraker", "update_manager.klipper_exec", executable)
|
||||||
|
kcfg = self.app_config["klipper"]
|
||||||
|
kcfg.set_option("path", kpath)
|
||||||
|
kcfg.set_option("env", executable)
|
||||||
need_notification = not isinstance(kupdater, AppDeploy)
|
need_notification = not isinstance(kupdater, AppDeploy)
|
||||||
self.updaters['klipper'] = get_deploy_class(kpath)(
|
kclass = get_deploy_class(kpath)
|
||||||
self.app_config[f"update_manager klipper"], self.cmd_helper,
|
self.updaters['klipper'] = kclass(kcfg, self.cmd_helper)
|
||||||
{
|
|
||||||
'channel': self.channel,
|
|
||||||
'path': kpath,
|
|
||||||
'executable': executable
|
|
||||||
})
|
|
||||||
async with self.cmd_request_lock:
|
async with self.cmd_request_lock:
|
||||||
umdb = self.cmd_helper.get_umdb()
|
umdb = self.cmd_helper.get_umdb()
|
||||||
await umdb.pop('klipper', None)
|
await umdb.pop('klipper', None)
|
||||||
|
|
|
@ -35,12 +35,8 @@ RINFO_KEYS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
class ZipDeploy(AppDeploy):
|
class ZipDeploy(AppDeploy):
|
||||||
def __init__(self,
|
def __init__(self, config: ConfigHelper, cmd_helper: CommandHelper) -> None:
|
||||||
config: ConfigHelper,
|
super().__init__(config, cmd_helper)
|
||||||
cmd_helper: CommandHelper,
|
|
||||||
app_params: Optional[Dict[str, Any]] = None
|
|
||||||
) -> None:
|
|
||||||
super().__init__(config, cmd_helper, app_params)
|
|
||||||
self.official_repo: str = "?"
|
self.official_repo: str = "?"
|
||||||
self.owner: str = "?"
|
self.owner: str = "?"
|
||||||
# Extract repo from origin for validation
|
# Extract repo from origin for validation
|
||||||
|
@ -60,7 +56,7 @@ class ZipDeploy(AppDeploy):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def from_application(app: AppDeploy) -> ZipDeploy:
|
async def from_application(app: AppDeploy) -> ZipDeploy:
|
||||||
new_app = ZipDeploy(app.config, app.cmd_helper, app.app_params)
|
new_app = ZipDeploy(app.config, app.cmd_helper)
|
||||||
await new_app.reinstall()
|
await new_app.reinstall()
|
||||||
return new_app
|
return new_app
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue