initial commit
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user