install_extras.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #!/usr/bin/env python3
  2. from __future__ import annotations
  3. import os
  4. import pathlib
  5. import platform
  6. import shutil
  7. import subprocess
  8. import tarfile
  9. import httpx
  10. CURRENT_DIR = pathlib.Path(__file__).parent
  11. def main():
  12. bat()
  13. delta()
  14. dua()
  15. dust()
  16. eza()
  17. fx()
  18. git_whence()
  19. jujutsu()
  20. lazygit()
  21. oh_my_posh()
  22. starship()
  23. def bat():
  24. if platform.system() == 'Darwin':
  25. print('$ brew install git-delta')
  26. subprocess.run(['brew', 'install', 'bat'], check=True)
  27. return
  28. else:
  29. assert platform.system() == 'Linux'
  30. if subprocess.run(['dpkg', '-l', 'bat'], stdout=subprocess.DEVNULL).returncode == 0:
  31. print_gray('bat package already installed')
  32. return
  33. subprocess.run(['sudo', 'apt', 'install', 'bat', '--yes'], check=True)
  34. def delta():
  35. if platform.system() == 'Darwin':
  36. print('$ brew install git-delta')
  37. subprocess.run(['brew', 'install', 'git-delta'], check=True)
  38. return
  39. else:
  40. assert platform.system() == 'Linux'
  41. if subprocess.run(['dpkg', '-l', 'git-delta'], stdout=subprocess.DEVNULL).returncode == 0:
  42. print_gray('git-delta package already installed')
  43. return
  44. client = httpx.Client()
  45. latest = gh_latest_version(client, 'dandavison', 'delta')
  46. version = latest['name']
  47. arch = get_output(['dpkg', '--print-architecture'])
  48. filename = f'git-delta_{version}_{arch}.deb'
  49. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  50. deb_path = CURRENT_DIR / 'git-delta.deb'
  51. download(client, asset['browser_download_url'], deb_path)
  52. try:
  53. subprocess.run(['sudo', 'dpkg', '-i', deb_path], check=True)
  54. finally:
  55. os.unlink(deb_path)
  56. def dua():
  57. if platform.system() == 'Darwin':
  58. print('$ brew install dua-cli')
  59. subprocess.run(['brew', 'install', 'dua-cli'], check=True)
  60. return
  61. else:
  62. assert platform.system() == 'Linux'
  63. dua_path = CURRENT_DIR / 'dua'
  64. if dua_path.exists():
  65. print_gray('dua already downloaded')
  66. return
  67. client = httpx.Client()
  68. latest = gh_latest_version(client, 'Byron', 'dua-cli')
  69. version = latest['name']
  70. dirname = f'dua-{version}-{platform.machine()}-unknown-linux-musl'
  71. filename = dirname + '.tar.gz'
  72. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  73. tarball_path = CURRENT_DIR / 'dua.tar.gz'
  74. download(client, asset['browser_download_url'], tarball_path)
  75. with tarfile.open(tarball_path) as tar:
  76. with tar.extractfile(dirname + '/dua') as binary, dua_path.open('wb') as f: # pyright: ignore[reportOptionalContextManager]
  77. shutil.copyfileobj(binary, f)
  78. os.unlink(tarball_path)
  79. dua_path.chmod(0o755)
  80. def dust():
  81. if platform.system() == 'Darwin':
  82. print('$ brew install dust')
  83. subprocess.run(['brew', 'install', 'dust'], check=True)
  84. return
  85. else:
  86. assert platform.system() == 'Linux'
  87. dust_path = CURRENT_DIR / 'dust'
  88. if dust_path.exists():
  89. print_gray('dust already downloaded')
  90. return
  91. client = httpx.Client()
  92. latest = gh_latest_version(client, 'bootandy', 'dust')
  93. version = latest['name']
  94. dirname = f'dust-{version}-{platform.machine()}-unknown-linux-musl'
  95. filename = dirname + '.tar.gz'
  96. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  97. tarball_path = CURRENT_DIR / 'dust.tar.gz'
  98. download(client, asset['browser_download_url'], tarball_path)
  99. with tarfile.open(tarball_path) as tar:
  100. with tar.extractfile(dirname + '/dust') as binary, dust_path.open('wb') as f: # pyright: ignore[reportOptionalContextManager]
  101. shutil.copyfileobj(binary, f)
  102. os.unlink(tarball_path)
  103. dust_path.chmod(0o755)
  104. def eza():
  105. if platform.system() == 'Darwin':
  106. print('$ brew install eza')
  107. subprocess.run(['brew', 'install', 'eza'], check=True)
  108. return
  109. else:
  110. assert platform.system() == 'Linux'
  111. if (CURRENT_DIR / 'eza').exists():
  112. print_gray('eza already downloaded')
  113. return
  114. client = httpx.Client()
  115. url = f'https://github.com/eza-community/eza/releases/latest/download/eza_{platform.machine()}-unknown-linux-gnu.tar.gz'
  116. tarball_path = CURRENT_DIR / 'eza.tar.gz'
  117. download(client, url, tarball_path)
  118. with tarfile.open(tarball_path) as tar:
  119. tar.extract('./eza', CURRENT_DIR)
  120. tarball_path.unlink()
  121. def fx():
  122. if platform.system() == 'Darwin':
  123. print('$ brew install fx')
  124. subprocess.run(['brew', 'install', 'fx'], check=True)
  125. return
  126. else:
  127. assert platform.system() == 'Linux'
  128. if (CURRENT_DIR / 'fx').exists():
  129. print_gray('fx already downloaded')
  130. return
  131. client = httpx.Client()
  132. arch = platform.machine()
  133. if arch == 'aarch64':
  134. arch = 'arm64'
  135. url = f'https://github.com/antonmedv/fx/releases/latest/download/fx_linux_{arch}'
  136. download(client, url, CURRENT_DIR / 'fx')
  137. os.chmod(CURRENT_DIR / 'fx', 0o755)
  138. def git_whence():
  139. if platform.system() == 'Darwin':
  140. print('$ brew install raylu/formulae/git-whence')
  141. subprocess.run(['brew', 'install', 'raylu/formulae/git-whence'], check=True)
  142. return
  143. else:
  144. assert platform.system() == 'Linux'
  145. if (CURRENT_DIR / 'git-whence').exists():
  146. print_gray('git-whence already downloaded')
  147. return
  148. client = httpx.Client()
  149. url = f'https://github.com/raylu/git-whence/releases/latest/download/git-whence-{platform.machine()}-unknown-linux-gnu'
  150. download(client, url, CURRENT_DIR / 'git-whence')
  151. os.chmod(CURRENT_DIR / 'git-whence', 0o755)
  152. def jujutsu():
  153. if platform.system() == 'Darwin':
  154. print('$ brew install jj')
  155. subprocess.run(['brew', 'install', 'jj'], check=True)
  156. return
  157. else:
  158. assert platform.system() == 'Linux'
  159. if (CURRENT_DIR / 'jj').exists():
  160. print_gray('jj already downloaded')
  161. return
  162. client = httpx.Client()
  163. latest = gh_latest_version(client, 'jj-vcs', 'jj')
  164. version = latest['name']
  165. arch = platform.machine()
  166. url = f'https://github.com/jj-vcs/jj/releases/download/{version}/jj-{version}-{arch}-unknown-linux-musl.tar.gz'
  167. tarball_path = CURRENT_DIR / 'jj.tar.gz'
  168. download(client, url, tarball_path)
  169. with tarfile.open(tarball_path, 'r:gz') as tar:
  170. tar.extract('./jj', CURRENT_DIR, filter='data')
  171. tarball_path.unlink()
  172. def lazygit():
  173. if (CURRENT_DIR / 'lazygit').exists():
  174. print_gray('lazygit package already installed')
  175. return
  176. client = httpx.Client()
  177. latest = gh_latest_version(client, 'jesseduffield', 'lazygit')
  178. version = latest['name']
  179. arch = platform.machine()
  180. if arch == 'aarch64':
  181. arch = 'arm64'
  182. url = f'https://github.com/jesseduffield/lazygit/releases/download/{version}/lazygit_{version.lstrip("v")}_{platform.system()}_{arch}.tar.gz'
  183. download(client, url, CURRENT_DIR / 'lazygit.tgz')
  184. with tarfile.open(CURRENT_DIR / 'lazygit.tgz', 'r:gz') as tar:
  185. tar.extract('lazygit', CURRENT_DIR)
  186. os.unlink(CURRENT_DIR / 'lazygit.tgz')
  187. def oh_my_posh():
  188. if platform.system() == 'Darwin':
  189. print('$ brew install oh-my-posh')
  190. subprocess.run(['brew', 'install', 'oh-my-posh'], check=True)
  191. return
  192. else:
  193. assert platform.system() == 'Linux'
  194. if (CURRENT_DIR / 'oh-my-posh').exists():
  195. print_gray('oh-my-posh already downloaded')
  196. return
  197. client = httpx.Client()
  198. arch = platform.machine()
  199. if arch == 'aarch64':
  200. arch = 'arm64'
  201. elif arch == 'x86_64':
  202. arch = 'amd64'
  203. url = f'https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/posh-linux-{arch}'
  204. download(client, url, CURRENT_DIR / 'oh-my-posh')
  205. os.chmod(CURRENT_DIR / 'oh-my-posh', 0o755)
  206. def starship():
  207. if platform.system() == 'Darwin':
  208. print('$ brew install starship')
  209. subprocess.run(['brew', 'install', 'starship'], check=True)
  210. return
  211. else:
  212. assert platform.system() == 'Linux'
  213. if (CURRENT_DIR / 'starship').exists():
  214. print_gray('starship already downloaded')
  215. return
  216. client = httpx.Client()
  217. arch = platform.machine()
  218. if arch == 'x86_64':
  219. libc = 'gnu'
  220. else:
  221. libc = 'musl'
  222. url = f'https://github.com/starship/starship/releases/latest/download/starship-{arch}-unknown-linux-{libc}.tar.gz'
  223. tarball_path = CURRENT_DIR / 'starship.tar.gz'
  224. download(client, url, tarball_path)
  225. with tarfile.open(tarball_path, 'r:gz') as tar:
  226. tar.extract('starship', CURRENT_DIR)
  227. tarball_path.unlink()
  228. def get_output(argv: list[str]) -> str:
  229. proc = subprocess.run(argv, check=True, capture_output=True, encoding='ascii')
  230. return proc.stdout.rstrip('\n')
  231. def gh_latest_version(client: httpx.Client, org: str, repo: str) -> dict:
  232. r = client.get(f'https://api.github.com/repos/{org}/{repo}/releases/latest',
  233. headers={'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28'})
  234. r.raise_for_status()
  235. return r.json()
  236. def download(client: httpx.Client, url: str, path: pathlib.Path) -> None:
  237. print('downloading', url, 'to', path)
  238. with client.stream('GET', url, follow_redirects=True) as r:
  239. r.raise_for_status()
  240. with path.open('wb') as f:
  241. for chunk in r.iter_bytes():
  242. f.write(chunk)
  243. def print_gray(*args: object):
  244. print('\x1B[90;m', end='')
  245. print(*args, end='')
  246. print('\x1B[0m')
  247. if __name__ == '__main__':
  248. main()