1
0
mirror of https://gitee.com/sui-feng-cb/AzurLaneAutoScript1 synced 2026-03-09 18:39:04 +08:00
AzurLaneAutoScript/module/webui/updater.py

291 lines
8.5 KiB
Python
Raw Normal View History

2022-01-09 18:59:25 +08:00
import datetime
import subprocess
import threading
import time
2022-01-12 22:27:56 +08:00
from typing import Generator, Tuple
2022-01-09 18:59:25 +08:00
import requests
2022-06-03 21:28:44 +08:00
from deploy.config import ExecutionError
from deploy.git import GitManager
from deploy.pip import PipManager
2022-06-03 21:28:44 +08:00
from deploy.utils import DEPLOY_CONFIG
from module.base.retry import retry
2022-01-09 18:59:25 +08:00
from module.logger import logger
2022-06-03 21:28:44 +08:00
from module.webui.config import DeployConfig
from module.webui.process_manager import ProcessManager
from module.webui.setting import State
2022-01-10 13:23:22 +08:00
from module.webui.utils import TaskHandler, get_next_time
2022-01-09 18:59:25 +08:00
2022-06-03 21:28:44 +08:00
class Updater(DeployConfig, GitManager, PipManager):
2022-01-09 18:59:25 +08:00
def __init__(self, file=DEPLOY_CONFIG):
2022-06-03 21:28:44 +08:00
super().__init__(file=file)
self.state = 0
self.event: threading.Event = None
2022-01-12 22:27:56 +08:00
@property
def delay(self):
self.read()
return int(self.CheckUpdateInterval) * 60
2022-01-12 22:27:56 +08:00
@property
def schedule_time(self):
self.read()
2022-06-03 21:28:44 +08:00
t = self.AutoRestartTime
if t is not None:
2022-01-16 00:57:32 +08:00
return datetime.time.fromisoformat(t)
else:
return None
2022-01-12 22:27:56 +08:00
def execute_output(self, command) -> str:
command = command.replace(r"\\", "/").replace("\\", "/").replace('"', '"')
log = subprocess.run(
command, capture_output=True, text=True, encoding="utf8", shell=True
).stdout
2022-01-12 22:27:56 +08:00
return log
def get_commit(self, revision="", n=1, short_sha1=False) -> Tuple:
2022-01-12 22:27:56 +08:00
"""
Return:
(sha1, author, isotime, message,)
"""
ph = "h" if short_sha1 else "H"
2022-01-12 22:27:56 +08:00
log = self.execute_output(
f'"{self.git}" log {revision} --pretty=format:"%{ph}---%an---%ad---%s" --date=iso -{n}'
)
2022-01-12 22:27:56 +08:00
if not log:
return None, None, None, None
logs = log.split("\n")
logs = list(map(lambda log: tuple(log.split("---")), logs))
2022-01-12 22:27:56 +08:00
if n == 1:
return logs[0]
else:
return logs
2022-01-11 02:36:45 +08:00
def _check_update(self) -> bool:
self.state = "checking"
source = "origin"
2022-01-12 22:27:56 +08:00
for _ in range(3):
if self.execute(
2022-06-03 21:28:44 +08:00
f'"{self.git}" fetch {source} {self.Branch}', allow_failure=True
):
2022-01-12 22:27:56 +08:00
break
else:
logger.warning("Git fetch failed")
return False
log = self.execute_output(
f'"{self.git}" log --not --remotes={source}/* -1 --oneline'
)
2022-01-12 22:27:56 +08:00
if log:
logger.info(
f"Cannot find local commit {log.split()[0]} in upstream, skip update"
)
2022-01-12 22:27:56 +08:00
return False
2022-06-03 21:28:44 +08:00
sha1, _, _, message = self.get_commit(f"..{source}/{self.Branch}")
2022-01-12 22:27:56 +08:00
if sha1:
2022-06-25 20:04:45 +08:00
logger.info(f"New update available")
2022-01-12 22:27:56 +08:00
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"
2022-06-03 21:28:44 +08:00
r = self.Repository.split("/")
2022-01-09 18:59:25 +08:00
owner = r[3]
repo = r[4]
if "gitee" in r[2]:
2022-01-10 00:42:40 +08:00
base = "https://gitee.com/api/v5/repos/"
2022-01-09 18:59:25 +08:00
headers = {}
token = self.config["ApiToken"]
2022-01-10 15:05:34 +08:00
if token:
para = {"access_token": token}
2022-01-09 18:59:25 +08:00
else:
2022-01-10 00:42:40 +08:00
base = "https://api.github.com/repos/"
headers = {"Accept": "application/vnd.github.v3.sha"}
2022-01-10 15:05:34 +08:00
para = {}
token = self.config["ApiToken"]
2022-01-10 15:05:34 +08:00
if token:
headers["Authorization"] = "token " + token
2022-01-09 18:59:25 +08:00
try:
2022-01-10 00:42:40 +08:00
list_commit = requests.get(
2022-06-03 21:28:44 +08:00
base + f"{owner}/{repo}/branches/{self.Branch}",
headers=headers,
params=para,
)
2022-01-09 18:59:25 +08:00
except Exception as e:
logger.exception(e)
logger.warning("Check update failed")
2022-01-11 02:36:45 +08:00
return 0
2022-01-09 18:59:25 +08:00
if list_commit.status_code != 200:
logger.warning(f"Check update failed, code {list_commit.status_code}")
2022-01-11 02:36:45 +08:00
return 0
2022-01-09 18:59:25 +08:00
try:
sha = list_commit.json()["commit"]["sha"]
2022-01-09 18:59:25 +08:00
except Exception as e:
logger.exception(e)
logger.warning("Check update failed when parsing return json")
2022-01-11 02:36:45 +08:00
return 0
2022-01-09 18:59:25 +08:00
2022-01-12 22:27:56 +08:00
local_sha, _, _, _ = self._get_local_commit()
2022-01-09 18:59:25 +08:00
if sha == local_sha:
logger.info("No update")
2022-01-11 02:36:45 +08:00
return 0
2022-01-09 18:59:25 +08:00
2022-01-10 15:05:34 +08:00
try:
get_commit = requests.get(
base + f"{owner}/{repo}/commits/" + local_sha,
headers=headers,
params=para,
)
2022-01-10 15:05:34 +08:00
except Exception as e:
logger.exception(e)
logger.warning("Check update failed")
2022-01-11 02:36:45 +08:00
return 0
2022-01-10 15:05:34 +08:00
if get_commit.status_code != 200:
# for develops
logger.info(
f"Cannot find local commit {local_sha[:8]} in upstream, skip update"
)
2022-01-11 02:36:45 +08:00
return 0
2022-01-10 15:05:34 +08:00
2022-06-25 20:04:45 +08:00
logger.info(f"Update {sha[:8]} available")
2022-01-11 02:36:45 +08:00
return 1
def check_update(self):
if self.state in (0, "failed", "finish"):
self.state = self._check_update()
2022-01-09 18:59:25 +08:00
@retry(ExecutionError, tries=3, delay=5, logger=None)
2022-01-10 22:14:25 +08:00
def git_install(self):
return super().git_install()
2022-01-09 18:59:25 +08:00
@retry(ExecutionError, tries=3, delay=5, logger=None)
2022-01-10 22:14:25 +08:00
def pip_install(self):
return super().pip_install()
2022-01-09 18:59:25 +08:00
2022-01-10 14:04:02 +08:00
def update(self):
2022-01-10 22:14:25 +08:00
logger.hr("Run update")
try:
self.git_install()
self.pip_install()
except ExecutionError:
return False
return True
2022-01-09 18:59:25 +08:00
2022-01-11 02:36:45 +08:00
def run_update(self):
if self.state not in ("failed", 0, 1):
2022-01-11 02:36:45 +08:00
return
self._start_update()
def _start_update(self):
self.state = "start"
instances = ProcessManager.running_instances()
2022-01-11 02:36:45 +08:00
names = []
for alas in instances:
names.append(alas.config_name + "\n")
2022-01-11 02:36:45 +08:00
logger.info("Waiting all running alas finish.")
self._wait_update(instances, names)
def _wait_update(self, instances, names):
if self.state == "cancel":
2022-01-11 02:36:45 +08:00
self.state = 1
self.state = "wait"
2022-01-11 02:36:45 +08:00
self.event.set()
_instances = instances.copy()
while _instances:
for alas in _instances:
if not alas.alive:
_instances.remove(alas)
logger.info(f"Alas [{alas.config_name}] stopped")
logger.info(f"Remains: {[alas.config_name for alas in _instances]}")
if self.state == "cancel":
2022-01-11 02:36:45 +08:00
self.state = 1
2022-01-11 18:06:06 +08:00
self.event.clear()
ProcessManager.restart_processes(instances, self.event)
2022-01-11 02:36:45 +08:00
return
time.sleep(0.25)
self._run_update(instances, names)
def _run_update(self, instances, names):
self.state = "run update"
2022-01-11 02:36:45 +08:00
logger.info("All alas stopped, start updating")
if self.update():
2022-06-25 20:04:45 +08:00
if State.restart_event is not None:
self.state = "reload"
with open("./config/reloadalas", mode="w") as f:
2022-01-15 17:55:54 +08:00
f.writelines(names)
from module.webui.app import clearup
2022-01-15 17:55:54 +08:00
self._trigger_reload(2)
clearup()
else:
self.state = "finish"
2022-01-11 02:36:45 +08:00
else:
self.state = "failed"
2022-01-11 02:36:45 +08:00
logger.warning("Update failed")
self.event.clear()
ProcessManager.restart_processes(instances, self.event)
2022-01-11 02:36:45 +08:00
return False
2022-01-12 22:27:56 +08:00
2022-01-11 02:36:45 +08:00
@staticmethod
def _trigger_reload(delay=2):
def trigger():
# with open("./config/reloadflag", mode="w"):
# # app ended here and uvicorn will restart whole app
# pass
2022-06-25 20:04:45 +08:00
State.restart_event.set()
timer = threading.Timer(delay, trigger)
timer.start()
2022-01-11 02:36:45 +08:00
2022-01-15 17:55:54 +08:00
def schedule_update(self) -> Generator:
2022-01-11 02:36:45 +08:00
th: TaskHandler
th = yield
if self.schedule_time is None:
th.remove_current_task()
yield
th._task.delay = get_next_time(self.schedule_time)
2022-01-10 13:23:22 +08:00
yield
2022-01-11 02:36:45 +08:00
while True:
self.check_update()
2022-01-11 02:36:45 +08:00
if self.state != 1:
th._task.delay = get_next_time(self.schedule_time)
yield
continue
2022-06-25 20:04:45 +08:00
if State.restart_event is None:
2022-01-15 17:55:54 +08:00
yield
continue
2022-01-11 02:36:45 +08:00
if not self.run_update():
self.state = "failed"
2022-01-11 02:36:45 +08:00
th._task.delay = get_next_time(self.schedule_time)
2022-01-10 13:23:22 +08:00
yield
2022-01-11 02:36:45 +08:00
def cancel(self):
self.state = "cancel"
2022-01-11 02:36:45 +08:00
2022-01-10 13:23:22 +08:00
2022-01-11 02:36:45 +08:00
updater = Updater()
2022-01-10 13:23:22 +08:00
if __name__ == "__main__":
2022-01-09 18:59:25 +08:00
pass
2022-01-10 22:14:25 +08:00
# if updater.check_update():
updater.update()