commit e8f6113d6a922064c3436c7c85fd15f40196199a Author: seung6lee Date: Tue Jul 14 23:50:05 2026 +0900 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bab06b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +Brewfile +Brewfile_*.backup +.DS_Store \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 0000000..e94f4b7 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ + +Todo: + ☐ Make dependency not hardcoded + ☐ Pass depencency detect if package is in list diff --git a/__pycache__/brewfile_tool.cpython-314.pyc b/__pycache__/brewfile_tool.cpython-314.pyc new file mode 100644 index 0000000..0c1b8fe Binary files /dev/null and b/__pycache__/brewfile_tool.cpython-314.pyc differ diff --git a/apps.csv b/apps.csv new file mode 100644 index 0000000..f12f044 --- /dev/null +++ b/apps.csv @@ -0,0 +1,94 @@ +ο»Ώname,type,mas_id,install_on_setup,category,description,price +ente-auth,cask,,yes,security,Free secure two-factor auth service,free +android-platform-tools,cask,,no,utilities,ADB tools,free +sozercan/repo/kaset,cask,,yes,media,MacOS YTM client,free +latest,cask,,yes,utilities,Check all app update,free +localsend,cask,,no,network,Share file between devices,free +modern-csv,cask,,no,development,CSV viewer for large file,free +motrix,cask,,no,network,Torrent download client,free +orbstack,cask,,yes,development,Docker replacement,free +pika,cask,,yes,utilities,Color picker,free +timescribe,cask,,yes,productivity,Time and App usage tracker,free +warp,cask,,yes,development,Best Terminal,free +fluent-reader,cask,,yes,productivity,RSS Reader,free +lunacy,cask,,yes,creativity,Figma alternative,free +zen,cask,,yes,productivity,Firefox based main browser,free +opencloud,cask,,yes,network,Opencloud desktop client,free +raycast,cask,,yes,personalization,Superior version of spotlight,free +claude,cask,,yes,ai,Claude desktop client,free +lookaway,cask,,yes,personalization,Eye protection,paid +notion,cask,,yes,knowledge,Notion desktop client,free +visual-studio-code,cask,,yes,development,Code editor,free +maccy,cask,,yes,personalization,Clipboard manager,free +iina,cask,,yes,media,Media player,free +itsycal,cask,,yes,personalization,Menubar calendar app,free +sidenotes,cask,,yes,knowledge,Sidepanel note app,paid +rectangle,cask,,yes,personalization,Window management tool,free +karabiner-elements,cask,,yes,personalization,Keyboard customization tool,free +zotero,cask,,no,knowledge,Reference organize tool,free +affine,cask,,yes,knowledge,Opensource notion alternative,free +busycontacts,cask,,yes,productivity,Contact management tool with CalDAV support,paid +affinity,cask,,yes,creativity,Photoshop alternative by canva,free +discord,cask,,yes,social,Discord desktop client,free +shifty,cask,,yes,personalization,Night shift adjust tool,free +keka,cask,,yes,utilities,File extraction enhancer,free +keyboardcleantool,cask,,yes,utilities,Lock keyboard input during cleaning,free +appcleaner,cask,,yes,utilities,Remove app without residue,free +monitorcontrol,cask,,yes,personalization,Control external monitor brightness,free +alcove,cask,,yes,personalization,Notch app,paid +tunnelbear,cask,,yes,network,VPN,free +arduino-ide,cask,,no,development,Arduino IDE,free +clop,cask,,yes,personalization,File compressor,free +insomnia,cask,,yes,development,API tester,free +obsidian,cask,,yes,knowledge,Knowledge management tool,free +openmtp,cask,,yes,utilities,Android device connector,free +responsively,cask,,no,development,Browser for responsible website development,free +telegram,cask,,yes,social,Telegram desktop client,free +wireshark-app,cask,,no,network,Network packets capturer,free +git,formula,,yes,development,Version management tool,free +mole,formula,,yes,utilities,System optimizer,free +fastfetch,formula,,yes,utilities,Neofetch alternative,free +mas,formula,,yes,utilities,CLI appstore,free +tree,formula,,yes,utilities,File structure tree,free +scrcpy,formula,,no,utilities,Android screen mirroring,free +thaw,formula,,yes,personalization,Menubar hidder,free +nmap,formula,,no,network,Network scanner,free +davinci resolve ,manual,,no,creativity,Video editor,free +reef,manual,,no,personalization,"Shortcuts based app switcher +https://github.com/gouwsxander/Reef",free +tageditor,mas,984278082,no,utilities,Audio file metadata editor,free +Allkdic,mas,1033453958,yes,productivity,Menubar dictionary,free +Bitwarden,mas,1352778147,yes,security,Password manager,free +Hancom Office HWP Viewer,mas,416746898,yes,productivity,Hancom Office HWP Viewer,free +KakaoTalk,mas,869223134,yes,social,KakaoTalk,free +Linearity Curve,mas,1219074514,no,creativity,Vector based design tool,free +Poolsuite FM,mas,1514817810,no,media,Internet music radio,free +Print to PDF,mas,1639234272,yes,utilities,Save pdf to file,free +RunCat,mas,1429033973,yes,personalization,Menubar system usage visualizer,free +Texty,mas,1538996043,yes,social,Third-party google chat desktop client,free +Windows App,mas,1295203466,yes,productivity,Windows RDP client,free +WireGuard,mas,1451685025,yes,network,Wireguard client,free +Xcode,mas,497799835,no,development,Xcode,free +anthropic.claude-code,vscode,,yes,tool,Claude integration,free +bierner.markdown-mermaid,vscode,,yes,integration,Support mermaid,free +esbenp.prettier-vscode,vscode,,yes,format,Formatter,free +fabiospampinato.vscode-todo-plus,vscode,,yes,tool,Todo management,free +formulahendry.code-runner,vscode,,yes,tool,Code runner with shortcuts support,free +inferrinizzard.prettier-sql-vscode,vscode,,yes,format,SQL formatter,free +james-yu.latex-workshop,vscode,,yes,integration,Latex integration,free +marp-team.marp-vscode,vscode,,no,integration,Support marp(MD based presentation),free +matt-meyers.vscode-dbml,vscode,,yes,integration,Support DBML,free +mechatroner.rainbow-csv,vscode,,yes,format,CSV highlighter,free +ms-azuretools.vscode-containers,vscode,,yes,tool,Container tool,free +ms-python.black-formatter,vscode,,yes,format,Python formatter,free +ms-python.python,vscode,,yes,language,Python integration,free +ms-vscode-remote.remote-ssh,vscode,,yes,tool,SSH conntection,free +pkief.material-icon-theme,vscode,,yes,theme,Best icon,free +pkief.material-product-icons,vscode,,yes,theme,Best product icon,free +pomdtr.excalidraw-editor,vscode,,no,integration,Excalidraw integration,free +rickaym.manim-sideview,vscode,,no,integration,Manim integration,free +ritwickdey.liveserver,vscode,,no,tool,Web frontend live server,free +svelte.svelte-vscode,vscode,,yes,language,Sevelte integration,free +wayou.vscode-todo-highlight,vscode,,yes,tool,Todo file highlighter,free +yzhang.markdown-all-in-one,vscode,,yes,language,Markdown highlighter & formatter,free +zhuangtongfa.material-theme,vscode,,yes,theme,Best darkmode theme (One Dark Pro),free \ No newline at end of file diff --git a/brewfile_tool.py b/brewfile_tool.py new file mode 100644 index 0000000..3d81cf4 --- /dev/null +++ b/brewfile_tool.py @@ -0,0 +1,185 @@ +# ====== Config ====== +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']}] } +} +MANUAL_TYPE = 'manual' + +support_types = list(SUPPORT_CONFIG.keys()) + + +import csv +import subprocess +import shutil +import datetime +import sys + +clear = lambda: subprocess.run(['clear']) + +def check_package(name): + path = shutil.which(name) + if not path: + return False + return True + +def check_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: + return list(csv.DictReader(f)) + +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: + new.writelines(old.readlines()) + print(f'πŸ“’ Backup old Brewfile (Brewfile_{stamp}.backup)') + except FileNotFoundError: + pass + + raw_list = get_csv() + temp = {pkg_type:[] for pkg_type in support_types} + + for row in raw_list: + pkg_type = row['type'] + if pkg_type in temp.keys(): + if row['install_on_setup'] == 'yes': + 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() + + with open(BREWFILE, 'w') as f: + for pkg_type in support_types: + f.write(f'# {"=" * 15} {pkg_type} {"=" * 15}\n') + f.writelines(temp[pkg_type]) + f.write('\n') + + print('βœ… Successfully create Brewfile') + +def get_brewfile_types(): + token_to_type = {SUPPORT_CONFIG[t]['token']: t for t in support_types} + types = set() + try: + with open(BREWFILE, 'r') as f: + for line in f: + 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)') + 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']) + dependencies.append(dep) + + for dep in dependencies: + 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) + print(f'βœ… Successfully installed dependency "{dep["name"]}"') + except subprocess.CalledProcessError as e: + print(f'❌ Failed to install dependency "{dep["name"]}" ({e.returncode})') + return False + except FileNotFoundError: + print(f'❌ Unable to find command to install dependency "{dep["name"]}"') + return False + return True + +def bundle_install(): + if not install_dependencies(): + print('❌ Aborting install due to missing dependency') + return + + try: + 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})') + except FileNotFoundError: + print('❌ Unable to find brew') + + +def bundle_check(): + try: + print('πŸ“’ Check script running') + result = subprocess.run( + ['brew', 'bundle', 'check', f'--file={BREWFILE}', '--verbose'] + ) + if result.returncode == 0: + print('βœ… Every packages are installed') + return True + else: + print('⚠️ There are uninstalled package(s)') + return False + except FileNotFoundError: + print('❌ Unable to find brew') + return False + + + +def bundle_cleanup(): + try: + subprocess.run(['brew', 'bundle', 'cleanup', f'--file={BREWFILE}']) + if input('⚠️ Are sure want to remove? (y/N): ').strip().lower() == 'y': + subprocess.run(['brew', 'bundle', 'cleanup', f'--file={BREWFILE}', '--force'], check=True) + print('βœ… Successfully cleanup') + else: + print('πŸ“’ Canceled') + except subprocess.CalledProcessError as e: + print(f'❌ Failed to cleanup ({e.returncode})') + except FileNotFoundError: + 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} + ] + while True: + print('Select option') + for idx, row in enumerate(options, 1): + print(f' {idx}) {row["text"]}') + raw = input('option: ').strip() + try: + clear() + idx = int(raw) - 1 + if 0 <= idx < len(options): + options[idx]['func']() + print() + return + else: + print(f'⚠️ Write valid number\n') + except ValueError as e: + print(f'⚠️ Write valid number\n') + + +def main(): + check_brew() + while True: + select_option() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/notes/brew.md b/notes/brew.md new file mode 100644 index 0000000..c4b4203 --- /dev/null +++ b/notes/brew.md @@ -0,0 +1,79 @@ +## Installation / Uninstallation +```sh +brew install # CLI +brew install --cask # GUI +brew uninstall # Uninstall +brew uninstall --zap --cask # Uninstall including cask config +brew reinstall +``` + +## Search +```sh +brew search # List matching packages (formula + cask) +brew info # detailed info +brew home # Open homepage +``` + +## List +```sh +brew list +brew list --formula +brew list --cask +brew list --versions # version of specific package +brew leaves # List only user installed (not dependencies) +brew deps # List dependencies +brew uses --installed # List packages that use this package +``` + +## Update / Upgrade +```sh +brew update +brew upgrade +brew upgrade +brew outdated # List upgradable packages +``` + +## Pin version +```sh +brew pin # Pin specific package version to currently installed one +brew unpin +``` + +## Cleanup +```sh +brew cleanup # Remove order version, cache +brew cleanup --prune=all # Remove all cache +brew autoremove # remove abandoned dependencies +brew doctor # detect problem +brew missing # find omitted dependencies +``` + +## Repo +```sh +brew tap # List all repo +brew tap # add repo +brew untap # remove repo +``` + +## Bundle +```sh +brew bundle dump # Export list of current installation +brew bundle install # Install via Brewfile +brew bundle check # Compare between cur status and Brewfile +brew bundle cleanup --force # Remove packages that are not in the Brewfile +``` + +## Services +```sh +brew services list +brew services start # run + autostart on boot +brew services stop +brew services restart +brew services run # run only once +``` + +## Miscellaneous +```sh +brew --prefix # Get brew path +brew --prefix # Get package path +``` \ No newline at end of file diff --git a/notes/category.txt b/notes/category.txt new file mode 100644 index 0000000..bdc5336 --- /dev/null +++ b/notes/category.txt @@ -0,0 +1,19 @@ +# Formula, Cask, MAS +creativity +development +ai +utilities +media +network +knowledge +productivity +security +social +personalization + +# VScode Extension +language +format +theme +integration +tool \ No newline at end of file