import json import mimetypes import sys from pathlib import Path from shutil import rmtree from subprocess import PIPE, STDOUT, Popen import requests import webview from log import logger from python.Lib import shutil, os, subprocess mimetypes.add_type("text/html", ".html") mimetypes.add_type("text/css", ".css") mimetypes.add_type("application/javascript", ".js") version = "V0.2" config = { "page": "init", "branch": "slow", "mirror": "aliyun", } config_path = Path("launcher.json") get_new_version_url = "https://git.zhaozuohong.vip/api/v1/repos/mower-ng/launcher/releases/latest" upgrade_script_name = "upgrade.bat" try: with config_path.open("r") as f: user_config = json.load(f) config.update(user_config) except Exception: pass def custom_event(data): data = json.dumps({"log": data}) js = f"var event = new CustomEvent('log', {{detail: {data}}}); window.dispatchEvent(event);" window.evaluate_js(js) def replace_restart(exename, new_exename): script_path = os.path.join(os.getcwd(), upgrade_script_name) with open(script_path, 'w') as b: TempList = f"@echo off\n" TempList += f"timeout /t 3 /nobreak\n" # 等待进程退出 TempList += f"del {exename}\n" # 删除旧程序 TempList += f"move {new_exename} {exename}\n" # 复制新版本程序 TempList += f"timeout /t 1 /nobreak\n" # 等待复制完成 TempList += f"start {exename}\n" # 启动新程序 TempList += f"exit" b.write(TempList) # 不显示cmd窗口 subprocess.Popen([script_path], creationflags=subprocess.CREATE_NO_WINDOW) os._exit(0) mirror_list = { "pypi": "https://pypi.org/simple", "aliyun": "https://mirrors.aliyun.com/pypi/simple/", "tuna": "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple", "sjtu": "https://mirror.sjtu.edu.cn/pypi/web/simple", } command_list = { "lfs": "git\\bin\\git lfs install", "ensurepip": "python\\python -m ensurepip --default-pip", "clone": "git\\bin\\git clone https://git.zhaozuohong.vip/mower-ng/mower-ng.git --branch slow", "fetch": lambda: f"..\\git\\bin\\git fetch origin {config['branch']}", "switch": lambda: f"..\\git\\bin\\git switch -f {config['branch']}", "reset": lambda: f"..\\git\\bin\\git reset --hard origin/{config['branch']}", "pip_install": lambda: f"..\\python\\Scripts\\pip install --no-cache-dir -i {mirror_list[config['mirror']]} -r requirements.txt --no-warn-script-location", "webview": "start ..\\python\\pythonw webview_ui.py", "manager": "start ..\\python\\pythonw manager.py", } class Api: def get_branch(self): return config["branch"] def set_branch(self, branch): config["branch"] = branch def get_page(self): return config["page"] def set_page(self, page): config["page"] = page def get_mirror(self): return config["mirror"] def set_mirror(self, mirror): config["mirror"] = mirror def get_version(self): return version def get_new_version(self): logger.info("获取最新版本号") response = requests.get(get_new_version_url) return response.json() # 更新启动器本身 def update_self(self, download_url): # 获取当前启动器的路径 current_path = sys.argv[0] # 如果current_path是以py结尾,则将其转换为.exe if current_path.endswith(".py"): current_path = current_path[:-3] + ".exe" temp_path = current_path + '.tmp' logger.info(f"下载新版本: {download_url}") response = requests.get(download_url, stream=True) if response.status_code == 200: with open(temp_path, 'wb') as file: shutil.copyfileobj(response.raw, file) else: logger.error(f"下载新版本失败: {response.status_code}") return f"下载新版本: {response.status_code}" logger.info(f"替换旧版本,{temp_path} -> {current_path}") replace_restart(current_path, temp_path) def rm_site_packages(self): site_packages_path = Path("./python/Lib/site-packages") if site_packages_path.exists(): rmtree(site_packages_path) return "site-packages目录移除成功" return "python\\Lib\\site-packages目录不存在" def rm_python_scripts(self): python_scripts_path = Path("./python/Scripts") if python_scripts_path.exists(): rmtree(python_scripts_path) return "Scripts目录移除成功" return "python\\Scripts目录不存在" def run(self, command, cwd=None): command = command_list[command] if callable(command): command = command() custom_event(command + "\n") try: with Popen( command, stdout=PIPE, stderr=STDOUT, shell=True, cwd=cwd, bufsize=0 ) as p: for data in p.stdout: try: text = data.decode("utf-8") except Exception: text = data.decode("gbk") custom_event(text) if p.returncode == 0: return "success" except Exception as e: custom_event(str(e)) return "failed" # 如果当前路径存在更新脚本,则删除 if Path(upgrade_script_name).exists(): os.remove(upgrade_script_name) window = webview.create_window(f"mower-ng launcher {version}", "ui/dist/index.html", js_api=Api()) # window = webview.create_window(f"mower-ng launcher {version}", "http://localhost:5173/", js_api=Api()) webview.start() with config_path.open("w") as f: json.dump(config, f)