Shell completion

pull/7/head
Micke Nordin 2 years ago
parent 9791c72a6e
commit 149dc17019
Signed by: micke
GPG Key ID: 0DA0A7A5708FE257

@ -6,10 +6,11 @@ https://gitlab.nic.cz/knot/knot-dns-rest
## Usage ## Usage
``` ```
usage: knotctl [-h] [--json | --no-json] {add,config,delete,list,update} ... usage: knotctl [-h] [--json | --no-json]
{add,complete,config,delete,list,update} ...
positional arguments: positional arguments:
{add,config,delete,list,update} {add,complete,config,delete,list,update}
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
@ -27,6 +28,31 @@ options:
-t TTL, --ttl TTL -t TTL, --ttl TTL
-z ZONE, --zone ZONE -z ZONE, --zone ZONE
``` ```
### COMPLETE
```
usage: knotctl complete [-h] [-s SHELL]
options:
-h, --help show this help message and exit
-s SHELL, --shell SHELL
```
For bash: add this to .bashrc
```
eval "$(knotctl complete)"
```
For fish, run:
```
knotctl complete --shell fish > ~/.config/fish/completions/knotctl.fish
```
For tcsh: add this to .cshrc
```
eval "$(knotctl complete --shell tcsh)"
```
For zsh: add this to .zshrc
```
eval "$(autoload -U bashcompinit; bashcompinit; scripts/knotctl complete)"
```
### CONFIG ### CONFIG
``` ```
usage: knotctl config [-h] [-b BASEURL] [-p PASSWORD] [-u USERNAME] usage: knotctl config [-h] [-b BASEURL] [-p PASSWORD] [-u USERNAME]

@ -3,8 +3,8 @@
import argparse import argparse
import getpass import getpass
import json import json
import os
import sys import sys
import urllib.parse
from collections.abc import Sequence from collections.abc import Sequence
from os import environ, mkdir from os import environ, mkdir
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
@ -16,6 +16,7 @@ import yaml
from requests.models import HTTPBasicAuth from requests.models import HTTPBasicAuth
# Helper functions
def error(description: str, error: str) -> Sequence[dict]: def error(description: str, error: str) -> Sequence[dict]:
response = [] response = []
reply = {} reply = {}
@ -32,16 +33,6 @@ def get_config(config_filename: str):
return yaml.safe_load(fh.read()) return yaml.safe_load(fh.read())
def output(response: Sequence[dict], jsonout: bool = False):
try:
if jsonout:
print(json.dumps(response))
else:
print(nested_out(response))
except BrokenPipeError:
pass
def nested_out(input, tabs="") -> str: def nested_out(input, tabs="") -> str:
string = "" string = ""
if isinstance(input, str) or isinstance(input, int): if isinstance(input, str) or isinstance(input, int):
@ -56,13 +47,33 @@ def nested_out(input, tabs="") -> str:
return string return string
# Define the parser for each command def output(response: Sequence[dict], jsonout: bool = False):
try:
if jsonout:
print(json.dumps(response))
else:
print(nested_out(response))
except BrokenPipeError:
pass
# Define the runner for each command
def run_add(url: str, jsonout: bool, headers: dict): def run_add(url: str, jsonout: bool, headers: dict):
print(url) print(url)
response = requests.put(url, headers=headers) response = requests.put(url, headers=headers)
output(response.json(), jsonout) output(response.json(), jsonout)
def run_complete(shell: Union[None, str]):
if not shell or shell in ["bash", "zsh"]:
os.system("register-python-argcomplete knotctl")
elif shell == "fish":
os.system("register-python-argcomplete --shell fish knotctl")
elif shell == "tcsh":
os.system("register-python-argcomplete --shell tcsh knotctl",
shell=True)
def run_config( def run_config(
config_filename: str, config_filename: str,
baseurl: Union[None, str] = None, baseurl: Union[None, str] = None,
@ -150,32 +161,8 @@ def setup_url(
return url return url
# Entry point to program
def main() -> int: def main() -> int:
config_basepath = join(environ["HOME"], ".knot")
config_filename = join(config_basepath, "config")
if not isdir(config_basepath):
mkdir(config_basepath)
if not isfile(config_filename):
print("You need to configure knotctl before proceeding")
run_config(config_filename)
configcmd = get_config(config_filename)
baseurl = configcmd["baseurl"]
username = configcmd["username"]
password = configcmd["password"]
# Authenticate
basic = HTTPBasicAuth(username, password)
response = requests.get(baseurl + "/user/login", auth=basic)
try:
token = response.json()["token"]
except KeyError:
output(response.json())
return 1
headers = {"Authorization": "Bearer {}".format(token)}
# Grab user input # Grab user input
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--json", action=argparse.BooleanOptionalAction) parser.add_argument("--json", action=argparse.BooleanOptionalAction)
@ -187,6 +174,9 @@ def main() -> int:
addcmd.add_argument("-t", "--ttl", required=True) addcmd.add_argument("-t", "--ttl", required=True)
addcmd.add_argument("-z", "--zone", required=True) addcmd.add_argument("-z", "--zone", required=True)
completecmd = subparsers.add_parser("complete")
completecmd.add_argument("-s", "--shell")
configcmd = subparsers.add_parser("config") configcmd = subparsers.add_parser("config")
configcmd.add_argument("-b", "--baseurl") configcmd.add_argument("-b", "--baseurl")
configcmd.add_argument("-p", "--password") configcmd.add_argument("-p", "--password")
@ -213,6 +203,36 @@ def main() -> int:
argcomplete.autocomplete(parser) argcomplete.autocomplete(parser)
args = parser.parse_args() args = parser.parse_args()
if args.command == "complete":
run_complete(args.shell)
return 0
# Make sure we have config
config_basepath = join(environ["HOME"], ".knot")
config_filename = join(config_basepath, "config")
if not isdir(config_basepath):
mkdir(config_basepath)
if not isfile(config_filename):
if args.command != "config":
print("You need to configure knotctl before proceeding")
run_config(config_filename)
config = get_config(config_filename)
baseurl = config["baseurl"]
username = config["username"]
password = config["password"]
# Authenticate
basic = HTTPBasicAuth(username, password)
response = requests.get(baseurl + "/user/login", auth=basic)
try:
token = response.json()["token"]
except KeyError:
output(response.json())
return 1
headers = {"Authorization": "Bearer {}".format(token)}
# Route based on command # Route based on command
ttl = None ttl = None

Loading…
Cancel
Save