1#!/usr/bin/env python3 2 3""" 4Install .deb packages from GitHub releases directly. 5 6Use as: 7 sudo ./github_install BurntSushi/ripgrep sharkdp/fd 8""" 9import re10import subprocess11import sys12import tempfile13from typing import Optional14from typing import Tuple1516import requests171819def download_file(url: str, temp_dir: str) -> str:20 local_filename = url.split("/")[-1]21 with requests.get(url, stream=True) as r:22 r.raise_for_status()23 with open(temp_dir + "/file.deb", "wb") as f:24 for chunk in r.iter_content(chunk_size=8192):25 f.write(chunk)26 return temp_dir + "/file.deb"272829def get_installed_version(package_name: str) -> Optional[str]:30 try:31 out = subprocess.check_output(32 ["apt", "show", package_name], stderr=subprocess.DEVNULL33 )34 except subprocess.CalledProcessError:35 return None36 return re.search("Version:\s+v?(.*)", out.decode()).group(1)373839def get_repo_details(repo_name: str) -> Tuple[str, str]:40 r = requests.get(f"https://api.github.com/repos/{repo_name}/releases/latest")41 version = r.json()["tag_name"].strip("v")4243 urls = [x["browser_download_url"] for x in r.json()["assets"]]44 linux_urls = sorted(45 (url for url in urls if "amd64" in url and "deb" in url), reverse=True46 )47 url = linux_urls[0] if linux_urls else None48 return version, url495051def install_package(repo_name: str) -> None:52 print(f"Processing {repo_name}...")53 package_name = repo_name.split("/")[1]54 installed_version = get_installed_version(package_name)55 repo_version, url = get_repo_details(repo_name)56 if not url:57 sys.exit("Could not find a suitable download for this package.")5859 if installed_version == repo_version:60 print(61 f"{package_name} is up to date at {installed_version}, will not continue."62 )63 return6465 if installed_version:66 print(67 f"Version {repo_version} found for {package_name}, which is currently at {installed_version}, upgrading..."68 )69 else:70 print(71 f"Version {repo_version} found for {package_name}, which is currently not installed, installing..."72 )7374 print(f"URL: {url}")7576 with tempfile.TemporaryDirectory() as temp_dir:77 file_name = download_file(url, temp_dir)78 subprocess.run(["dpkg", "-i", file_name])798081if __name__ == "__main__":82 repos = sys.argv[1:]83 for repo in repos:84 install_package(repo)85 print("Done.")