Improved typing, refactored code, fixed some issues

This commit is contained in:
Firq 2024-07-04 22:12:36 +02:00
parent 06cece6242
commit d3e5d4ae56
Signed by: Firq
GPG key ID: 3ACC61C8CEC83C20
16 changed files with 59 additions and 72 deletions

View file

View file

@ -0,0 +1,102 @@
from urllib.parse import urlparse
from getpass import getpass
from ...models.parser import Credentials
from ...service import storage
from ..utils import stack_formatter, status_formatter, generic_formatter, get_credential_parser
from ...service.communicate import DockgeConnection
class ExecutionCommands():
@staticmethod
def __setup():
con = DockgeConnection()
con.connect_and_login()
return con
@staticmethod
def host(extra_args):
if len(extra_args) > 0:
res = urlparse(extra_args[0])
if all([res.scheme, res.netloc]):
host = extra_args[0].rstrip("/").replace("https://", "").replace("wss://", "")
storage.put("host", host)
else:
raise ValueError(f"Malformed URL {extra_args[0]}")
print(storage.get("host"))
@staticmethod
def login(extra_args):
if len(extra_args) > 0:
credentials = get_credential_parser().parse_args(extra_args, namespace=Credentials)
storage.put("username", credentials.username, encoded=True)
storage.put("password", credentials.password, encoded=True)
return
storage.put("username", input("Username: "), encoded=True)
storage.put("password", getpass("Password: "), encoded=True)
@staticmethod
def logout(_):
storage.remove("username")
storage.remove("password")
@staticmethod
def exit(_):
storage.clear()
@staticmethod
def list(_):
con = ExecutionCommands.__setup()
stack_formatter(con.list_stacks())
con.disconnect()
@staticmethod
def status(extra_args):
if extra_args is None:
raise ValueError
con = ExecutionCommands.__setup()
status_formatter(con.list_stack(extra_args[0]))
con.disconnect()
@staticmethod
def restart(extra_args):
if extra_args is None:
raise ValueError
con = ExecutionCommands.__setup()
generic_formatter(con.restart(extra_args[0]))
con.disconnect()
@staticmethod
def update(extra_args):
if extra_args is None:
raise ValueError
con = ExecutionCommands.__setup()
generic_formatter(con.update(extra_args[0]))
con.disconnect()
@staticmethod
def stop(extra_args):
if extra_args is None:
raise ValueError
con = ExecutionCommands.__setup()
generic_formatter(con.stop(extra_args[0]))
con.disconnect()
@staticmethod
def start(extra_args):
if extra_args is None:
raise ValueError
con = ExecutionCommands.__setup()
generic_formatter(con.start(extra_args[0]))
con.disconnect()
@staticmethod
def down(extra_args):
if extra_args is None:
raise ValueError
con = ExecutionCommands.__setup()
generic_formatter(con.down(extra_args[0]))
con.disconnect()
@staticmethod
def help():
print("WTF")

View file

@ -0,0 +1,88 @@
from .bindings import ExecutionCommands
command_mappings = [
{
"command": "host",
"description": "Sets and gets the URI of the dockge instance. Remove any unnecessary subdomains/protocols from the URI",
"args": 1,
"optional": True,
"binding": ExecutionCommands.host
},
{
"command": "login",
"description": "Logs into a given dockge account, either with an interactive dialogue or by passing --user and --password",
"args": 2,
"optional": True,
"binding": ExecutionCommands.login
},
{
"command": "logout",
"description": "Removes the credentials from the local storage.",
"args": 0,
"optional": False,
"binding": ExecutionCommands.logout
},
{
"command": "list",
"description": "Lists all available stacks with their status",
"args": 0,
"optional": False,
"binding": ExecutionCommands.list
},
{
"command": "status",
"description": "Returns the status of one stack",
"args": 1,
"optional": False,
"binding": ExecutionCommands.status
},
{
"command": "restart",
"description": "Restarts a given stack",
"args": 1,
"optional": False,
"binding": ExecutionCommands.restart
},
{
"command": "start",
"description": "Starts a given stack",
"args": 1,
"optional": False,
"binding": ExecutionCommands.start
},
{
"command": "stop",
"description": "Stops a given stack",
"args": 1,
"optional": False,
"binding": ExecutionCommands.stop
},
{
"command": "down",
"description": "Stop & Downs a given stack",
"args": 1,
"optional": False,
"binding": ExecutionCommands.down
},
{
"command": "update",
"description": "Updates a stack",
"args": 1,
"optional": False,
"binding": ExecutionCommands.update
},
{
"command": "exit",
"description": "Exits the CLI - this will reset all settings, including credentials and host",
"args": 0,
"optional": False,
"binding": ExecutionCommands.exit
},
{
"command": "help",
"description": "Displays helping hints for commands",
"args": 1,
"optional": True,
"binding": ExecutionCommands.help
}
]

View file

@ -0,0 +1,17 @@
from typing import List, Callable
from pydantic import BaseModel
from .descriptors import command_mappings
class Command(BaseModel):
command: str
description: str
args: int
optional: bool
binding: Callable
commands: dict[str, Command] = {}
descriptors: List[dict[str, object]] = command_mappings
for descriptor in descriptors:
c = Command(**descriptor) # type: ignore
commands.update({ c.command: c })

View file

@ -0,0 +1,18 @@
import argparse
import sys
from .. import __version__
from ..models.parser import Arguments
from .commandprovider.factory import commands
def parse_arguments():
parser = argparse.ArgumentParser(
prog="dockge_cli",
description="CLI interface for interacting with Dockge",)
parser.add_argument("command", choices=list(commands.keys()), action="store", type=str, default=None)
parser.add_argument("--version", action="version", version=f"dockge_cli {__version__}")
args = Arguments()
args, extra_args = parser.parse_known_args(sys.argv[1:], namespace=args)
return args, extra_args

28
dockge_cli/client/run.py Normal file
View file

@ -0,0 +1,28 @@
from .commandprovider.factory import commands
def display_help(extra_args):
if not extra_args:
print(f"{commands['help'].description}")
return
if len(extra_args) > 1:
raise ValueError("Invalid arguments for help command")
if extra_args[0] not in commands:
raise ValueError("Unknown command")
print(f"{commands[extra_args[0]].description}")
def run(command, args):
if command not in commands:
raise ValueError("Invalid Command")
c = commands[command]
if args and c.args > len(args):
raise ValueError("Too many arguments")
if args and c.args < len(args) and not c.optional:
raise ValueError("Missing arguments")
if command == "help":
display_help(args)
return
c.binding(args)

View file

@ -0,0 +1,32 @@
import argparse
from tabulate import tabulate
from ..models import StackStatus
def get_credential_parser():
credentialparser = argparse.ArgumentParser(
prog="login",
description="Subparser for login credentials provided by CI"
)
credentialparser.add_argument("--username", action="store", type=str, required=True)
credentialparser.add_argument("--password", action="store", type=str, required=True)
return credentialparser
def stack_formatter(stacks):
if not stacks["ok"]:
raise RuntimeError("Stack GET didn't work")
table, headers = [], ["Stackname", "Status"]
for key, val in stacks["stackList"].items():
table.append([key, StackStatus(val['status']).name])
print(tabulate(table, headers=headers, tablefmt="github"), "\n")
def status_formatter(status):
print(f"Is Stack Ok? {'Yes' if status['ok'] else 'No'}")
headers = ["Container", "Status"]
table = [[k, v] for k, v in status["serviceStatusList"].items()]
print(tabulate(table, headers=headers, tablefmt="github"), "\n")
def generic_formatter(status):
print(f"Is Ok? {'Yes' if status['ok'] else 'No'}")
print(f"Stack status: {status['msg']}")