From e5ba30d4d1ae8bdf8fc791531f6ba78eda5b232d Mon Sep 17 00:00:00 2001 From: Seungjun Lee Date: Sat, 25 Jul 2026 22:50:05 +0900 Subject: [PATCH] format code & add todo --- TODO | 1 + brewfile_tool.py | 197 +++++++++++++++++++++++++++-------------------- 2 files changed, 116 insertions(+), 82 deletions(-) diff --git a/TODO b/TODO index e94f4b7..408c603 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,4 @@ Todo: ☐ Make dependency not hardcoded ☐ Pass depencency detect if package is in list + ☐ add type in brewfile_tool.py diff --git a/brewfile_tool.py b/brewfile_tool.py index 0cdaca5..a082259 100644 --- a/brewfile_tool.py +++ b/brewfile_tool.py @@ -1,25 +1,47 @@ import csv -import subprocess -import shutil import datetime -import sys import re +import shutil +import subprocess +import sys # ====== Config ====== -CSV_FILE = './apps.csv' -BREWFILE = './Brewfile' +CSV_FILE = "./apps.csv" +BREWFILE = "./Brewfile" SUPPORT_CONFIG = { - 'formula': {'token': 'brew', 'structure': lambda data: f'brew "{data["name"]}"', 'dependency': [] }, - 'cask' : {'token': 'cask', 'structure': lambda data: f'cask "{data["name"]}"', 'dependency': [] }, - 'mas': {'token': 'mas', 'structure': lambda data: f'mas "{data["name"]}", id: {data["mas_id"]}', 'dependency': [{'name': 'mas', 'script': ['brew', 'install', 'mas']}] }, - 'vscode': {'token': 'vscode', 'structure': lambda data: f'vscode "{data["name"]}"', 'dependency': [{'name': 'code', 'script': ['brew', 'install', '--cask', 'visual-studio-code']}] } + "formula": { + "token": "brew", + "structure": lambda data: f'brew "{data["name"]}"', + "dependency": [], + }, + "cask": { + "token": "cask", + "structure": lambda data: f'cask "{data["name"]}"', + "dependency": [], + }, + "mas": { + "token": "mas", + "structure": lambda data: f'mas "{data["name"]}", id: {data["mas_id"]}', + "dependency": [{"name": "mas", "script": ["brew", "install", "mas"]}], + }, + "vscode": { + "token": "vscode", + "structure": lambda data: f'vscode "{data["name"]}"', + "dependency": [ + { + "name": "code", + "script": ["brew", "install", "--cask", "visual-studio-code"], + } + ], + }, } -MANUAL_TYPE = 'manual' +MANUAL_TYPE = "manual" support_types = list(SUPPORT_CONFIG.keys()) + def clear(): - subprocess.run(['clear']) + subprocess.run(["clear"]) def check_package(name): @@ -28,124 +50,131 @@ def check_package(name): return False return True + def check_brew(): - if not check_package('brew'): - print('❌ Unable to find brew') + if not check_package("brew"): + print("❌ Unable to find brew") sys.exit() + def get_csv(): - with open(CSV_FILE, 'r', encoding='utf-8-sig') as f: + with open(CSV_FILE, "r", encoding="utf-8-sig") as f: return list(csv.DictReader(f)) + def extract_tap(name): - parts = name.split('/') + parts = name.split("/") if len(parts) == 3: - return f'{parts[0]}/{parts[1]}' + return f"{parts[0]}/{parts[1]}" return None + def create_brewfile(): try: - with open(BREWFILE, 'r') as old: - stamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') - with open(f'./Brewfile_{stamp}.backup', 'w') as new: + with open(BREWFILE, "r") as old: + stamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + with open(f"./Brewfile_{stamp}.backup", "w") as new: new.writelines(old.readlines()) - print(f'📢 Backup old Brewfile (Brewfile_{stamp}.backup)') + print(f"📢 Backup old Brewfile (Brewfile_{stamp}.backup)") except FileNotFoundError: pass raw_list = get_csv() - temp = {pkg_type:[] for pkg_type in support_types} + temp = {pkg_type: [] for pkg_type in support_types} taps = set() for row in raw_list: - pkg_type = row['type'] + pkg_type = row["type"] if pkg_type in temp.keys(): - if row['install_on_setup'] == 'yes': - tap = extract_tap(row['name']) + if row["install_on_setup"] == "yes": + tap = extract_tap(row["name"]) if tap: taps.add(tap) - content = f'# {row["description"]}\n{SUPPORT_CONFIG[pkg_type]["structure"](row)}\n' + content = f"# {row['description']}\n{SUPPORT_CONFIG[pkg_type]['structure'](row)}\n" temp[pkg_type].append(content) elif pkg_type != MANUAL_TYPE: - print(f'Error: {row["name"]} {pkg_type}') - sys.exit() + print(f"Error: {row['name']} {pkg_type}") + sys.exit() - with open(BREWFILE, 'w') as f: + with open(BREWFILE, "w") as f: if taps: - f.write(f'# {"=" * 15} tap {"=" * 15}\n') + f.write(f"# {'=' * 15} tap {'=' * 15}\n") for tap in sorted(taps): f.write(f'tap "{tap}"\n') - f.write('\n') + f.write("\n") for pkg_type in support_types: - f.write(f'# {"=" * 15} {pkg_type} {"=" * 15}\n') + f.write(f"# {'=' * 15} {pkg_type} {'=' * 15}\n") f.writelines(temp[pkg_type]) - f.write('\n') + f.write("\n") + + print("✅ Successfully created Brewfile") - print('✅ Successfully created Brewfile') def handle_untrusted_taps(): taps = set() try: - with open(BREWFILE, 'r') as f: + with open(BREWFILE, "r") as f: for line in f: m = re.fullmatch(r'tap "([^/]+/[^/]+)"', line.strip()) if m: taps.add(m.group(1)) except FileNotFoundError: - print('❌ Unable to find Brewfile (create it first)') + print("❌ Unable to find Brewfile (create it first)") return False if taps: - print('⚠️ These third-party taps are needed') + print("⚠️ These third-party taps are needed") for tap in sorted(taps): - print(f' - {tap}') - print(' These taps is not official and my execute certain script.\n') - if input('Trust these taps? (y/N): ').strip().lower() !='y': - print('📢 Operation is canceled as these taps are not allowed.') + print(f" - {tap}") + print(" These taps is not official and my execute certain script.\n") + if input("Trust these taps? (y/N): ").strip().lower() != "y": + print("📢 Operation is canceled as these taps are not allowed.") return False for tap in sorted(taps): try: - subprocess.run(['brew', 'tap', tap], check=True) - subprocess.run(['brew', 'trust', tap], check=True) + subprocess.run(["brew", "tap", tap], check=True) + subprocess.run(["brew", "trust", tap], check=True) print(f'✅ Successfully installed tap "{tap}"') except subprocess.CalledProcessError as e: print(f'❌ Failed to install tap "{tap}" ({e.returncode})') return False except FileNotFoundError: - print('❌ Unable to find brew') + print("❌ Unable to find brew") return False return True + def get_brewfile_types(): - token_to_type = {SUPPORT_CONFIG[t]['token']: t for t in support_types} + token_to_type = {SUPPORT_CONFIG[t]["token"]: t for t in support_types} types = set() try: - with open(BREWFILE, 'r') as f: + with open(BREWFILE, "r") as f: for line in f: - token = line.strip().split(' ', 1)[0] + token = line.strip().split(" ", 1)[0] if token in token_to_type: types.add(token_to_type[token]) except FileNotFoundError: - print('❌ Unable to find Brewfile (create it first)') + print("❌ Unable to find Brewfile (create it first)") return types + def install_dependencies(): dependencies = [] seen = set() for pkg_type in get_brewfile_types(): - for dep in SUPPORT_CONFIG[pkg_type]['dependency']: - if dep['name'] not in seen: - seen.add(dep['name']) + for dep in SUPPORT_CONFIG[pkg_type]["dependency"]: + if dep["name"] not in seen: + seen.add(dep["name"]) dependencies.append(dep) for dep in dependencies: - if check_package(dep['name']): + if check_package(dep["name"]): print(f'✅ Dependency "{dep["name"]}" already installed') continue print(f'📢 Installing missing dependency "{dep["name"]}"...') try: - subprocess.run(dep['script'], check=True) + subprocess.run(dep["script"], check=True) print(f'✅ Successfully installed dependency "{dep["name"]}"') except subprocess.CalledProcessError as e: print(f'❌ Failed to install dependency "{dep["name"]}" ({e.returncode})') @@ -155,79 +184,82 @@ def install_dependencies(): return False return True + def bundle_install(): if not handle_untrusted_taps(): return if not install_dependencies(): - print('❌ Aborting install due to missing dependency') + print("❌ Aborting install due to missing dependency") return try: - subprocess.run(['brew', 'bundle', 'install', f'--file={BREWFILE}'], check=True) - print('✅ Successfully install all packages') + subprocess.run(["brew", "bundle", "install", f"--file={BREWFILE}"], check=True) + print("✅ Successfully install all packages") except subprocess.CalledProcessError as e: - print(f'❌ Failed to install some packages ({e.returncode})') + print(f"❌ Failed to install some packages ({e.returncode})") except FileNotFoundError: - print('❌ Unable to find brew') + print("❌ Unable to find brew") def bundle_check(): try: - print('📢 Check script running') + print("📢 Check script running") result = subprocess.run( - ['brew', 'bundle', 'check', f'--file={BREWFILE}', '--verbose'] + ["brew", "bundle", "check", f"--file={BREWFILE}", "--verbose"] ) if result.returncode == 0: - print('✅ All packages are installed') + print("✅ All packages are installed") return True else: - print('⚠️ There are uninstalled package(s)') + print("⚠️ There are uninstalled package(s)") return False except FileNotFoundError: - print('❌ Unable to find brew') + print("❌ Unable to find brew") return False - def bundle_cleanup(): try: - subprocess.run(['brew', 'bundle', 'cleanup', f'--file={BREWFILE}']) - if input('⚠️ Are sure to remove? (y/N): ').strip().lower() == 'y': - subprocess.run(['brew', 'bundle', 'cleanup', f'--file={BREWFILE}', '--force'], check=True) - print('✅ Successfully cleanup') + subprocess.run(["brew", "bundle", "cleanup", f"--file={BREWFILE}"]) + if input("⚠️ Are sure to remove? (y/N): ").strip().lower() == "y": + subprocess.run( + ["brew", "bundle", "cleanup", f"--file={BREWFILE}", "--force"], + check=True, + ) + print("✅ Successfully cleanup") else: - print('📢 Canceled') + print("📢 Canceled") except subprocess.CalledProcessError as e: - print(f'❌ Failed to cleanup ({e.returncode})') + print(f"❌ Failed to cleanup ({e.returncode})") except FileNotFoundError: - print('❌ Unable to find brew') + print("❌ Unable to find brew") def select_option(): options = [ - {'text': 'Create Brewfile', 'func': create_brewfile}, - {'text': 'Install packages', 'func': bundle_install}, - {'text': 'Check packages', 'func': bundle_check}, - {'text': 'Cleanup packages', 'func': bundle_cleanup}, - {'text': 'Exit', 'func': sys.exit} + {"text": "Create Brewfile", "func": create_brewfile}, + {"text": "Install packages", "func": bundle_install}, + {"text": "Check packages", "func": bundle_check}, + {"text": "Cleanup packages", "func": bundle_cleanup}, + {"text": "Exit", "func": sys.exit}, ] while True: - print('Select option') + print("Select option") for idx, row in enumerate(options, 1): - print(f' {idx}) {row["text"]}') - raw = input('option: ').strip() + print(f" {idx}) {row['text']}") + raw = input("option: ").strip() try: clear() idx = int(raw) - 1 if 0 <= idx < len(options): - options[idx]['func']() + options[idx]["func"]() print() return else: - print('⚠️ Write valid number\n') + print("⚠️ Write valid number\n") except ValueError: - print('⚠️ Write valid number\n') + print("⚠️ Write valid number\n") def main(): @@ -235,5 +267,6 @@ def main(): while True: select_option() -if __name__ == '__main__': + +if __name__ == "__main__": main()