import os import re import sys from winpty import PtyProcess class BuildAll: def __init__(self): self.current_dir = os.path.dirname(os.path.abspath(__file__)) @staticmethod def __get_python_env_name_from_args(): for arg in sys.argv[1:]: if arg.startswith("-python_env_name="): return arg.split("=")[1] return None def build_all(self): python_env_name = self.__get_python_env_name_from_args() if not python_env_name: python_env_name = input("请输入conda python环境的名称(例如:base): ") # confirm_remove = input("是否删除输出目录及其所有内容? (y/N) ").strip().lower() confirm_remove = "y" pyinstaller_confirm_flag = "-y" if confirm_remove == 'y' else "" commands = [ (f"conda activate {python_env_name} && Pyinstaller {pyinstaller_confirm_flag} -D launcher.py", self.current_dir), (f"conda activate {python_env_name} && Pyinstaller {pyinstaller_confirm_flag} -D server.py", os.path.join(self.current_dir, "server")), ("npm run build:win && echo BUILD_EXIT_WITH_NPM_RUN_END", os.path.join(self.current_dir, "client")) ] for cmd, cwd in commands: if not self.__pre_execute_check(cmd, cwd): return self.__execute_cmd_with_pty(cmd, cwd) print("Build complete!") @staticmethod def __pre_execute_check(cmd, cwd): if "Pyinstaller" in cmd: script_name = cmd.split(" ")[-1] absolute_path = os.path.join(cwd, script_name) if not os.path.exists(absolute_path): print(f"Error: Python脚本 '{absolute_path}' 不存在!") return False elif cmd.startswith("npm "): pass return True def __execute_cmd_with_pty(self, cmd, cwd=None): counter_output_is_all_none: int = 0 process = PtyProcess.spawn(["cmd", "/c", cmd], cwd=cwd) process.setwinsize(20, 9999) while process.isalive(): try: output: str = process.readline() output = self.__remove_ansi_escape_codes(output) output = self.__remove_leading_newlines(output) if output in ["", " ", "\n", "\r\n", "\n\r"]: if counter_output_is_all_none != 0: continue else: counter_output_is_all_none += 1 print("\n", end='') continue else: counter_output_is_all_none = 0 output = self.__remove_ending_newlines(output) print(output, end='\n') except EOFError: break # 当伪终端关闭时跳出循环 @staticmethod def __remove_ansi_escape_codes(s): ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') return ansi_escape.sub('', s) @staticmethod def __remove_leading_newlines(s): while s.startswith(('\n\r', '\r\n', '\n', '\r')): for seq in ['\n\r', '\r\n', '\n', '\r']: if s.startswith(seq): s = s[len(seq):] return s @staticmethod def __remove_ending_newlines(s): sequences = ['\n\r', '\r\n', '\n', '\r'] while s.endswith(tuple(sequences)): for seq in sequences: if s.endswith(seq): s = s[:-len(seq)] return s if __name__ == "__main__": builder = BuildAll() builder.build_all()