Compare commits
1 commit
main
...
feature/pa
Author | SHA1 | Date | |
---|---|---|---|
ca18a070c7 |
7 changed files with 120 additions and 111 deletions
dockge_cli
pyproject.toml
|
@ -1,4 +1,2 @@
|
|||
from ...models import Command
|
||||
from .mappings import mapping
|
||||
|
||||
commands: dict[str, Command] = { c.cmd: c for c in mapping }
|
||||
from .mappings import commands
|
||||
|
|
|
@ -2,10 +2,10 @@ from urllib.parse import urlparse
|
|||
from getpass import getpass
|
||||
import re
|
||||
|
||||
from ...models import Credentials
|
||||
from ...models.command import LoginNamespace, StacknameNamespace, HostNamespace, HelpNamespace
|
||||
from ...service import storage
|
||||
from ...service.connection import DockgeConnection
|
||||
from ..utils import stack_formatter, status_formatter, generic_formatter, credential_parser_factory
|
||||
from ..utils import stack_formatter, status_formatter, generic_formatter
|
||||
|
||||
class FunctionBindings():
|
||||
"""
|
||||
|
@ -22,31 +22,30 @@ class FunctionBindings():
|
|||
return con
|
||||
|
||||
@staticmethod
|
||||
def host(extra_args):
|
||||
def host(args: HostNamespace):
|
||||
"""
|
||||
host command binding
|
||||
"""
|
||||
if len(extra_args) > 0:
|
||||
mat = re.search(r"((\w+\.)?\w+\.\w+(\/.+)?)", extra_args[0], re.IGNORECASE)
|
||||
if args.uri is not None:
|
||||
mat = re.search(r"((\w+\.)?\w+\.\w+(\/.+)?)", args.uri, re.IGNORECASE)
|
||||
if mat is None:
|
||||
raise ValueError("Given host did not match regex")
|
||||
res = urlparse(f"https://{mat[0]}")
|
||||
if all([res.scheme, res.netloc]):
|
||||
storage.put("host", mat[0])
|
||||
else:
|
||||
raise ValueError(f"Malformed URL {extra_args[0]}")
|
||||
raise ValueError(f"Malformed URL {args.uri}")
|
||||
print(storage.get("host"))
|
||||
|
||||
@staticmethod
|
||||
def login(extra_args):
|
||||
def login(args: LoginNamespace):
|
||||
"""
|
||||
login command binding
|
||||
"""
|
||||
print(f"WARNING! These credentials will be saved unencrypted in {storage._file.absolute()}")
|
||||
if len(extra_args) > 0:
|
||||
credentials = credential_parser_factory().parse_args(extra_args, namespace=Credentials)
|
||||
storage.put("username", credentials.username, encoded=True)
|
||||
storage.put("password", credentials.password, encoded=True)
|
||||
if args.username is not None and args.password is not None:
|
||||
storage.put("username", args.username, encoded=True)
|
||||
storage.put("password", args.password, encoded=True)
|
||||
return
|
||||
storage.put("username", input("Username: "), encoded=True)
|
||||
storage.put("password", getpass("Password: "), encoded=True)
|
||||
|
@ -76,62 +75,56 @@ class FunctionBindings():
|
|||
con.disconnect()
|
||||
|
||||
@staticmethod
|
||||
def status(extra_args):
|
||||
def status(args: StacknameNamespace):
|
||||
"""
|
||||
status command binding
|
||||
"""
|
||||
con = FunctionBindings.__setup()
|
||||
status_formatter(con.list_stack(extra_args[0]))
|
||||
status_formatter(con.list_stack(args.stackname))
|
||||
con.disconnect()
|
||||
|
||||
@staticmethod
|
||||
def restart(extra_args):
|
||||
def restart(args: StacknameNamespace):
|
||||
"""
|
||||
restart command binding
|
||||
"""
|
||||
con = FunctionBindings.__setup()
|
||||
generic_formatter(con.restart(extra_args[0]))
|
||||
generic_formatter(con.restart(args.stackname))
|
||||
con.disconnect()
|
||||
|
||||
@staticmethod
|
||||
def update(extra_args):
|
||||
def update(args: StacknameNamespace):
|
||||
"""
|
||||
update command binding
|
||||
"""
|
||||
con = FunctionBindings.__setup()
|
||||
generic_formatter(con.update(extra_args[0]))
|
||||
generic_formatter(con.update(args.stackname))
|
||||
con.disconnect()
|
||||
|
||||
@staticmethod
|
||||
def stop(extra_args):
|
||||
def stop(args: StacknameNamespace):
|
||||
"""
|
||||
stop command binding
|
||||
"""
|
||||
con = FunctionBindings.__setup()
|
||||
generic_formatter(con.stop(extra_args[0]))
|
||||
generic_formatter(con.stop(args.stackname))
|
||||
con.disconnect()
|
||||
|
||||
@staticmethod
|
||||
def start(extra_args):
|
||||
def start(args: StacknameNamespace):
|
||||
"""
|
||||
start command binding
|
||||
"""
|
||||
con = FunctionBindings.__setup()
|
||||
generic_formatter(con.start(extra_args[0]))
|
||||
generic_formatter(con.start(args.stackname))
|
||||
con.disconnect()
|
||||
|
||||
@staticmethod
|
||||
def down(extra_args):
|
||||
def down(args: StacknameNamespace):
|
||||
"""
|
||||
down command binding
|
||||
"""
|
||||
con = FunctionBindings.__setup()
|
||||
generic_formatter(con.down(extra_args[0]))
|
||||
generic_formatter(con.down(args.stackname))
|
||||
con.disconnect()
|
||||
|
||||
@staticmethod
|
||||
def help():
|
||||
"""
|
||||
exit command binding - This should never be invoked
|
||||
"""
|
||||
print("WTF")
|
||||
|
|
|
@ -1,90 +1,104 @@
|
|||
from typing import List
|
||||
from ...models import Command
|
||||
from ...models.command import HelpNamespace, HelpParser, HostNamespace, HostnameParser, LoginNamespace, LoginParser, StacknameNamespace, StacknameParser
|
||||
from .functions import FunctionBindings
|
||||
|
||||
mapping: List[Command] = [
|
||||
Command(
|
||||
cmd="host",
|
||||
description="Sets and gets the URI of the dockge instance. Remove any unnecessary subdomains/protocols from the URI",
|
||||
args=1,
|
||||
optional=True,
|
||||
func=FunctionBindings.host
|
||||
func=FunctionBindings.host,
|
||||
namespace=HostNamespace(),
|
||||
parser=HostnameParser
|
||||
),
|
||||
Command(
|
||||
cmd="login",
|
||||
description="Logs into a given dockge account, either with an interactive dialogue or by passing --user and --password",
|
||||
args=2,
|
||||
optional=True,
|
||||
func=FunctionBindings.login
|
||||
func=FunctionBindings.login,
|
||||
namespace=LoginNamespace(),
|
||||
parser=LoginParser
|
||||
),
|
||||
Command(
|
||||
cmd="logout",
|
||||
description="Removes the credentials from the local storage.",
|
||||
args=0,
|
||||
optional=False,
|
||||
func=FunctionBindings.logout
|
||||
func=FunctionBindings.logout,
|
||||
namespace=None,
|
||||
parser=None
|
||||
),
|
||||
Command(
|
||||
cmd="list",
|
||||
description="Lists all available stacks with their status",
|
||||
args=0,
|
||||
optional=False,
|
||||
func=FunctionBindings.list
|
||||
func=FunctionBindings.list,
|
||||
namespace=None,
|
||||
parser=None
|
||||
),
|
||||
Command(
|
||||
cmd="status",
|
||||
description="Returns the status of one stack",
|
||||
args=1,
|
||||
optional=False,
|
||||
func=FunctionBindings.status
|
||||
func=FunctionBindings.status,
|
||||
namespace=StacknameNamespace(),
|
||||
parser=StacknameParser
|
||||
|
||||
),
|
||||
Command(
|
||||
cmd="restart",
|
||||
description="Restarts a given stack",
|
||||
args=1,
|
||||
optional=False,
|
||||
func=FunctionBindings.restart
|
||||
func=FunctionBindings.restart,
|
||||
namespace=StacknameNamespace(),
|
||||
parser=StacknameParser
|
||||
),
|
||||
Command(
|
||||
cmd="start",
|
||||
description="Starts a given stack",
|
||||
args=1,
|
||||
optional=False,
|
||||
func=FunctionBindings.start
|
||||
func=FunctionBindings.start,
|
||||
namespace=StacknameNamespace(),
|
||||
parser=StacknameParser
|
||||
),
|
||||
Command(
|
||||
cmd="stop",
|
||||
description="Stops a given stack",
|
||||
args=1,
|
||||
optional=False,
|
||||
func=FunctionBindings.stop
|
||||
func=FunctionBindings.stop,
|
||||
namespace=StacknameNamespace(),
|
||||
parser=StacknameParser
|
||||
),
|
||||
Command(
|
||||
cmd="down",
|
||||
description="Stop & Downs a given stack",
|
||||
args=1,
|
||||
optional=False,
|
||||
func=FunctionBindings.down
|
||||
func=FunctionBindings.down,
|
||||
namespace=StacknameNamespace(),
|
||||
parser=StacknameParser
|
||||
),
|
||||
Command(
|
||||
cmd="update",
|
||||
description="Updates a stack",
|
||||
args=1,
|
||||
optional=False,
|
||||
func=FunctionBindings.update
|
||||
func=FunctionBindings.update,
|
||||
namespace=StacknameNamespace(),
|
||||
parser=StacknameParser
|
||||
),
|
||||
Command(
|
||||
cmd="exit",
|
||||
description="Exits the CLI - this will reset all settings, including credentials and host",
|
||||
args=0,
|
||||
optional=False,
|
||||
func=FunctionBindings.exit
|
||||
func=FunctionBindings.exit,
|
||||
namespace=None,
|
||||
parser=None
|
||||
),
|
||||
Command(
|
||||
cmd="help",
|
||||
description="Displays helping hints for commands",
|
||||
args=1,
|
||||
optional=True,
|
||||
func=FunctionBindings.help
|
||||
func=None, # type: ignore
|
||||
namespace=HelpNamespace(),
|
||||
parser=HelpParser
|
||||
)
|
||||
]
|
||||
|
||||
commands: dict[str, Command] = { c.cmd: c for c in mapping }
|
||||
|
||||
def helpfunc(args: HelpNamespace):
|
||||
if args.command is None:
|
||||
print("WTF")
|
||||
return
|
||||
if args.command not in commands:
|
||||
raise ValueError("Unknown command")
|
||||
print(f"{commands[args.command].description}")
|
||||
|
||||
commands["help"].func = helpfunc
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
from .commands import commands
|
||||
|
||||
def display_help(extra_args):
|
||||
"""
|
||||
Display help dialogues for each command
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Runs a given command with the provided args
|
||||
|
@ -22,14 +9,7 @@ def run(command, args):
|
|||
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.func(args)
|
||||
parsed = None
|
||||
if c.parser is not None:
|
||||
parsed, _ = c.parser.parse_known_args(args, namespace=c.namespace)
|
||||
c.func(parsed)
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
import argparse
|
||||
from tabulate import tabulate
|
||||
from ..models import StackStatus
|
||||
|
||||
def credential_parser_factory():
|
||||
"""
|
||||
Creates a new parser for login credentials
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Prints a given stack list formatted as a table
|
||||
|
|
|
@ -1,12 +1,49 @@
|
|||
from typing import Callable
|
||||
from pydantic import BaseModel
|
||||
from argparse import Namespace, ArgumentParser
|
||||
from typing import Callable, Optional
|
||||
|
||||
class Command(BaseModel):
|
||||
class Command:
|
||||
"""
|
||||
Basic command structure for the CLI to automatically generate valid commands
|
||||
"""
|
||||
cmd: str
|
||||
func: Callable
|
||||
args: int
|
||||
optional: bool
|
||||
description: str
|
||||
namespace: Optional[Namespace]
|
||||
parser: Optional[ArgumentParser]
|
||||
|
||||
def __init__(self, cmd: str, func: Callable, description: str, namespace: Optional[Namespace], parser: Optional[ArgumentParser] ):
|
||||
self.cmd = cmd
|
||||
self.func = func
|
||||
self.description = description
|
||||
self.namespace = namespace
|
||||
self.parser = parser
|
||||
|
||||
class HelpNamespace(Namespace):
|
||||
"""Namespace for help command"""
|
||||
command: str
|
||||
|
||||
HelpParser = ArgumentParser(prog="help", description="Subparser for help command")
|
||||
HelpParser.add_argument("command", nargs="?", default=None, action="store", type=str)
|
||||
|
||||
class StacknameNamespace(Namespace):
|
||||
"""Namespace for update command"""
|
||||
stackname: str
|
||||
|
||||
StacknameParser = ArgumentParser(prog="stack", description="Subparser for stack command")
|
||||
StacknameParser.add_argument("stackname", action="store", type=str)
|
||||
|
||||
class HostNamespace(Namespace):
|
||||
"""Namespace for host command"""
|
||||
uri: Optional[str]
|
||||
|
||||
HostnameParser = ArgumentParser(prog="host", description="Subparser for host command")
|
||||
HostnameParser.add_argument("uri", nargs="?", default=None, action="store", type=str)
|
||||
|
||||
class LoginNamespace(Namespace):
|
||||
"""Namespace for login command"""
|
||||
username: Optional[str]
|
||||
password: Optional[str]
|
||||
|
||||
LoginParser = ArgumentParser(prog="login", description="Subparser for login command")
|
||||
LoginParser.add_argument("--username", action="store", default=None ,type=str, dest="username")
|
||||
LoginParser.add_argument("--password", action="store", default=None ,type=str, dest="password")
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "dockge_cli"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0-c.1"
|
||||
dependencies = [
|
||||
"pyyaml~=6.0.1",
|
||||
"pydantic~=2.8.0",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue