Compare commits

...

6 Commits

7 changed files with 156 additions and 53 deletions

View File

@@ -6,36 +6,19 @@ import tarfile
from rich.console import Console
from rich.progress import SpinnerColumn
from util import check_ground_libs_path, check_sudo
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]
def install_package(package_name, version, args):
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")
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
@@ -79,3 +62,28 @@ def install(args):
f.close()
console.print(f"[d][:white_check_mark:] Extracted to {extract_dir}.")
console.status("Finishing up...")
# 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)
console.print("[:white_check_mark:] Done!")
def install(args):
check_sudo()
check_ground_libs_path()
for package in args.names:
# figure out which version to install
package_name = package
version = "latest"
if "@" in package:
split = package.split("@")
package_name = split[0]
version = split[1]
install_package(package_name, version, args)

38
src/list.py Normal file
View File

@@ -0,0 +1,38 @@
import os
import configparser
from rich import print
from rich.table import Table
from util import check_ground_libs_path
def list_cmd(args):
check_ground_libs_path()
ground_libs_folder = os.getenv("GROUND_LIBS")
folders = os.listdir(ground_libs_folder)
table = Table("Name", "Version", "Description", title="Installed")
config_parser = configparser.ConfigParser()
for folder in folders:
full_path = os.path.join(ground_libs_folder, folder)
# skip anything that isnt a folder
if not os.path.isdir(full_path):
continue
# read the mineral.ini file to figure out the version and description
ini_path = os.path.join(full_path, "mineral.ini")
if not os.path.isfile(ini_path):
continue
config_parser.read(ini_path)
table.add_row(
f"[b]{folder}",
f"[blue]{config_parser.get('package', 'version')}",
config_parser.get("package", "description"),
)
print(table)

View File

@@ -4,6 +4,8 @@ import os, sys
from install import install
from publish import publish
from remove import remove
from list import list_cmd
from uninstall import uninstall
def parse_arguments():
@@ -13,7 +15,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("names", help="name of the minerals to install", nargs="+")
install_command.add_argument("--max-retries", help="max number of download retries before giving up", default=3, type=int)
# uninstall command
@@ -22,7 +24,6 @@ def parse_arguments():
# list command
list_command = sub_parsers.add_parser(name="list", description="list all minerals installed in the current environment")
list_command.add_argument("--env_name", help="list all minerals from a specific environment.", default=None, required=False)
# publish command
publish_command = sub_parsers.add_parser(name="publish", description="publish a package to the repository")
@@ -34,28 +35,12 @@ def parse_arguments():
remove_command.add_argument("name", help="name and version of the package")
# env command
"""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")
env_new_command.add_argument("name", help="name of the new environment")
env_new_command.add_argument("--dont-use", help="by default, the newly created environment will be set as the current environment. if this argument is parsed, then it will be created but not activated.", action="store_true")
env_destroy_command = env_sub_parsers.add_parser(name="destroy", description="delete an environment")
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")"""
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)
@@ -63,6 +48,10 @@ def parse_arguments():
publish(args)
elif args.command == "remove":
remove(args)
elif args.command == "list":
list_cmd(args)
elif args.command == "uninstall":
uninstall(args)
def main():
parse_arguments()

View File

@@ -39,8 +39,21 @@ def publish(args):
console.print()
with console.status("Compressing...", spinner="bouncingBall", spinner_style="blue") as status:
with console.status("Authenticating...", spinner="bouncingBall", spinner_style="blue") as status:
# check if we have permission to link the package to the repo
repo_perms_request = requests.get(
url=f"https://chookspace.com/api/v1/users/{username}/orgs/ground/permissions",
auth=HTTPBasicAuth(username, password)
)
if repo_perms_request.status_code == 401:
console.print(f"[b red]digpkg: failed to publish mineral: checking authorization failed: invalid password[/b red]")
sys.exit(1)
elif not repo_perms_request.ok:
console.print(f"[b red]digpkg: failed to publish mineral: checking authorization failed: {repo_perms_request.content.decode()}[/b red]")
sys.exit(1)
# compress to a tar file
console.status("Compressing")
f = tempfile.TemporaryFile(mode="wb+")
with tarfile.open(fileobj=f, mode="w:gz") as tar_file:
tar_file.add(args.folder_path, arcname=os.path.basename(args.folder_path))
@@ -52,22 +65,25 @@ def publish(args):
# send the request
status.update("Uploading...")
response = requests.put(
url=f"https://chookspace.com/api/packages/{username}/generic/{mineral_name}/{version}/mineral.tar",
url=f"https://chookspace.com/api/packages/ground/generic/{mineral_name}/{version}/mineral.tar",
data=f,
auth=HTTPBasicAuth(username, password)
)
f.close()
if response.status_code == 401:
match response.status_code:
case 401:
console.print("[b red]digpkg: failed to publish mineral: authentication failed[/]")
sys.exit(1)
elif response.status_code == 400:
case 400:
console.print("[b red]digpkg: failed to publish mineral: the package name or version number are invalid[/]")
sys.exit(1)
elif response.status_code == 409:
case 409:
console.print("[b red]digpkg: failed to publish mineral: that version number is already in use[/]")
sys.exit(1)
response.raise_for_status()
console.print("[d][:white_check_mark:] Uploaded![/]")
console.print("[:white_check_mark:] Done!")

View File

@@ -30,7 +30,7 @@ def remove(args):
# send the request
response = requests.delete(
url=f"https://chookspace.com/api/packages/{username}/generic/{mineral_name}/{version}",
url=f"https://chookspace.com/api/packages/ground/generic/{mineral_name}/{version}",
auth=HTTPBasicAuth(username, password)
)
@@ -42,4 +42,4 @@ def remove(args):
sys.exit(1)
response.raise_for_status()
console.print("[d][:white_check_mark:] Success![/]")
console.print("[d][:white_check_mark:] Done![/]")

36
src/uninstall.py Normal file
View File

@@ -0,0 +1,36 @@
import os, sys
import shutil
from util import check_ground_libs_path, check_sudo
from rich.console import Console
console = Console()
def uninstall(args):
check_sudo()
check_ground_libs_path()
with console.status(status=f"Looking for [i]{args.name}[/]...", spinner="bouncingBall", spinner_style="blue") as status:
mineral_path = os.path.join(os.getenv("GROUND_LIBS"), args.name)
symlink_path = os.path.join(os.getenv("GROUND_LIBS"), f"{args.name}.so")
# check to make sure the mineral is installed
if not os.path.isdir(mineral_path):
console.print(f"[b red]digpkg: failed to uninstall [i]{args.name}[/]: mineral is not installed[/b red]")
sys.exit(1)
# remove the symlink
status.update("Removing symlink...")
if os.path.islink(symlink_path):
os.unlink(symlink_path)
console.print(f"[d][:white_check_mark:] Removed symlink!")
# delete the folder
shutil.rmtree(mineral_path)
console.print(f"[d][:white_check_mark:] Removed mineral folder!")
console.print(f"[:white_check_mark:] Done!")

16
src/util.py Normal file
View File

@@ -0,0 +1,16 @@
import os, sys
from rich import print
def check_ground_libs_path():
# ensure the GROUND_LIBS var is set
if not os.getenv("GROUND_LIBS"):
print("digpkg: the [i]GROUND_LIBS[/] environment variable is not set, defaulting to /usr/lib/ground/")
os.environ["GROUND_LIBS"] = "/usr/lib/ground/"
def check_sudo():
# check if we are sudo
if os.getuid() != 0:
print("[b red]digpkg: that command requires sudo to run[/]")
sys.exit(1)