diff --git a/requirements.txt b/requirements.txt index c94be38..3bfa0c6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -rich \ No newline at end of file +rich +requests \ No newline at end of file diff --git a/src/install.py b/src/install.py new file mode 100644 index 0000000..be90993 --- /dev/null +++ b/src/install.py @@ -0,0 +1,75 @@ +import requests +import os +import sys +import tempfile +import tarfile + +from rich.console import Console +from rich.progress import SpinnerColumn + + +console = Console() + + +def install(args): + # check if we are sudo + if os.getuid() != 0: + console.print("[b red]digpkg: the install command requires sudo to run[/]") + sys.exit(1) + + # ensure the GROUND_LIBS var is set + if not os.getenv("GROUND_LIBS"): + console.print("digpkg: the [i]GROUND_LIBS[/] environment variable is not set, defaulting to /usr/lib/ground/") + os.environ["GROUND_LIBS"] = "/usr/lib/ground/" + + # figure out which version to install + package_name = args.name + version = "latest" + if "@" in args.name: + split = package_name.split("@") + package_name = split[0] + version = split[1] + + retries_left = args.max_retries + + with console.status("Downloading tarball...", spinner="bouncingBall", spinner_style="blue") as status: + while retries_left > 0: + # grab the tar ball + response = requests.get(f"https://chookspace.com/api/packages/SpookyDervish/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 + + break + + # create temporary file for tarball + f = tempfile.TemporaryFile("wb+") + f.write(response.content) + f.flush() + f.seek(0) + console.print("[d][:white_check_mark:] Tarball downloaded![/]") + + # 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}.") \ No newline at end of file diff --git a/src/main.py b/src/main.py index 41d9183..35fb961 100644 --- a/src/main.py +++ b/src/main.py @@ -1,5 +1,7 @@ -from rich import print import argparse +import os, sys + +from install import install def parse_arguments(): @@ -10,6 +12,7 @@ def parse_arguments(): # install command install_command = sub_parsers.add_parser(name="install", description="install a mineral") install_command.add_argument("name", help="name of the mineral to install") + install_command.add_argument("--max-retries", help="max number of download retries before giving up", default=3, type=int) # uninstall command uninstall_command = sub_parsers.add_parser(name="uninstall", description="uninstall a mineral") @@ -20,7 +23,7 @@ def parse_arguments(): list_command.add_argument("--env_name", help="list all minerals from a specific environment.", default=None, required=False) # env command - env_command = sub_parsers.add_parser(name="env", description="manage Ground environments") + """env_command = sub_parsers.add_parser(name="env", description="manage Ground environments") env_sub_parsers = env_command.add_subparsers(dest="env_command") env_new_command = env_sub_parsers.add_parser(name="new", description="create a new environment") @@ -31,20 +34,23 @@ def parse_arguments(): env_destroy_command.add_argument("name", help="name of the environment to DESTROYYY") env_destroy_command.add_argument("--confirm-yes", action="store_true", help="don't ask for confirmation (DANGEROUS)") - env_list_command = env_sub_parsers.add_parser(name="list", description="list all environments") + env_list_command = env_sub_parsers.add_parser(name="list", description="list all environments")""" args = arg_parser.parse_args() if not args.command: arg_parser.print_help() + sys.exit(0) if args.command == "env" and not args.env_command: env_command.print_help() + sys.exit(0) + + if args.command == "install": + install(args) def main(): parse_arguments() - - if __name__ == "__main__": diff --git a/src/mineral.py b/src/mineral.py new file mode 100644 index 0000000..8ac7cb6 --- /dev/null +++ b/src/mineral.py @@ -0,0 +1,28 @@ +import configparser +import os, sys +from rich import print + + +class Mineral: + def __init__(self, mineral_name: str, ground_folder_path: str, env_name: str): + self.folder_path = os.path.join(ground_folder_path, env_name, mineral_name) + self.config_path = os.path.join(self.folder_path, "mineral.ini") + self.name = mineral_name + + if not os.path.isdir(self.folder_path): # mineral does not exist on system + print(f"[b red]digpkg: error: folder \"{self.folder_path}\" does not exist![/]") + sys.exit(1) + + if not os.path.isfile(self.config_path): # mineral has no file inside it named "mineral.ini" + print(f"[b red]digpkg: error: the mineral \"{self.name}\" has no config.ini file![/]") + sys.exit(1) + + self.config_parser = configparser.ConfigParser() + self.config_parser.read(self.config_path) + + self.description = self.config_parser.get("package", "description") + self.version = self.config_parser.get("package", "version") + + self.dependencies = dict(self.config_parser["dependencies"]) + + print(self.description) \ No newline at end of file