install_extras.py 8.0 KB

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