Opt: Show commit info in updater

This commit is contained in:
18870 2022-01-12 22:27:56 +08:00
parent bff8296af5
commit c8a95970d5
13 changed files with 171 additions and 58 deletions

View File

@ -17,7 +17,7 @@ from module.logger import logger
class AzurLaneAutoScript:
stop_event: threading.Event
stop_event: threading.Event = None
def __init__(self, config_name='alas'):
self.config_name = config_name
@ -284,7 +284,7 @@ class AzurLaneAutoScript:
if seconds <= 0:
logger.warning(f'Wait until {str(future)}, but sleep length < 0, skip waiting')
if hasattr(self, 'stop_event'):
if self.stop_event is not None:
self.stop_event.wait(seconds)
if self.stop_event.is_set():
logger.info("Update event detected")
@ -330,7 +330,7 @@ class AzurLaneAutoScript:
failure_record = {}
while 1:
if hasattr(self, 'stop_event'):
if self.stop_event is not None:
if self.stop_event.is_set():
logger.info("Update event detected")
logger.info(f"Alas [{self.config_name}] exited.")

View File

@ -62,22 +62,10 @@ Deploy:
InstallUiautomator2: true
Update:
# Api Access token
# Not necessary, unauthorised users can call Github API 60 times/h, Gitee API has no limitations
# **Use same platform as Repository
# Github:
# https://github.com/settings/tokens/new
# Enter your note, choose expiration and click Generate token, copy the token
# Token will be like this: ghp_cdvpqb23klCfg9Ah567anou8Bt4imDwxersj0yz1
# Gitee:
# https://gitee.com/api/v5/swagger#/
# Click "申请授权" at the upper right corner, copy value of access_token
# Token will be like this: pqrsg189hijcbkn0672def1lm495a3o4
ApiToken: null
# Check update every X minute
# [Disable] -1
# [Default] 30
CheckUpdateInterval: 30
# [Default] 5
CheckUpdateInterval: 5
# Scheduled restart time
# If there are updates, Alas will automatically restart and update at this time every day
# and run all alas instances that running before restarted

View File

@ -30,6 +30,7 @@ Status:
Running:
Inactive:
Warning:
Updating:
MenuAlas:
Overview:
@ -66,6 +67,11 @@ Update:
UpdateFailed:
UpdateChecking:
UpdateCancel:
Local:
Upstream:
Author:
Time:
Message:
Text:
InvalidFeedBack:

View File

@ -57,7 +57,7 @@ def name_to_function(name):
class AzurLaneConfig(ConfigUpdater, ManualConfig, GeneratedConfig):
stop_event: threading.Event
stop_event: threading.Event = None
bound = {}
# Class property
@ -406,7 +406,7 @@ class AzurLaneConfig(ConfigUpdater, ManualConfig, GeneratedConfig):
bool: If task switched
"""
# Update event
if hasattr(self, 'stop_event'):
if self.stop_event is not None:
if self.stop_event.is_set():
return True
prev = self.task

View File

@ -1782,7 +1782,8 @@
"Status": {
"Running": "Running",
"Inactive": "Inactive",
"Warning": "Warning"
"Warning": "Warning",
"Updating": "Waiting Update"
},
"MenuAlas": {
"Overview": "Overview",
@ -1817,7 +1818,12 @@
"UpdateRun": "Updating",
"UpdateSuccess": "Update succeeded, restarting",
"UpdateChecking": "Checking for updates",
"UpdateCancel": "Update canceled, restarting Alas"
"UpdateCancel": "Update canceled, restarting Alas",
"Local": "Local",
"Upstream": "Upstream",
"Author": "Author",
"Time": "Commit time",
"Message": "Commit message"
},
"Text": {
"InvalidFeedBack": "Invalid format. Example: {0}"

View File

@ -1782,7 +1782,8 @@
"Status": {
"Running": "Gui.Status.Running",
"Inactive": "Gui.Status.Inactive",
"Warning": "Gui.Status.Warning"
"Warning": "Gui.Status.Warning",
"Updating": "Gui.Status.Updating"
},
"MenuAlas": {
"Overview": "Gui.MenuAlas.Overview",
@ -1817,7 +1818,12 @@
"UpdateRun": "Gui.Update.UpdateRun",
"UpdateSuccess": "Gui.Update.UpdateSuccess",
"UpdateChecking": "Gui.Update.UpdateChecking",
"UpdateCancel": "Gui.Update.UpdateCancel"
"UpdateCancel": "Gui.Update.UpdateCancel",
"Local": "Gui.Update.Local",
"Upstream": "Gui.Update.Upstream",
"Author": "Gui.Update.Author",
"Time": "Gui.Update.Time",
"Message": "Gui.Update.Message"
},
"Text": {
"InvalidFeedBack": "Gui.Text.InvalidFeedBack"

View File

@ -1782,7 +1782,8 @@
"Status": {
"Running": "运行中",
"Inactive": "闲置",
"Warning": "发生错误"
"Warning": "发生错误",
"Updating": "等待更新"
},
"MenuAlas": {
"Overview": "总览",
@ -1817,7 +1818,12 @@
"UpdateRun": "更新中",
"UpdateSuccess": "更新成功,正在重启",
"UpdateChecking": "检查更新中",
"UpdateCancel": "取消更新,重启 Alas 中"
"UpdateCancel": "取消更新,重启 Alas 中",
"Local": "本地",
"Upstream": "上游仓库",
"Author": "作者",
"Time": "提交时间",
"Message": "提交信息"
},
"Text": {
"InvalidFeedBack": "格式错误。 示例:{0}"

View File

@ -1782,7 +1782,8 @@
"Status": {
"Running": "執行中",
"Inactive": "閒置",
"Warning": "發生錯誤"
"Warning": "發生錯誤",
"Updating": "等待更新"
},
"MenuAlas": {
"Overview": "總覽",
@ -1817,7 +1818,12 @@
"UpdateRun": "更新中",
"UpdateSuccess": "更新成功,正在重啓",
"UpdateChecking": "檢查更新中",
"UpdateCancel": "取消更新,重啓 Alas 中"
"UpdateCancel": "取消更新,重啓 Alas 中",
"Local": "本地",
"Upstream": "上游倉庫",
"Author": "作者",
"Time": "提交時間",
"Message": "提交資訊"
},
"Text": {
"InvalidFeedBack": "格式錯誤。 示例:{0}"

View File

@ -33,7 +33,7 @@ from pywebio.exceptions import SessionClosedException, SessionNotFoundException
from pywebio.output import (clear, close_popup, popup, put_button, put_buttons,
put_collapse, put_column, put_error, put_html,
put_loading, put_markdown, put_row, put_scope,
put_text, toast, use_scope)
put_table, put_text, toast, use_scope)
from pywebio.pin import pin, pin_wait_change
from pywebio.session import go_app, info, register_thread, run_js, set_env
@ -97,6 +97,7 @@ class AlasGUI(Frame):
1 (running)
2 (not running)
3 (warning, stop unexpectedly)
4 (stop for update)
0 (hide)
-1 (*state not changed)
"""
@ -124,6 +125,13 @@ class AlasGUI(Frame):
None,
put_text(t("Gui.Status.Warning"))
], size='auto 2px 1fr')
elif state == 4:
put_row([
put_loading(shape='grow', color='success').style(
"--loading-grow--"),
None,
put_text(t("Gui.Status.Updating"))
], size='auto 2px 1fr')
@classmethod
def set_theme(cls, theme='default') -> None:
@ -570,6 +578,18 @@ class AlasGUI(Frame):
], size='auto .25rem 1fr')
put_scope('updater_btn')
put_scope('updater_info')
def update_table():
with use_scope('updater_info', clear=True):
local_commit = updater.get_commit(short_sha1=True)
upstream_commit = updater.get_commit(
f'origin/{updater.branch}', short_sha1=True)
put_table([
[t('Gui.Update.Local'), *local_commit],
[t('Gui.Update.Upstream'), *upstream_commit]
], header=['', 'SHA1', t('Gui.Update.Author'),
t('Gui.Update.Time'), t('Gui.Update.Message')])
def u(state):
if state == -1:
@ -586,6 +606,7 @@ class AlasGUI(Frame):
color='info',
scope='updater_btn'
)
update_table()
elif state == 1:
put_loading('grow', 'success', 'updater_loading').style(
"--loading-grow--")
@ -595,6 +616,7 @@ class AlasGUI(Frame):
color='success',
scope='updater_btn'
)
update_table()
elif state == 'checking':
put_loading('border', 'primary', 'updater_loading').style(
"--loading-border--")
@ -640,6 +662,7 @@ class AlasGUI(Frame):
put_loading('grow', 'success', 'updater_loading').style(
"--loading-grow--")
put_text(t('Gui.Update.UpdateSuccess'), scope='updater_state')
update_table()
elif state == 'cancel':
put_loading('border', 'danger', 'updater_loading').style(
"--loading-border--")
@ -661,6 +684,7 @@ class AlasGUI(Frame):
name='updater'
)
update_table()
self.task_handler.add(updater_switch.g(),
delay=0.5, pending_delete=True)
@ -952,7 +976,7 @@ def app():
debug=True,
on_startup=[
startup,
lambda: AlasManager.start_alas(ev = updater.event)
lambda: AlasManager.start_alas(ev=updater.event)
],
on_shutdown=[clearup]
)

View File

@ -1,4 +1,4 @@
from module.webui.utils import Icon, TaskHandler, set_localstorage
from module.webui.utils import Icon, WebIOTaskHandler, set_localstorage
from pywebio.output import clear, put_html, put_scope, put_text, use_scope
from pywebio.session import defer_call, info, run_js
@ -11,7 +11,7 @@ class Base:
# Device type
self.is_mobile = info.user_agent.is_mobile
# Task handler
self.task_handler = TaskHandler(use_pywebio=True)
self.task_handler = WebIOTaskHandler()
defer_call(self.stop)
def stop(self) -> None:

View File

@ -62,6 +62,8 @@ class AlasManager:
return 1
elif len(self.log) == 0 or self.log[-1] == "Scheduler stopped.\n":
return 2
elif self.log[-2].endswith('Update event detected'):
return 4
else:
return 3

View File

@ -3,7 +3,7 @@ import datetime
import subprocess
import threading
import time
from typing import Generator
from typing import Generator, Tuple
import requests
from deploy.installer import DeployConfig, ExecutionError, Installer
@ -26,11 +26,18 @@ class Updater(Config, Installer):
def __init__(self, file=DEPLOY_CONFIG):
super().__init__(file=file)
self.state = 0
self.delay = int(self.config['CheckUpdateInterval'])*60
self.schedule_time = datetime.time.fromisoformat(
self.config['AutoRestartTime'])
self.event: threading.Event = None
@property
def delay(self):
self.read()
return int(self.config['CheckUpdateInterval'])*60
@property
def schedule_time(self):
self.read()
return datetime.time.fromisoformat(self.config['AutoRestartTime'])
@cached_property
def repo(self):
return self.config['Repository']
@ -39,7 +46,65 @@ class Updater(Config, Installer):
def branch(self):
return self.config['Branch']
def execute_output(self, command) -> str:
command = command.replace(
r'\\', '/').replace('\\', '/').replace('\"', '"')
log = subprocess.run(command, capture_output=True,
text=True, encoding='utf8').stdout
return log
def get_commit(self, revision='', n=1, short_sha1=False) -> Tuple:
"""
Return:
(sha1, author, isotime, message,)
"""
ph = 'h' if short_sha1 else 'H'
log = self.execute_output(
f'{self.git} log {revision} --pretty=format:"%{ph}---%an---%ad---%s" --date=iso -{n}')
if not log:
return None, None, None, None
logs = log.split('\n')
logs = list(map(lambda log: tuple(log.split('---')), logs))
if n == 1:
return logs[0]
else:
return logs
def _check_update(self) -> bool:
self.state = 'checking'
source = 'origin'
for _ in range(3):
if self.execute(f'"{self.git}" fetch {source} {self.branch}', allow_failure=True):
break
else:
logger.warning("Git fetch failed")
return False
log = self.execute_output(
f'{self.git} log --not --remotes={source}/* -1 --oneline')
if log:
logger.info(
f"Cannot find local commit {log.split()[0]} in upstream, skip update")
return False
sha1, _, _, message = self.get_commit(f'..{source}/{self.branch}')
if sha1:
logger.info(f"New update avaliable")
logger.info(f"{sha1[:8]} - {message}")
return True
else:
logger.info(f"No update")
return False
def _check_update_(self) -> bool:
"""
Deprecated
"""
self.state = 'checking'
r = self.repo.split('/')
owner = r[3]
@ -60,20 +125,6 @@ class Updater(Config, Installer):
if token:
headers['Authorization'] = 'token ' + token
p = subprocess.run(f"{self.git} rev-parse HEAD",
capture_output=True, text=True)
if p.stdout is None:
logger.warning("Cannot get local commit sha1")
return 0
local_sha = p.stdout
if len(local_sha) != 41:
logger.warning("Cannot get local commit sha1")
return 0
local_sha = local_sha.strip()
try:
list_commit = requests.get(
base + f"{owner}/{repo}/branches/{self.branch}", headers=headers, params=para)
@ -93,6 +144,8 @@ class Updater(Config, Installer):
logger.warning("Check update failed when parsing return json")
return 0
local_sha, _, _, _ = self._get_local_commit()
if sha == local_sha:
logger.info("No update")
return 0
@ -192,7 +245,7 @@ class Updater(Config, Installer):
self.event.clear()
AlasManager.start_alas(instances, self.event)
return False
@staticmethod
def _trigger_reload(delay=2):
def trigger():

View File

@ -52,14 +52,15 @@ class Thread(threading.Thread):
class Task:
def __init__(self, g: Generator, delay: float, next_run: float = None) -> None:
def __init__(self, g: Generator, delay: float, next_run: float = None, name: str = None) -> None:
self.g = g
g.send(None)
self.delay = delay
self.next_run = next_run if next_run else time.time()
self.name = name if name is not None else self.g.__name__
def __str__(self) -> str:
return f'<{self.g.__name__} (delay={self.delay})>'
return f'<{self.name} (delay={self.delay})>'
def __next__(self) -> None:
return next(self.g)
@ -71,7 +72,7 @@ class Task:
class TaskHandler:
def __init__(self, use_pywebio=False) -> None:
def __init__(self) -> None:
# List of background running task
self.tasks: List[Task] = []
# List of task name to be removed
@ -81,8 +82,6 @@ class TaskHandler:
# Task running thread
self._thread: Thread = None
self._lock = threading.Lock()
# register pywebio thread
self.use_pywebio = use_pywebio
def add(self, func, delay: float, pending_delete: bool = False) -> None:
"""
@ -143,6 +142,13 @@ class TaskHandler:
def remove_current_task(self) -> None:
self.remove_task(self._task, nowait=True)
def get_task(self, name) -> Task:
with self._lock:
for task in self.tasks:
if task.name == name:
return task
return None
def loop(self) -> None:
"""
Start task loop.
@ -175,6 +181,11 @@ class TaskHandler:
else:
time.sleep(0.5)
def _get_thread(self) -> threading.Thread:
thread = Thread(target=self.loop)
thread.daemon = True
return thread
def start(self) -> None:
"""
Start task handler.
@ -183,9 +194,7 @@ class TaskHandler:
if self._thread is not None and self._thread.is_alive():
logger.warning("Task handler already running!")
return
self._thread = Thread(target=self.loop)
if self.use_pywebio:
register_thread(self._thread)
self._thread = self._get_thread()
self._thread.start()
def stop(self) -> None:
@ -195,6 +204,13 @@ class TaskHandler:
logger.info("Finish task handler")
class WebIOTaskHandler(TaskHandler):
def _get_thread(self) -> threading.Thread:
thread = super()._get_thread()
register_thread(thread)
return thread
class Switch:
def __init__(self, status, get_state, name=None):
"""