install_extras.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. #!/usr/bin/env python3
  2. # /// script
  3. # dependencies = [
  4. # "httpx",
  5. # ]
  6. # ///
  7. from __future__ import annotations
  8. import os
  9. import pathlib
  10. import platform
  11. import shutil
  12. import subprocess
  13. import tarfile
  14. import zipfile
  15. import httpx
  16. CURRENT_DIR = pathlib.Path(__file__).parent
  17. def main():
  18. bat()
  19. choose()
  20. curlie()
  21. delta()
  22. dua()
  23. dust()
  24. eza()
  25. fx()
  26. git_whence()
  27. jujutsu()
  28. lazygit()
  29. oh_my_posh()
  30. procs()
  31. #starship()
  32. uv()
  33. yazi()
  34. def bat():
  35. if platform.system() == 'Darwin':
  36. print('$ brew install git-delta')
  37. subprocess.run(['brew', 'install', 'bat'], check=True)
  38. return
  39. else:
  40. assert platform.system() == 'Linux'
  41. if subprocess.run(['dpkg', '-l', 'bat'], stdout=subprocess.DEVNULL).returncode == 0:
  42. print_gray('bat package already installed')
  43. return
  44. subprocess.run(['sudo', 'apt', 'install', 'bat', '--yes'], check=True)
  45. def choose():
  46. if platform.system() == 'Darwin':
  47. print('$ brew install choose-rust')
  48. subprocess.run(['brew', 'install', 'choose-rust'], check=True)
  49. return
  50. else:
  51. assert platform.system() == 'Linux'
  52. if (CURRENT_DIR / 'choose').exists():
  53. print_gray('choose already downloaded')
  54. return
  55. client = httpx.Client()
  56. arch = platform.machine()
  57. if arch == 'arm64':
  58. arch = 'aarch64'
  59. url = f'https://github.com/theryangeary/choose/releases/latest/download/choose-{arch}-unknown-linux-gnu'
  60. download(client, url, CURRENT_DIR / 'choose')
  61. os.chmod(CURRENT_DIR / 'choose', 0o755)
  62. def curlie():
  63. if platform.system() == 'Darwin':
  64. print('$ brew install curlie')
  65. subprocess.run(['brew', 'install', 'curlie'], check=True)
  66. return
  67. if subprocess.run(['dpkg', '-l', 'curlie'], stdout=subprocess.DEVNULL).returncode == 0:
  68. print_gray('curlie package already installed')
  69. return
  70. client = httpx.Client()
  71. latest = gh_latest_version(client, 'rs', 'curlie')
  72. version = latest['tag_name'].removeprefix('v')
  73. system = platform.system().lower()
  74. arch = get_output(['dpkg', '--print-architecture'])
  75. filename = f'curlie_{version}_{system}_{arch}.deb'
  76. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  77. deb_path = CURRENT_DIR / 'curlie.deb'
  78. download(client, asset['browser_download_url'], deb_path)
  79. try:
  80. subprocess.run(['sudo', 'dpkg', '-i', deb_path], check=True)
  81. finally:
  82. os.unlink(deb_path)
  83. def delta():
  84. if platform.system() == 'Darwin':
  85. print('$ brew install git-delta')
  86. subprocess.run(['brew', 'install', 'git-delta'], check=True)
  87. return
  88. else:
  89. assert platform.system() == 'Linux'
  90. if subprocess.run(['dpkg', '-l', 'git-delta'], stdout=subprocess.DEVNULL).returncode == 0:
  91. print_gray('git-delta package already installed')
  92. return
  93. client = httpx.Client()
  94. latest = gh_latest_version(client, 'dandavison', 'delta')
  95. version = latest['name']
  96. arch = get_output(['dpkg', '--print-architecture'])
  97. filename = f'git-delta_{version}_{arch}.deb'
  98. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  99. deb_path = CURRENT_DIR / 'git-delta.deb'
  100. download(client, asset['browser_download_url'], deb_path)
  101. try:
  102. subprocess.run(['sudo', 'dpkg', '-i', deb_path], check=True)
  103. finally:
  104. os.unlink(deb_path)
  105. def dua():
  106. if platform.system() == 'Darwin':
  107. print('$ brew install dua-cli')
  108. subprocess.run(['brew', 'install', 'dua-cli'], check=True)
  109. return
  110. else:
  111. assert platform.system() == 'Linux'
  112. dua_path = CURRENT_DIR / 'dua'
  113. if dua_path.exists():
  114. print_gray('dua already downloaded')
  115. return
  116. client = httpx.Client()
  117. latest = gh_latest_version(client, 'Byron', 'dua-cli')
  118. version = latest['name']
  119. dirname = f'dua-{version}-{platform.machine()}-unknown-linux-musl'
  120. filename = dirname + '.tar.gz'
  121. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  122. tarball_path = CURRENT_DIR / 'dua.tar.gz'
  123. download(client, asset['browser_download_url'], tarball_path)
  124. with tarfile.open(tarball_path) as tar:
  125. with tar.extractfile(dirname + '/dua') as binary, dua_path.open('wb') as f: # pyright: ignore[reportOptionalContextManager]
  126. shutil.copyfileobj(binary, f)
  127. os.unlink(tarball_path)
  128. dua_path.chmod(0o755)
  129. def dust():
  130. if platform.system() == 'Darwin':
  131. print('$ brew install dust')
  132. subprocess.run(['brew', 'install', 'dust'], check=True)
  133. return
  134. else:
  135. assert platform.system() == 'Linux'
  136. dust_path = CURRENT_DIR / 'dust'
  137. if dust_path.exists():
  138. print_gray('dust already downloaded')
  139. return
  140. client = httpx.Client()
  141. latest = gh_latest_version(client, 'bootandy', 'dust')
  142. version = latest['name']
  143. dirname = f'dust-{version}-{platform.machine()}-unknown-linux-musl'
  144. filename = dirname + '.tar.gz'
  145. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  146. tarball_path = CURRENT_DIR / 'dust.tar.gz'
  147. download(client, asset['browser_download_url'], tarball_path)
  148. with tarfile.open(tarball_path) as tar:
  149. with tar.extractfile(dirname + '/dust') as binary, dust_path.open('wb') as f: # pyright: ignore[reportOptionalContextManager]
  150. shutil.copyfileobj(binary, f)
  151. os.unlink(tarball_path)
  152. dust_path.chmod(0o755)
  153. def eza():
  154. if platform.system() == 'Darwin':
  155. print('$ brew install eza')
  156. subprocess.run(['brew', 'install', 'eza'], check=True)
  157. return
  158. else:
  159. assert platform.system() == 'Linux'
  160. if (CURRENT_DIR / 'eza').exists():
  161. print_gray('eza already downloaded')
  162. return
  163. client = httpx.Client()
  164. url = f'https://github.com/eza-community/eza/releases/latest/download/eza_{platform.machine()}-unknown-linux-gnu.tar.gz'
  165. tarball_path = CURRENT_DIR / 'eza.tar.gz'
  166. download(client, url, tarball_path)
  167. with tarfile.open(tarball_path) as tar:
  168. tar.extract('./eza', CURRENT_DIR)
  169. tarball_path.unlink()
  170. def fx():
  171. if platform.system() == 'Darwin':
  172. print('$ brew install fx')
  173. subprocess.run(['brew', 'install', 'fx'], check=True)
  174. return
  175. else:
  176. assert platform.system() == 'Linux'
  177. if (CURRENT_DIR / 'fx').exists():
  178. print_gray('fx already downloaded')
  179. return
  180. client = httpx.Client()
  181. arch = platform.machine()
  182. if arch == 'aarch64':
  183. arch = 'arm64'
  184. elif arch == 'x86_64':
  185. arch = 'amd64'
  186. url = f'https://github.com/antonmedv/fx/releases/latest/download/fx_linux_{arch}'
  187. download(client, url, CURRENT_DIR / 'fx')
  188. os.chmod(CURRENT_DIR / 'fx', 0o755)
  189. def git_whence():
  190. if platform.system() == 'Darwin':
  191. print('$ brew install raylu/formulae/git-whence')
  192. subprocess.run(['brew', 'install', 'raylu/formulae/git-whence'], check=True)
  193. return
  194. else:
  195. assert platform.system() == 'Linux'
  196. if (CURRENT_DIR / 'git-whence').exists():
  197. print_gray('git-whence already downloaded')
  198. return
  199. client = httpx.Client()
  200. url = f'https://github.com/raylu/git-whence/releases/latest/download/git-whence-{platform.machine()}-unknown-linux-gnu'
  201. download(client, url, CURRENT_DIR / 'git-whence')
  202. os.chmod(CURRENT_DIR / 'git-whence', 0o755)
  203. def jujutsu():
  204. if (CURRENT_DIR / 'jj').exists():
  205. print_gray('jj already downloaded')
  206. return
  207. if platform.system() == 'Darwin':
  208. print('$ brew install jj')
  209. subprocess.run(['brew', 'install', 'jj'], check=True)
  210. return
  211. else:
  212. assert platform.system() == 'Linux'
  213. client = httpx.Client()
  214. latest = gh_latest_version(client, 'jj-vcs', 'jj')
  215. version = latest['name']
  216. arch = platform.machine()
  217. url = f'https://github.com/jj-vcs/jj/releases/download/{version}/jj-{version}-{arch}-unknown-linux-musl.tar.gz'
  218. tarball_path = CURRENT_DIR / 'jj.tar.gz'
  219. download(client, url, tarball_path)
  220. with tarfile.open(tarball_path, 'r:gz') as tar:
  221. tar.extract('./jj', CURRENT_DIR, filter='data')
  222. tarball_path.unlink()
  223. def lazygit():
  224. if (CURRENT_DIR / 'lazygit').exists():
  225. print_gray('lazygit package already installed')
  226. return
  227. client = httpx.Client()
  228. latest = gh_latest_version(client, 'jesseduffield', 'lazygit')
  229. version = latest['name']
  230. arch = platform.machine()
  231. if arch == 'aarch64':
  232. arch = 'arm64'
  233. url = f'https://github.com/jesseduffield/lazygit/releases/download/{version}/lazygit_{version.lstrip("v")}_{platform.system()}_{arch}.tar.gz'
  234. download(client, url, CURRENT_DIR / 'lazygit.tgz')
  235. with tarfile.open(CURRENT_DIR / 'lazygit.tgz', 'r:gz') as tar:
  236. tar.extract('lazygit', CURRENT_DIR)
  237. os.unlink(CURRENT_DIR / 'lazygit.tgz')
  238. def oh_my_posh():
  239. if platform.system() == 'Darwin':
  240. print('$ brew install oh-my-posh')
  241. subprocess.run(['brew', 'install', 'oh-my-posh'], check=True)
  242. return
  243. else:
  244. assert platform.system() == 'Linux'
  245. if (CURRENT_DIR / 'oh-my-posh').exists():
  246. print_gray('oh-my-posh already downloaded')
  247. return
  248. client = httpx.Client()
  249. arch = platform.machine()
  250. if arch == 'aarch64':
  251. arch = 'arm64'
  252. elif arch == 'x86_64':
  253. arch = 'amd64'
  254. url = f'https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/posh-linux-{arch}'
  255. download(client, url, CURRENT_DIR / 'oh-my-posh')
  256. os.chmod(CURRENT_DIR / 'oh-my-posh', 0o755)
  257. def procs():
  258. if (CURRENT_DIR / 'procs').exists():
  259. print_gray('procs already downloaded')
  260. return
  261. client = httpx.Client()
  262. latest = gh_latest_version(client, 'dalance', 'procs')
  263. version = latest['name']
  264. system = platform.system().lower()
  265. arch = platform.machine()
  266. if arch == 'arm64':
  267. arch = 'aarch64'
  268. if system == 'darwin':
  269. system = 'mac'
  270. name = f'procs-{version}-{arch}-{system}.zip'
  271. url = f'https://github.com/dalance/procs/releases/download/{version}/{name}'
  272. zip_path = CURRENT_DIR / 'procs.zip'
  273. download(client, url, zip_path)
  274. with zipfile.ZipFile(zip_path, 'r') as zipf:
  275. extracted = (CURRENT_DIR / 'procs')
  276. with zipf.open('procs', 'r') as binary, extracted.open('wb') as f:
  277. shutil.copyfileobj(binary, f)
  278. extracted.chmod(0o755)
  279. zip_path.unlink()
  280. def starship():
  281. if platform.system() == 'Darwin':
  282. print('$ brew install starship')
  283. subprocess.run(['brew', 'install', 'starship'], check=True)
  284. return
  285. else:
  286. assert platform.system() == 'Linux'
  287. if (CURRENT_DIR / 'starship').exists():
  288. print_gray('starship already downloaded')
  289. return
  290. client = httpx.Client()
  291. arch = platform.machine()
  292. if arch == 'x86_64':
  293. libc = 'gnu'
  294. else:
  295. libc = 'musl'
  296. url = f'https://github.com/starship/starship/releases/latest/download/starship-{arch}-unknown-linux-{libc}.tar.gz'
  297. tarball_path = CURRENT_DIR / 'starship.tar.gz'
  298. download(client, url, tarball_path)
  299. with tarfile.open(tarball_path, 'r:gz') as tar:
  300. tar.extract('starship', CURRENT_DIR)
  301. tarball_path.unlink()
  302. def uv():
  303. if (CURRENT_DIR / 'uv').exists():
  304. print_gray('uv already downloaded')
  305. return
  306. if which := shutil.which('uv'):
  307. print_gray('uv already at ' + which)
  308. return
  309. client = httpx.Client()
  310. arch = platform.machine()
  311. if arch == 'arm64':
  312. arch = 'aarch64'
  313. os = platform.system().lower()
  314. if os == 'darwin':
  315. prefix = f'uv-{arch}-apple-darwin'
  316. else:
  317. prefix = f'uv-{arch}-unknown-linux-gnu'
  318. url = f'https://github.com/astral-sh/uv/releases/latest/download/{prefix}.tar.gz'
  319. tarball_path = CURRENT_DIR / 'uv.tar.gz'
  320. download(client, url, tarball_path)
  321. with tarfile.open(tarball_path, 'r:gz') as tar:
  322. for filename in ['uv', 'uvx']:
  323. target_path = CURRENT_DIR / filename
  324. with tar.extractfile(f'{prefix}/{filename}') as binary, target_path.open('wb') as f: # pyright: ignore[reportOptionalContextManager]
  325. shutil.copyfileobj(binary, f)
  326. target_path.chmod(0o755)
  327. tarball_path.unlink()
  328. def yazi():
  329. if platform.system() == 'Darwin':
  330. print('$ brew install yazi')
  331. subprocess.run(['brew', 'install', 'yazi'], check=True)
  332. return
  333. else:
  334. assert platform.system() == 'Linux'
  335. if (CURRENT_DIR / 'yazi').exists():
  336. print_gray('yazi already downloaded')
  337. return
  338. client = httpx.Client()
  339. name = f'yazi-{platform.machine()}-unknown-linux-musl'
  340. url = f'https://github.com/sxyazi/yazi/releases/latest/download/{name}.zip'
  341. zip_path = CURRENT_DIR / 'yazi.zip'
  342. download(client, url, zip_path)
  343. with zipfile.ZipFile(zip_path, 'r') as zipf:
  344. for filename in ['ya', 'yazi']:
  345. extracted = (CURRENT_DIR / filename)
  346. with zipf.open(f'{name}/{filename}', 'r') as binary, extracted.open('wb') as f:
  347. shutil.copyfileobj(binary, f)
  348. extracted.chmod(0o755)
  349. zip_path.unlink()
  350. def get_output(argv: list[str]) -> str:
  351. proc = subprocess.run(argv, check=True, capture_output=True, encoding='ascii')
  352. return proc.stdout.rstrip('\n')
  353. def gh_latest_version(client: httpx.Client, org: str, repo: str) -> dict:
  354. r = client.get(f'https://api.github.com/repos/{org}/{repo}/releases/latest',
  355. headers={'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28'})
  356. r.raise_for_status()
  357. return r.json()
  358. def download(client: httpx.Client, url: str, path: pathlib.Path) -> None:
  359. print('downloading', url, 'to', path)
  360. with client.stream('GET', url, follow_redirects=True) as r:
  361. r.raise_for_status()
  362. with path.open('wb') as f:
  363. for chunk in r.iter_bytes():
  364. f.write(chunk)
  365. def print_gray(*args: object):
  366. print('\x1B[90;m', end='')
  367. print(*args, end='')
  368. print('\x1B[0m')
  369. if __name__ == '__main__':
  370. main()