update_manager: refresh the local git repo state when a status refresh is requested

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Arksine 2020-12-17 06:16:30 -05:00
parent 20d27b0be6
commit 40b74cefb5
1 changed files with 39 additions and 26 deletions

View File

@ -11,6 +11,7 @@ import sys
import shutil import shutil
import zipfile import zipfile
import io import io
import asyncio
import tornado.gen import tornado.gen
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient, HTTPRequest from tornado.httpclient import AsyncHTTPClient, HTTPRequest
@ -44,11 +45,10 @@ class UpdateManager:
self.server = config.get_server() self.server = config.get_server()
AsyncHTTPClient.configure(None, defaults=dict(user_agent="Moonraker")) AsyncHTTPClient.configure(None, defaults=dict(user_agent="Moonraker"))
self.http_client = AsyncHTTPClient() self.http_client = AsyncHTTPClient()
sw_version = config['system_args'].get('software_version') env = sys.executable
self.updaters = { self.updaters = {
"system": PackageUpdater(self), "system": PackageUpdater(self),
"moonraker": GitUpdater(self, "moonraker", MOONRAKER_PATH, "moonraker": GitUpdater(self, "moonraker", MOONRAKER_PATH, env)
sw_version, sys.executable)
} }
self.current_update = None self.current_update = None
client_repo = config.get("client_repo", None) client_repo = config.get("client_repo", None)
@ -86,14 +86,14 @@ class UpdateManager:
logging.info("No valid klippy info received") logging.info("No valid klippy info received")
return return
kpath = kinfo['klipper_path'] kpath = kinfo['klipper_path']
kversion = kinfo['software_version']
env = kinfo['python_path'] env = kinfo['python_path']
self.updaters['klipper'] = GitUpdater( self.updaters['klipper'] = GitUpdater(self, "klipper", kpath, env)
self, "klipper", kpath, kversion, env)
async def _check_versions(self): async def _refresh_git_repo_state(self):
for updater in self.updaters.values(): for updater in self.updaters.values():
await updater.check_remote_version() ret = updater.refresh_update_state()
if asyncio.iscoroutine(ret):
await ret
async def _handle_update_request(self, web_request): async def _handle_update_request(self, web_request):
app = web_request.get_endpoint().split("/")[-1] app = web_request.get_endpoint().split("/")[-1]
@ -114,7 +114,7 @@ class UpdateManager:
async def _handle_status_request(self, web_request): async def _handle_status_request(self, web_request):
if web_request.get_boolean('refresh', False): if web_request.get_boolean('refresh', False):
await self._check_versions() await self._refresh_git_repo_state()
vinfo = {} vinfo = {}
for name, updater in self.updaters.items(): for name, updater in self.updaters.items():
if hasattr(updater, "get_update_status"): if hasattr(updater, "get_update_status"):
@ -184,7 +184,7 @@ class UpdateManager:
class GitUpdater: class GitUpdater:
def __init__(self, umgr, name, path, ver, env): def __init__(self, umgr, name, path, env):
self.server = umgr.server self.server = umgr.server
self.execute_cmd = umgr.execute_cmd self.execute_cmd = umgr.execute_cmd
self.execute_cmd_with_response = umgr.execute_cmd_with_response self.execute_cmd_with_response = umgr.execute_cmd_with_response
@ -194,14 +194,8 @@ class GitUpdater:
self.repo_path = path self.repo_path = path
self.env = env self.env = env
self.version = self.cur_hash = self.remote_hash = "?" self.version = self.cur_hash = self.remote_hash = "?"
self.is_valid = False self.is_valid = self.is_dirty = False
self.is_dirty = ver.endswith("dirty") IOLoop.current().spawn_callback(self.refresh_update_state)
tag_version = "?"
ver_match = re.match(r"v\d+\.\d+\.\d-\d+", ver)
if ver_match:
tag_version = ver_match.group()
self.version = tag_version
IOLoop.current().spawn_callback(self._init_repo)
def _get_version_info(self): def _get_version_info(self):
ver_path = os.path.join(self.repo_path, "scripts/version.txt") ver_path = os.path.join(self.repo_path, "scripts/version.txt")
@ -239,7 +233,7 @@ class GitUpdater:
logging.debug(log_msg) logging.debug(log_msg)
self.notify_update_response(log_msg) self.notify_update_response(log_msg)
async def _init_repo(self): async def refresh_update_state(self):
self.is_valid = False self.is_valid = False
self.cur_hash = "?" self.cur_hash = "?"
try: try:
@ -249,10 +243,20 @@ class GitUpdater:
f"git -C {self.repo_path} remote get-url origin") f"git -C {self.repo_path} remote get-url origin")
hash = await self.execute_cmd_with_response( hash = await self.execute_cmd_with_response(
f"git -C {self.repo_path} rev-parse HEAD") f"git -C {self.repo_path} rev-parse HEAD")
repo_version = await self.execute_cmd_with_response(
f"git -C {self.repo_path} describe --always "
"--tags --long --dirty")
except Exception: except Exception:
self._log_exc("Error retreiving git info") self._log_exc("Error retreiving git info")
return return
self.is_dirty = repo_version.endswith("dirty")
tag_version = "?"
ver_match = re.match(r"v\d+\.\d+\.\d-\d+", repo_version)
if ver_match:
tag_version = ver_match.group()
self.version = tag_version
if not branch.startswith("fatal:"): if not branch.startswith("fatal:"):
self.cur_hash = hash self.cur_hash = hash
if branch == "master": if branch == "master":
@ -267,7 +271,7 @@ class GitUpdater:
else: else:
self._log_info("Git repo not on master branch") self._log_info("Git repo not on master branch")
else: else:
self._log_info(f"Invalid git repo at path '{self.repo_path}''") self._log_info(f"Invalid git repo at path '{self.repo_path}'")
try: try:
await self.check_remote_version() await self.check_remote_version()
except Exception: except Exception:
@ -400,7 +404,9 @@ class PackageUpdater:
self.execute_cmd = umgr.execute_cmd self.execute_cmd = umgr.execute_cmd
self.notify_update_response = umgr.notify_update_response self.notify_update_response = umgr.notify_update_response
async def check_remote_version(self): def refresh_update_state(self):
# TODO: We should be able to determine if packages need to be
# updated here
pass pass
async def update(self, *args): async def update(self, *args):
@ -422,17 +428,24 @@ class ClientUpdater:
self.name = self.repo.split("/")[-1] self.name = self.repo.split("/")[-1]
self.path = path self.path = path
self.version = self.remote_version = self.dl_url = "?" self.version = self.remote_version = self.dl_url = "?"
self._get_local_version()
logging.info(f"\nInitializing Client Updater: '{self.name}',"
f"\nversion: {self.version}"
f"\npath: {self.path}")
IOLoop.current().spawn_callback(self.refresh_update_state)
def _get_local_version(self):
version_path = os.path.join(self.path, ".version") version_path = os.path.join(self.path, ".version")
if os.path.isfile(os.path.join(self.path, ".version")): if os.path.isfile(os.path.join(self.path, ".version")):
with open(version_path, "r") as f: with open(version_path, "r") as f:
v = f.read() v = f.read()
self.version = v.strip() self.version = v.strip()
logging.info(f"\nInitializing repo '{self.name}',"
f"\nversion: {self.version}"
f"\npath: {self.path}")
IOLoop.current().spawn_callback(self.check_remote_version)
async def check_remote_version(self): async def refresh_update_state(self):
# Local state
self._get_local_version()
# Remote state
url = f"https://api.github.com/repos/{self.repo}/releases/latest" url = f"https://api.github.com/repos/{self.repo}/releases/latest"
try: try:
result = await self.github_request(url) result = await self.github_request(url)