install_extras.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. eza()
  16. git_whence()
  17. lazygit()
  18. starship()
  19. def bat():
  20. if platform.system() == 'Darwin':
  21. print('$ brew install git-delta')
  22. subprocess.run(['brew', 'install', 'bat'], check=True)
  23. return
  24. else:
  25. assert platform.system() == 'Linux'
  26. if subprocess.run(['dpkg', '-l', 'bat'], stdout=subprocess.DEVNULL).returncode == 0:
  27. print('bat package already installed')
  28. return
  29. subprocess.run(['sudo', 'apt', 'install', 'bat', '--yes'], check=True)
  30. def delta():
  31. if platform.system() == 'Darwin':
  32. print('$ brew install git-delta')
  33. subprocess.run(['brew', 'install', 'git-delta'], check=True)
  34. return
  35. else:
  36. assert platform.system() == 'Linux'
  37. if subprocess.run(['dpkg', '-l', 'git-delta'], stdout=subprocess.DEVNULL).returncode == 0:
  38. print('git-delta package already installed')
  39. return
  40. client = httpx.Client()
  41. latest = gh_latest_version(client, 'dandavison', 'delta')
  42. version = latest['name']
  43. arch = get_output(['dpkg', '--print-architecture'])
  44. filename = f'git-delta_{version}_{arch}.deb'
  45. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  46. deb_path = CURRENT_DIR / 'git-delta.deb'
  47. download(client, asset['browser_download_url'], deb_path)
  48. try:
  49. subprocess.run(['sudo', 'dpkg', '-i', deb_path], check=True)
  50. finally:
  51. os.unlink(deb_path)
  52. def dua():
  53. if platform.system() == 'Darwin':
  54. print('$ brew install dua-cli')
  55. subprocess.run(['brew', 'install', 'dua-cli'], check=True)
  56. return
  57. else:
  58. assert platform.system() == 'Linux'
  59. dua_path = CURRENT_DIR / 'dua'
  60. if dua_path.exists():
  61. print('dua already downloaded')
  62. return
  63. client = httpx.Client()
  64. latest = gh_latest_version(client, 'Byron', 'dua-cli')
  65. version = latest['name']
  66. dirname = f'dua-{version}-{platform.machine()}-unknown-linux-musl'
  67. filename = dirname + '.tar.gz'
  68. (asset,) = (asset for asset in latest['assets'] if asset['name'] == filename)
  69. tarball_path = CURRENT_DIR / 'dua.tar.gz'
  70. download(client, asset['browser_download_url'], tarball_path)
  71. with tarfile.open(tarball_path) as tar:
  72. with tar.extractfile(dirname + '/dua') as binary, dua_path.open('wb') as f: # pyright: ignore[reportOptionalContextManager]
  73. shutil.copyfileobj(binary, f)
  74. os.unlink(tarball_path)
  75. dua_path.chmod(0o755)
  76. def eza():
  77. if platform.system() == 'Darwin':
  78. print('$ brew install eza')
  79. subprocess.run(['brew', 'install', 'eza'], check=True)
  80. return
  81. else:
  82. assert platform.system() == 'Linux'
  83. if (CURRENT_DIR / 'eza').exists():
  84. print('eza already downloaded')
  85. return
  86. client = httpx.Client()
  87. url = f'https://github.com/eza-community/eza/releases/latest/download/eza_{platform.machine()}-unknown-linux-gnu.tar.gz'
  88. tarball_path = CURRENT_DIR / 'eza.tar.gz'
  89. download(client, url, tarball_path)
  90. with tarfile.open(tarball_path) as tar:
  91. tar.extract('./eza', CURRENT_DIR)
  92. tarball_path.unlink()
  93. def git_whence():
  94. if platform.system() == 'Darwin':
  95. print('$ brew install raylu/formulae/git-whence')
  96. subprocess.run(['brew', 'install', 'raylu/formulae/git-whence'], check=True)
  97. return
  98. else:
  99. assert platform.system() == 'Linux'
  100. if (CURRENT_DIR / 'git-whence').exists():
  101. print('git-whence already downloaded')
  102. return
  103. client = httpx.Client()
  104. url = f'https://github.com/raylu/git-whence/releases/latest/download/git-whence-{platform.machine()}-unknown-linux-gnu'
  105. download(client, url, CURRENT_DIR / 'git-whence')
  106. os.chmod(CURRENT_DIR / 'git-whence', 0o755)
  107. def lazygit():
  108. if (CURRENT_DIR / 'lazygit').exists():
  109. print('lazygit package already installed')
  110. return
  111. client = httpx.Client()
  112. latest = gh_latest_version(client, 'jesseduffield', 'lazygit')
  113. version = latest['name']
  114. arch = platform.processor()
  115. if arch == 'aarch64':
  116. arch = 'arm64'
  117. url = f'https://github.com/jesseduffield/lazygit/releases/download/{version}/lazygit_{version.lstrip("v")}_{platform.system()}_{arch}.tar.gz'
  118. download(client, url, CURRENT_DIR / 'lazygit.tgz')
  119. with tarfile.open(CURRENT_DIR / 'lazygit.tgz', 'r:gz') as tar:
  120. tar.extract('lazygit', CURRENT_DIR)
  121. os.unlink(CURRENT_DIR / 'lazygit.tgz')
  122. def starship():
  123. if platform.system() == 'Darwin':
  124. print('$ brew install starship')
  125. subprocess.run(['brew', 'install', 'starship'], check=True)
  126. return
  127. else:
  128. assert platform.system() == 'Linux'
  129. if (CURRENT_DIR / 'starship').exists():
  130. print('starship already downloaded')
  131. return
  132. client = httpx.Client()
  133. arch = platform.machine()
  134. if arch == 'x86_64':
  135. libc = 'gnu'
  136. else:
  137. libc = 'musl'
  138. url = f'https://github.com/starship/starship/releases/latest/download/starship-{arch}-unknown-linux-{libc}.tar.gz'
  139. tarball_path = CURRENT_DIR / 'starship.tar.gz'
  140. download(client, url, tarball_path)
  141. with tarfile.open(tarball_path, 'r:gz') as tar:
  142. tar.extract('starship', CURRENT_DIR)
  143. tarball_path.unlink()
  144. def get_output(argv: list[str]) -> str:
  145. proc = subprocess.run(argv, check=True, capture_output=True, encoding='ascii')
  146. return proc.stdout.rstrip('\n')
  147. def gh_latest_version(client: httpx.Client, org: str, repo: str) -> dict:
  148. r = client.get(f'https://api.github.com/repos/{org}/{repo}/releases/latest',
  149. headers={'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28'})
  150. r.raise_for_status()
  151. return r.json()
  152. def download(client: httpx.Client, url: str, path: pathlib.Path) -> None:
  153. print('downloading', url, 'to', path)
  154. with client.stream('GET', url, follow_redirects=True) as r:
  155. r.raise_for_status()
  156. with path.open('wb') as f:
  157. for chunk in r.iter_bytes():
  158. f.write(chunk)
  159. if __name__ == '__main__':
  160. main()