Compare commits
6 Commits
6ea078c80d
...
4de2819109
| Author | SHA1 | Date | |
|---|---|---|---|
| 4de2819109 | |||
| dd7697fcc7 | |||
| 28b56e71ab | |||
| dd204788e3 | |||
| 57e763a24f | |||
| 81c33d100f |
@@ -6,36 +6,19 @@ import tarfile
|
|||||||
|
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.progress import SpinnerColumn
|
from rich.progress import SpinnerColumn
|
||||||
|
from util import check_ground_libs_path, check_sudo
|
||||||
|
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
def install(args):
|
def install_package(package_name, version, 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
|
retries_left = args.max_retries
|
||||||
|
|
||||||
with console.status("Downloading tarball...", spinner="bouncingBall", spinner_style="blue") as status:
|
with console.status("Downloading tarball...", spinner="bouncingBall", spinner_style="blue") as status:
|
||||||
while retries_left > 0:
|
while retries_left > 0:
|
||||||
# grab the tar ball
|
# 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
|
# check response code for errors
|
||||||
if response.status_code == 404: # package doesn't exist
|
if response.status_code == 404: # package doesn't exist
|
||||||
@@ -79,3 +62,28 @@ def install(args):
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
console.print(f"[d][:white_check_mark:] Extracted to {extract_dir}.")
|
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
38
src/list.py
Normal 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)
|
||||||
25
src/main.py
25
src/main.py
@@ -4,6 +4,8 @@ import os, sys
|
|||||||
from install import install
|
from install import install
|
||||||
from publish import publish
|
from publish import publish
|
||||||
from remove import remove
|
from remove import remove
|
||||||
|
from list import list_cmd
|
||||||
|
from uninstall import uninstall
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
@@ -13,7 +15,7 @@ def parse_arguments():
|
|||||||
|
|
||||||
# install command
|
# install command
|
||||||
install_command = sub_parsers.add_parser(name="install", description="install a mineral")
|
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)
|
install_command.add_argument("--max-retries", help="max number of download retries before giving up", default=3, type=int)
|
||||||
|
|
||||||
# uninstall command
|
# uninstall command
|
||||||
@@ -22,7 +24,6 @@ def parse_arguments():
|
|||||||
|
|
||||||
# list command
|
# list command
|
||||||
list_command = sub_parsers.add_parser(name="list", description="list all minerals installed in the current environment")
|
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
|
||||||
publish_command = sub_parsers.add_parser(name="publish", description="publish a package to the repository")
|
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")
|
remove_command.add_argument("name", help="name and version of the package")
|
||||||
|
|
||||||
# env command
|
# 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()
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
if not args.command:
|
if not args.command:
|
||||||
arg_parser.print_help()
|
arg_parser.print_help()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
if args.command == "env" and not args.env_command:
|
|
||||||
env_command.print_help()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if args.command == "install":
|
if args.command == "install":
|
||||||
install(args)
|
install(args)
|
||||||
@@ -63,6 +48,10 @@ def parse_arguments():
|
|||||||
publish(args)
|
publish(args)
|
||||||
elif args.command == "remove":
|
elif args.command == "remove":
|
||||||
remove(args)
|
remove(args)
|
||||||
|
elif args.command == "list":
|
||||||
|
list_cmd(args)
|
||||||
|
elif args.command == "uninstall":
|
||||||
|
uninstall(args)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parse_arguments()
|
parse_arguments()
|
||||||
|
|||||||
@@ -39,8 +39,21 @@ def publish(args):
|
|||||||
|
|
||||||
console.print()
|
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
|
# compress to a tar file
|
||||||
|
console.status("Compressing")
|
||||||
f = tempfile.TemporaryFile(mode="wb+")
|
f = tempfile.TemporaryFile(mode="wb+")
|
||||||
with tarfile.open(fileobj=f, mode="w:gz") as tar_file:
|
with tarfile.open(fileobj=f, mode="w:gz") as tar_file:
|
||||||
tar_file.add(args.folder_path, arcname=os.path.basename(args.folder_path))
|
tar_file.add(args.folder_path, arcname=os.path.basename(args.folder_path))
|
||||||
@@ -52,22 +65,25 @@ def publish(args):
|
|||||||
# send the request
|
# send the request
|
||||||
status.update("Uploading...")
|
status.update("Uploading...")
|
||||||
response = requests.put(
|
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,
|
data=f,
|
||||||
auth=HTTPBasicAuth(username, password)
|
auth=HTTPBasicAuth(username, password)
|
||||||
)
|
)
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
if response.status_code == 401:
|
match response.status_code:
|
||||||
|
case 401:
|
||||||
console.print("[b red]digpkg: failed to publish mineral: authentication failed[/]")
|
console.print("[b red]digpkg: failed to publish mineral: authentication failed[/]")
|
||||||
sys.exit(1)
|
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[/]")
|
console.print("[b red]digpkg: failed to publish mineral: the package name or version number are invalid[/]")
|
||||||
sys.exit(1)
|
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[/]")
|
console.print("[b red]digpkg: failed to publish mineral: that version number is already in use[/]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
console.print("[d][:white_check_mark:] Uploaded![/]")
|
console.print("[d][:white_check_mark:] Uploaded![/]")
|
||||||
|
|
||||||
|
console.print("[:white_check_mark:] Done!")
|
||||||
@@ -30,7 +30,7 @@ def remove(args):
|
|||||||
|
|
||||||
# send the request
|
# send the request
|
||||||
response = requests.delete(
|
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)
|
auth=HTTPBasicAuth(username, password)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,4 +42,4 @@ def remove(args):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
console.print("[d][:white_check_mark:] Success![/]")
|
console.print("[d][:white_check_mark:] Done![/]")
|
||||||
36
src/uninstall.py
Normal file
36
src/uninstall.py
Normal 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
16
src/util.py
Normal 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)
|
||||||
Reference in New Issue
Block a user