Files
Digpkg/dig/install.py

116 lines
4.5 KiB
Python

import requests
import os
import sys
import tempfile
import tarfile
import configparser
import shutil
from rich.console import Console
from rich.progress import SpinnerColumn
from .util import check_ground_libs_path, check_sudo
console = Console()
def install_package(package_name, version, args, is_dependency: bool = False):
retries_left = args.max_retries
with console.status("Downloading tarball...", spinner="bouncingBall", spinner_style="blue") as status:
console.print(f"Installing {package_name} [d]({version})[/]")
while retries_left > 0:
# grab the tar ball
response = requests.get(f"https://chookspace.com/api/packages/ground/generic/{package_name}/{version}/mineral.tar")
# check response code for errors
if response.status_code == 404: # package doesn't exist
console.print(f"[b red]digpkg: mineral \"{package_name}\" was not found. Check to make sure the name and version number are correct.[/]")
sys.exit(1)
elif response.status_code != 200:
retries_left -= 1
console.print(f"[b yellow]digpkg: failed to download mineral \"{package_name}\": {response.content.decode()} ({retries_left} retries left)[/]")
if retries_left == 0:
console.print(f"[b red]digpkg: exceeded max retries while downloading mineral \"{package_name}\"[/]")
sys.exit(1)
continue
response.raise_for_status()
break
# create temporary file for tarball
try:
f = tempfile.TemporaryFile("wb+")
f.write(response.content)
f.flush()
f.seek(0)
console.print("[d][:white_check_mark:] Tarball downloaded![/]")
except KeyboardInterrupt:
console.print("[b yellow]digpkg: operation cancelled by user[/]")
return
# extract the tarball to the GROUND_LIBS folder
status.update("Extracting...")
extract_dir = os.getenv("GROUND_LIBS")
if not os.path.isdir(extract_dir): # gotta ensure the folder exists
os.mkdir(extract_dir)
tar_file = tarfile.open(fileobj=f)
tar_file.extractall(extract_dir)
f.close()
console.print(f"[d][:white_check_mark:] Extracted to {extract_dir}.")
console.status("Finishing up...")
package_folder = os.path.join(extract_dir, f"{package_name}/")
if not os.path.isfile(os.path.join(package_folder, "mineral.ini")):
console.print(f"[b red]digpkg: failed to install {package_name}: the mineral doesn't have a mineral.ini file, please contact the maintainer because they've set up the mineral incorrectly.")
console.print("[d]Cleaning up failed install...[/]")
shutil.rmtree(os.path.join(extract_dir, package_name))
sys.exit(1)
config_parser = configparser.ConfigParser()
config_parser.read(os.path.join(package_folder, "mineral.ini"))
dependencies = config_parser["dependencies"]
# create a symlink from the main.so file to the ground libs folder so ground can find it
symlink_path = os.path.join(extract_dir, f"{package_name}.so") # the path where the symlink is
if not os.path.isfile(symlink_path):
os.symlink(os.path.join(extract_dir, package_name, "main.so"), symlink_path)
if is_dependency:
console.print(f"[d][:white_check_mark:] Done installing dependency: {package_name}[/]")
for dependency, dependency_version in dependencies.items():
install_package(dependency, dependency_version, args, True)
if not is_dependency:
console.print(f"\n[b green][:white_check_mark:] Installed {package_name}![/]")
def install(args):
check_sudo()
check_ground_libs_path()
for package in args.names:
# figure out which version to install
package_name = package
version = "1.0.0"
if "@" in package:
split = package.split("@")
package_name = split[0]
version = split[1]
else:
console.print(f"[b red]digpkg: failed to install package: please specify version to install for {package_name}[/]")
sys.exit(1)
install_package(package_name, version, args)