import subprocess import toml import sys import re import os def get_latest_tag(): t = subprocess.check_output(['git', 'tag', '--sort=v:refname']).decode('utf-8').strip().split("\n") return t[-1] if (t[-1] != toml.load("./pyproject.toml")["tool"]["poetry"]["version"]) else t[-2] def get_specified_tag(index): r = subprocess.check_output(['git', 'tag', '--sort=v:refname']).decode('utf-8').strip().split("\n") n = [] for i in r: if (i): n.append(i.strip()) return n[index] def get_changelog(): cmd = ['git', 'log', f'{get_specified_tag(-1)}..HEAD', '--pretty=format:"%h %s"'] # print(cmd) res = subprocess.check_output(cmd).decode('utf-8').strip() res = res.split('\n') featMsg = [] fixMsg = [] docsMsg = [] buildMsg = [] otherMsg = [] noticeMsg = [] unknownMsg = [] for msg in res: if (re.match('[a-f0-9]*.(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|notice).*?\(?.*?\)?\:', msg[1:-1])): msg = msg[1:-1] if msg[8:].startswith('notice'): noticeMsg.append(msg) elif msg[8:].startswith('feat'): featMsg.append(msg) elif msg[8:].startswith('fix'): fixMsg.append(msg) elif msg[8:].startswith('docs'): docsMsg.append(msg) elif msg[8:].startswith('build'): buildMsg.append(msg) else: otherMsg.append(msg) else: msg = msg[1:-1] unknownMsg.append(msg) # final Nres = '' if (len(noticeMsg) > 0): Nres += '## 公告\n' for msg in noticeMsg: Nres += f'- {msg}\n' if (len(featMsg) > 0): Nres += '## 功能更新\n' for msg in featMsg: Nres += f'- {msg}\n' if (len(fixMsg) > 0): Nres += '## bug修复\n' for msg in fixMsg: Nres += f'- {msg}\n' if (len(docsMsg) > 0): Nres += '## 文档更新\n' for msg in docsMsg: Nres += f'- {msg}\n' if (len(unknownMsg) > 0): Nres += '## 未知类型的提交\n' for msg in unknownMsg: Nres += f'- {msg}\n' if (len(buildMsg) > 0): Nres += '## 构建配置\n' for msg in buildMsg: Nres += f'- {msg}\n' if (len(otherMsg) > 0): Nres += '## 其他\n' for msg in otherMsg: Nres += f'- {msg}\n' return Nres.strip() def get_python_path(): return sys.executable def get_latest_commit_sha(): return subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode('utf-8').strip()[0:7] def build_test(fileName): os.environ['build'] = 'T' try: import PyInstaller as UNUSED except ModuleNotFoundError: print('[ERROR]: Please install PyInstaller module first.', 'If you have the module installed,', 'Please check if you forgetting to activate the virtualenv.', sep='\n') sys.exit(1) sha = get_latest_commit_sha() popen = subprocess.Popen([get_python_path(), '-m', 'PyInstaller', '-F', '-i', 'res/icon.ico', '--name', fileName if fileName else f'lx-music-api-server_{sha}', 'main.py']) print('PyInstaller process started, PID: ' + str(popen.pid)) print('Please wait for a while...') popen.wait() if (popen.returncode != 0): print(f'[ERROR]: PyInstaller build with code {popen.returncode}.', 'Please check the output log,', 'this may inculde errors or warnings.', sep='\n') sys.exit(popen.returncode) else: print('[SUCCESS]: PyInstaller build success.') print('FilePath: ' + os.getcwd() + os.sep + os.listdir(os.getcwd() + '/dist')[0]) def build_release(fileName = ''): os.environ['build'] = 'R' try: import PyInstaller as UNUSED except ModuleNotFoundError: print('[ERROR]: Please install PyInstaller module first.', 'If you have the module installed,', 'Please check if you forgetting to activate the virtualenv.', sep='\n') sys.exit(1) vername = toml.load("./pyproject.toml")["tool"]["poetry"]["version"] popen = subprocess.Popen([get_python_path(), '-m', 'PyInstaller', '-F', '-i', 'res/icon.ico', '--name', fileName if fileName else f'lx-music-api-server_{vername}', 'main.py']) print('PyInstaller process started, PID: ' + str(popen.pid)) print('Please wait for a while...') popen.wait() if (popen.returncode != 0): print(f'[ERROR]: PyInstaller build with code {popen.returncode}.', 'Please check the output log,', 'this may inculde errors or warnings.', sep='\n') sys.exit(popen.returncode) else: print('[SUCCESS]: PyInstaller build success.') print('FilePath: ' + os.getcwd() + os.sep + os.listdir(os.getcwd() + '/dist')[0]) argv = sys.argv argv.pop(0) commands = [] options = [] further_info_required_options = ['-f', '--fileName'] for arg in argv: if (arg.startswith('-')): options.append(arg) if (arg in further_info_required_options): options.append(argv[argv.index(arg) + 1]) else: if (arg not in options): commands.append(arg) def main(): fileName = '' for o in options: if (o == '-f' or o == '--fileName'): try: fileName = options[options.index(o) + 1] except: print('[ERROR] No fileName specified') sys.exit(1) elif (o == '-h' or o == '--help'): print('Usage: build.py [options] ') print('Options:') print(' -f, --filename Specify the fileName of the executable.') print(' -h, --help Show this help message and exit.') print('Commands:') print(' build test Build test executable.') print(' build release Build release executable.') print(' changelog Show changelog.') sys.exit(0) elif (o.startswith('-')): print(f'[ERROR] Invalid option "{o}" specified.') sys.exit(1) if (len(commands) == 0): print('[ERROR] No command specified') sys.exit(0) try: if (commands[0] == 'build'): if (len(commands) == 1): print('[WARNING] No build command specified, defaulting to build test.') build_test(fileName) sys.exit(0) elif (commands[1] == 'test'): build_test(fileName) sys.exit(0) elif (commands[1] == 'release'): build_release(fileName) sys.exit(0) else: print('[ERROR] Invalid build command specified.') sys.exit(1) elif (commands[0] == 'changelog'): print(get_changelog()) sys.exit(0) else: print('[ERROR] Invalid command specified.') sys.exit(1) except IndexError: print('[ERROR] Invalid command specified.') sys.exit(1) if __name__ == '__main__': try: main() except KeyboardInterrupt: print('[INFO] Aborting...') sys.exit(0)