install_extras.py 9.3 KB

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