update_manager: add support for persistent state
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
3a547fb530
commit
eb8f1e2526
|
@ -32,6 +32,7 @@ from typing import (
|
||||||
Union,
|
Union,
|
||||||
Dict,
|
Dict,
|
||||||
List,
|
List,
|
||||||
|
cast
|
||||||
)
|
)
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from tornado.httpclient import HTTPResponse
|
from tornado.httpclient import HTTPResponse
|
||||||
|
@ -41,6 +42,7 @@ if TYPE_CHECKING:
|
||||||
from components.klippy_apis import KlippyAPI as APIComp
|
from components.klippy_apis import KlippyAPI as APIComp
|
||||||
from components.shell_command import ShellCommandFactory as SCMDComp
|
from components.shell_command import ShellCommandFactory as SCMDComp
|
||||||
from components.database import MoonrakerDatabase as DBComp
|
from components.database import MoonrakerDatabase as DBComp
|
||||||
|
from components.database import NamespaceWrapper
|
||||||
JsonType = Union[List[Any], Dict[str, Any]]
|
JsonType = Union[List[Any], Dict[str, Any]]
|
||||||
|
|
||||||
MOONRAKER_PATH = os.path.normpath(os.path.join(
|
MOONRAKER_PATH = os.path.normpath(os.path.join(
|
||||||
|
@ -167,9 +169,7 @@ class UpdateManager:
|
||||||
async def component_init(self) -> None:
|
async def component_init(self) -> None:
|
||||||
async with self.cmd_request_lock:
|
async with self.cmd_request_lock:
|
||||||
for updater in list(self.updaters.values()):
|
for updater in list(self.updaters.values()):
|
||||||
if isinstance(updater, PackageDeploy):
|
if updater.needs_refresh():
|
||||||
ret = updater.refresh(False)
|
|
||||||
else:
|
|
||||||
ret = updater.refresh()
|
ret = updater.refresh()
|
||||||
await ret
|
await ret
|
||||||
if self.refresh_cb is not None:
|
if self.refresh_cb is not None:
|
||||||
|
@ -436,6 +436,11 @@ class CommandHelper:
|
||||||
self.http_client = AsyncHTTPClient()
|
self.http_client = AsyncHTTPClient()
|
||||||
self.github_request_cache: Dict[str, CachedGithubResponse] = {}
|
self.github_request_cache: Dict[str, CachedGithubResponse] = {}
|
||||||
|
|
||||||
|
# database management
|
||||||
|
db: DBComp = self.server.lookup_component('database')
|
||||||
|
db.register_local_namespace("update_manager")
|
||||||
|
self.umdb = db.wrap_namespace("update_manager")
|
||||||
|
|
||||||
# Refresh Time Tracking (default is to refresh every 28 days)
|
# Refresh Time Tracking (default is to refresh every 28 days)
|
||||||
reresh_interval = config.getint('refresh_interval', 672)
|
reresh_interval = config.getint('refresh_interval', 672)
|
||||||
# Convert to seconds
|
# Convert to seconds
|
||||||
|
@ -457,6 +462,9 @@ class CommandHelper:
|
||||||
def get_refresh_interval(self) -> float:
|
def get_refresh_interval(self) -> float:
|
||||||
return self.refresh_interval
|
return self.refresh_interval
|
||||||
|
|
||||||
|
def get_umdb(self) -> NamespaceWrapper:
|
||||||
|
return self.umdb
|
||||||
|
|
||||||
def is_debug_enabled(self) -> bool:
|
def is_debug_enabled(self) -> bool:
|
||||||
return self.debug_enabled
|
return self.debug_enabled
|
||||||
|
|
||||||
|
@ -744,15 +752,16 @@ class PackageDeploy(BaseDeploy):
|
||||||
config: ConfigHelper,
|
config: ConfigHelper,
|
||||||
cmd_helper: CommandHelper
|
cmd_helper: CommandHelper
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(config, cmd_helper)
|
super().__init__(config, cmd_helper, "system", "", "")
|
||||||
cmd_helper.set_package_updater(self)
|
cmd_helper.set_package_updater(self)
|
||||||
self.available_packages: List[str] = []
|
storage = self._load_storage()
|
||||||
|
self.available_packages: List[str] = storage.get('packages', [])
|
||||||
self.refresh_evt: Optional[asyncio.Event] = None
|
self.refresh_evt: Optional[asyncio.Event] = None
|
||||||
# Initialze to current time so an update is not performed on init
|
# Initialze to current time so an update is not performed on init
|
||||||
self.last_apt_update_time: float = time.time()
|
self.last_apt_update_time: float = time.time()
|
||||||
self.mutex: asyncio.Lock = asyncio.Lock()
|
self.mutex: asyncio.Lock = asyncio.Lock()
|
||||||
|
|
||||||
async def refresh(self, fetch_packages: bool = True) -> None:
|
async def refresh(self) -> None:
|
||||||
# TODO: Use python-apt python lib rather than command line for updates
|
# TODO: Use python-apt python lib rather than command line for updates
|
||||||
if self.refresh_evt is not None:
|
if self.refresh_evt is not None:
|
||||||
self.refresh_evt.wait()
|
self.refresh_evt.wait()
|
||||||
|
@ -760,7 +769,7 @@ class PackageDeploy(BaseDeploy):
|
||||||
async with self.mutex:
|
async with self.mutex:
|
||||||
self.refresh_evt = asyncio.Event()
|
self.refresh_evt = asyncio.Event()
|
||||||
try:
|
try:
|
||||||
await self._update_apt(force=fetch_packages)
|
await self._update_apt()
|
||||||
res = await self.cmd_helper.run_cmd_with_response(
|
res = await self.cmd_helper.run_cmd_with_response(
|
||||||
"apt list --upgradable", timeout=60.)
|
"apt list --upgradable", timeout=60.)
|
||||||
pkg_list = [p.strip() for p in res.split("\n") if p.strip()]
|
pkg_list = [p.strip() for p in res.split("\n") if p.strip()]
|
||||||
|
@ -776,6 +785,13 @@ class PackageDeploy(BaseDeploy):
|
||||||
logging.exception("Error Refreshing System Packages")
|
logging.exception("Error Refreshing System Packages")
|
||||||
self.refresh_evt.set()
|
self.refresh_evt.set()
|
||||||
self.refresh_evt = None
|
self.refresh_evt = None
|
||||||
|
# Update Persistent Storage
|
||||||
|
self._save_state()
|
||||||
|
|
||||||
|
def get_persistent_data(self) -> Dict[str, Any]:
|
||||||
|
storage = super().get_persistent_data()
|
||||||
|
storage['packages'] = self.available_packages
|
||||||
|
return storage
|
||||||
|
|
||||||
async def update(self) -> bool:
|
async def update(self) -> bool:
|
||||||
async with self.mutex:
|
async with self.mutex:
|
||||||
|
@ -830,7 +846,7 @@ class WebClientDeploy(BaseDeploy):
|
||||||
config: ConfigHelper,
|
config: ConfigHelper,
|
||||||
cmd_helper: CommandHelper
|
cmd_helper: CommandHelper
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(config, cmd_helper)
|
super().__init__(config, cmd_helper, prefix="Web Client")
|
||||||
self.repo = config.get('repo').strip().strip("/")
|
self.repo = config.get('repo').strip().strip("/")
|
||||||
self.owner = self.repo.split("/", 1)[0]
|
self.owner = self.repo.split("/", 1)[0]
|
||||||
self.path = pathlib.Path(config.get("path")).expanduser().resolve()
|
self.path = pathlib.Path(config.get("path")).expanduser().resolve()
|
||||||
|
@ -844,9 +860,12 @@ class WebClientDeploy(BaseDeploy):
|
||||||
raise config.error(
|
raise config.error(
|
||||||
"Invalid value for option 'persistent_files': "
|
"Invalid value for option 'persistent_files': "
|
||||||
"'.version' can not be persistent")
|
"'.version' can not be persistent")
|
||||||
self.version: str = "?"
|
storage = self._load_storage()
|
||||||
self.remote_version: str = "?"
|
self.version: str = storage.get('version', "?")
|
||||||
self.dl_info: Tuple[str, str, int] = ("?", "?", 0)
|
self.remote_version: str = storage.get('remote_version', "?")
|
||||||
|
dl_info: List[Any] = storage.get('dl_info', ["?", "?", 0])
|
||||||
|
self.dl_info: Tuple[str, str, int] = cast(
|
||||||
|
Tuple[str, str, int], tuple(dl_info))
|
||||||
self.refresh_evt: Optional[asyncio.Event] = None
|
self.refresh_evt: Optional[asyncio.Event] = None
|
||||||
self.mutex: asyncio.Lock = asyncio.Lock()
|
self.mutex: asyncio.Lock = asyncio.Lock()
|
||||||
logging.info(f"\nInitializing Client Updater: '{self.name}',"
|
logging.info(f"\nInitializing Client Updater: '{self.name}',"
|
||||||
|
@ -875,6 +894,7 @@ class WebClientDeploy(BaseDeploy):
|
||||||
logging.exception("Error Refreshing Client")
|
logging.exception("Error Refreshing Client")
|
||||||
self.refresh_evt.set()
|
self.refresh_evt.set()
|
||||||
self.refresh_evt = None
|
self.refresh_evt = None
|
||||||
|
self._save_state()
|
||||||
|
|
||||||
async def _get_remote_version(self) -> None:
|
async def _get_remote_version(self) -> None:
|
||||||
# Remote state
|
# Remote state
|
||||||
|
@ -909,6 +929,13 @@ class WebClientDeploy(BaseDeploy):
|
||||||
f"size: {size}\n"
|
f"size: {size}\n"
|
||||||
f"Content Type: {content_type}")
|
f"Content Type: {content_type}")
|
||||||
|
|
||||||
|
def get_persistent_data(self) -> Dict[str, Any]:
|
||||||
|
storage = super().get_persistent_data()
|
||||||
|
storage['version'] = self.version
|
||||||
|
storage['remote_version'] = self.remote_version
|
||||||
|
storage['dl_info'] = list(self.dl_info)
|
||||||
|
return storage
|
||||||
|
|
||||||
async def update(self) -> bool:
|
async def update(self) -> bool:
|
||||||
async with self.mutex:
|
async with self.mutex:
|
||||||
if self.remote_version == "?":
|
if self.remote_version == "?":
|
||||||
|
@ -947,6 +974,7 @@ class WebClientDeploy(BaseDeploy):
|
||||||
version_path.write_text, self.version)
|
version_path.write_text, self.version)
|
||||||
self.cmd_helper.notify_update_response(
|
self.cmd_helper.notify_update_response(
|
||||||
f"Client Update Finished: {self.name}", is_complete=True)
|
f"Client Update Finished: {self.name}", is_complete=True)
|
||||||
|
self._save_state()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _extract_release(self,
|
def _extract_release(self,
|
||||||
|
|
Loading…
Reference in New Issue