wip: shell integration, fixing cli
This commit is contained in:
parent
dcb27eecc1
commit
b8df31f036
26
iam/app.py
26
iam/app.py
@ -12,7 +12,7 @@ from . import exceptions as error
|
||||
from .catalog import Catalog
|
||||
from .framework import DictItem, scoped_ident
|
||||
from .idents import Idents
|
||||
from .lib.utils import import_module, open_yaml
|
||||
from .lib.utils import import_module, open_yaml, get_root_pkg_dir
|
||||
from .meta import NAME, VERSION
|
||||
from .providers import Providers
|
||||
|
||||
@ -181,10 +181,26 @@ class App:
|
||||
ret = {svc.name: svc.list_cmds() for svc in self.catalog.services.values()}
|
||||
return ret
|
||||
|
||||
def shell_enable(self):
|
||||
def shell_enable(self, **kwargs):
|
||||
"Enable shell"
|
||||
return self.catalog.shell_enable()
|
||||
return self.catalog.shell_enable(**kwargs)
|
||||
|
||||
def shell_disable(self):
|
||||
def shell_disable(self, **kwargs):
|
||||
"Disable shell"
|
||||
return self.catalog.shell_disable()
|
||||
return self.catalog.shell_disable(**kwargs)
|
||||
|
||||
|
||||
def shell_install(self, shell="bash"):
|
||||
"Install iam in shell"
|
||||
|
||||
assets_dir = os.path.join(get_root_pkg_dir("iam"), "assets")
|
||||
|
||||
|
||||
if shell == "bash":
|
||||
config_file = ".bashrc"
|
||||
template_file = os.path.join(assets_dir, "init_bash.sh")
|
||||
|
||||
else:
|
||||
raise Exception(f"Unsupported shell: {shell}")
|
||||
|
||||
return f"source {template_file}"
|
||||
180
iam/assets/init_bash.sh
Normal file
180
iam/assets/init_bash.sh
Normal file
@ -0,0 +1,180 @@
|
||||
|
||||
# Workllow
|
||||
#
|
||||
# API
|
||||
# i <ident>
|
||||
# i status <ident>
|
||||
# i switch <ident>
|
||||
# i disable <ident>
|
||||
# i help
|
||||
# i FORWARD
|
||||
|
||||
# ${debian_chroot:+($debian_chroot)}\u@\h:\w\$
|
||||
|
||||
|
||||
#IAM_BIN=/home/jez/volumes/data/prj/jez/lab/iam-python/.direnv/python-3.11.3/bin/iam
|
||||
IAM_BIN=$(command -v iam)
|
||||
IAM_IDENT=
|
||||
|
||||
_usage ()
|
||||
{
|
||||
echo "iam shell wrapper"
|
||||
|
||||
cat << EOF
|
||||
|
||||
Usage:
|
||||
i [status] Show shell status
|
||||
i switch IDENT Enable shell identity
|
||||
i disable Disable shell identity
|
||||
i kill Disable and kill shell identity
|
||||
i help Show this help
|
||||
|
||||
Informations:
|
||||
IAM_BIN=${IAM_BIN}
|
||||
SHELL_IDENT=${SHELL_IDENT:-_}
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
i ()
|
||||
{
|
||||
# set -x
|
||||
|
||||
# Get status
|
||||
target_ident=_
|
||||
current_ident=${SHELL_IDENT:-_}
|
||||
available_idents=$($IAM_BIN shell idents -O words)
|
||||
|
||||
# Internal vars
|
||||
remaining_args=
|
||||
idents_pattern=:${available_idents// /:}:
|
||||
index=0
|
||||
action=
|
||||
|
||||
|
||||
while [[ -n "${1-}" ]] ; do
|
||||
local arg=$1
|
||||
|
||||
case "$arg" in
|
||||
status|st)
|
||||
action=status
|
||||
shift 1
|
||||
if [[ -n "${1}" ]]; then
|
||||
target_ident=$1
|
||||
shift 1
|
||||
fi
|
||||
;;
|
||||
switch|enable|en)
|
||||
action=switch
|
||||
shift 1
|
||||
if [[ -n "${1}" ]]; then
|
||||
target_ident=$1
|
||||
shift 1
|
||||
fi
|
||||
;;
|
||||
disable|dis|q)
|
||||
action=disable
|
||||
shift 1
|
||||
;;
|
||||
kill|k)
|
||||
action=kill
|
||||
shift 1
|
||||
;;
|
||||
stop|K)
|
||||
action=kill_all
|
||||
shift 1
|
||||
;;
|
||||
help|--help|-h)
|
||||
action=help
|
||||
shift 1
|
||||
;;
|
||||
*)
|
||||
if [[ "$idents_pattern" == *":$arg:"* ]]; then
|
||||
action=switch
|
||||
target_ident=$arg
|
||||
shift 1
|
||||
else
|
||||
remaining_args="$remaining_args $arg"
|
||||
shift 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
((index++))
|
||||
done
|
||||
|
||||
if [[ -z "$action" ]]; then
|
||||
action="idents"
|
||||
fi
|
||||
|
||||
|
||||
# echo "Current Ident: $current_ident"
|
||||
# echo "Target Ident: $target_ident"
|
||||
# echo "Action: $action"
|
||||
|
||||
case "$action" in
|
||||
idents)
|
||||
echo "Iam path: ${IAM_BIN}"
|
||||
echo "Current ident: ${SHELL_IDENT:-<None>}"
|
||||
echo "Available identities: $($IAM_BIN shell idents -O words)"
|
||||
;;
|
||||
|
||||
switch)
|
||||
# if [[ "$current_ident" != '_' ]]; then
|
||||
# eval $IAM_BIN shell disable $current_ident
|
||||
# fi
|
||||
# $IAM_BIN shell switch $target_ident
|
||||
|
||||
if [[ "$target_ident" != '_' ]]; then
|
||||
>&2 echo "DEBUG: eval: $IAM_BIN shell switch $target_ident"
|
||||
eval "$($IAM_BIN shell switch $target_ident)"
|
||||
fi
|
||||
;;
|
||||
|
||||
disable)
|
||||
if [[ "$current_ident" != '_' ]]; then
|
||||
>&2 echo "DEBUG: eval: $IAM_BIN shell switch"
|
||||
eval "$($IAM_BIN shell disable)"
|
||||
fi
|
||||
;;
|
||||
|
||||
kill)
|
||||
if [[ "$current_ident" != '_' ]]; then
|
||||
>&2 echo "DEBUG: eval: $IAM_BIN shell switch --kill"
|
||||
eval "$($IAM_BIN shell disable --kill)"
|
||||
fi
|
||||
;;
|
||||
|
||||
kill_all)
|
||||
eval "$($IAM_BIN shell kill -a)"
|
||||
;;
|
||||
|
||||
status)
|
||||
echo "IAM_BIN=${IAM_BIN}"
|
||||
echo "SHELL_IDENT=${SHELL_IDENT:-_}"
|
||||
|
||||
#echo $IAM_BIN shell status $current_ident
|
||||
;;
|
||||
help)
|
||||
_usage
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
set +x
|
||||
return
|
||||
|
||||
|
||||
# Source or switch
|
||||
if $source_output; then
|
||||
out=($IAM_BIN $@)
|
||||
echo "SOURCE: $out"
|
||||
else
|
||||
echo $IAM_BIN $@
|
||||
fi
|
||||
|
||||
set +x
|
||||
}
|
||||
|
||||
#i2 $@
|
||||
254
iam/catalog.py
254
iam/catalog.py
@ -9,6 +9,7 @@ from .idents import Ident
|
||||
from .lib.utils import format_render, jinja_render, uniq
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
cli_logger = logging.getLogger("iam.cli")
|
||||
|
||||
|
||||
IamException = error.IamException
|
||||
@ -47,7 +48,18 @@ class ServiceCommand(DictItem):
|
||||
|
||||
default_attrs = {
|
||||
"desc": "Service without description",
|
||||
"cmd": "",
|
||||
|
||||
"cmd": "", # Direct commands to launch
|
||||
|
||||
"shell": "", # Will be run in a shell (or specific shell below)
|
||||
"shell_sh": "",
|
||||
"shell_bash": "",
|
||||
"shell_zsh": "",
|
||||
"shell_fish": "",
|
||||
"shell_bash": "",
|
||||
|
||||
"source": False, # True for enable commands !
|
||||
|
||||
}
|
||||
|
||||
# Overrides
|
||||
@ -55,12 +67,15 @@ class ServiceCommand(DictItem):
|
||||
|
||||
def payload_transform(self, name, kwargs=None):
|
||||
"Transform short form into long form"
|
||||
self.service = self.parent
|
||||
|
||||
payload = self._payload
|
||||
if not isinstance(payload, dict):
|
||||
payload = {"cmd": payload}
|
||||
self._payload = payload
|
||||
|
||||
def cmd_name(self):
|
||||
return self.name.replace("_", " ")
|
||||
|
||||
class Service(DictItem):
|
||||
"Hold provider services"
|
||||
@ -83,9 +98,10 @@ class Service(DictItem):
|
||||
self.catalog = self.parent.catalog
|
||||
|
||||
def init(self):
|
||||
|
||||
ret = {}
|
||||
for cmd_name, cmd in self.commands.items():
|
||||
ret[cmd_name] = ServiceCommand(cmd_name, cmd)
|
||||
ret[cmd_name] = ServiceCommand(cmd_name, cmd, parent=self)
|
||||
self.commands = ret
|
||||
|
||||
# def require_resolved_deps(func):
|
||||
@ -200,7 +216,7 @@ class Service(DictItem):
|
||||
out = cmd.format(**env_var)
|
||||
except KeyError as err:
|
||||
msg = f"Missing variable: {err} for service: {res.key}"
|
||||
# print (msg)
|
||||
logger.warning (msg)
|
||||
out = msg
|
||||
# raise IamException(msg)
|
||||
|
||||
@ -213,6 +229,13 @@ class Service(DictItem):
|
||||
|
||||
# def _list_cmds(self):
|
||||
|
||||
def get_cmds(self):
|
||||
"Get all services commands objects"
|
||||
|
||||
return [cmd for name, cmd in self.commands.items() if not name.startswith("shell")]
|
||||
|
||||
|
||||
|
||||
def list_cmds(self):
|
||||
"List all services commands"
|
||||
|
||||
@ -226,11 +249,15 @@ class Service(DictItem):
|
||||
|
||||
for cmd_name, conf in self.commands.items():
|
||||
target = ret2["cmds"]
|
||||
|
||||
if cmd_name.startswith(shell_prefix):
|
||||
target = ret2["shell"]
|
||||
cmd_name = cmd_name[len(shell_prefix) :]
|
||||
# cmd_name = cmd_name[len(shell_prefix):]
|
||||
name = f"{cmd_name}_{prefix}"
|
||||
else:
|
||||
|
||||
name = cmd_name.replace("_", " ")
|
||||
|
||||
name = f"{prefix} {cmd_name}"
|
||||
target[name] = conf.desc
|
||||
|
||||
return ret2
|
||||
@ -253,9 +280,76 @@ class Services(DictCtrl):
|
||||
|
||||
items_class = Service
|
||||
|
||||
RESERVED_CMD_PREFIX=["kind", "res", "svc", "shell", "run"]
|
||||
|
||||
def prepare(self):
|
||||
self.catalog = self.parent
|
||||
|
||||
|
||||
|
||||
def get_svc_command(self, cmd):
|
||||
"Return the command to be run"
|
||||
|
||||
# Prepare context
|
||||
cmd_parts = cmd
|
||||
if isinstance(cmd, str):
|
||||
cmd_parts = cmd.split(" ")
|
||||
cmd_req = " ".join(cmd_parts)
|
||||
|
||||
# Retrieve command list
|
||||
cmds = self.list_cmds()
|
||||
cmd_names = [cmd.name for cmd in cmds ]
|
||||
|
||||
|
||||
# Find best matching command
|
||||
cmd_split_idx = None
|
||||
cmd = None
|
||||
curr=None
|
||||
for index, part in enumerate(cmd_parts):
|
||||
curr = f"{curr} {part}" if curr is not None else part
|
||||
if curr in cmd_names:
|
||||
cmd_idx = cmd_names.index(curr)
|
||||
cmd = cmds[cmd_idx]
|
||||
cmd_split_idx = index + 1
|
||||
break
|
||||
|
||||
# Validate result
|
||||
if not cmd:
|
||||
_choices = ','.join(cmd_names)
|
||||
_msg = f"No such services command named: {cmd_req}, please choose one of: {_choices}"
|
||||
raise error.UnknownServiceCommand(_msg)
|
||||
|
||||
args = cmd_parts[cmd_split_idx:]
|
||||
|
||||
return cmd, args
|
||||
|
||||
|
||||
|
||||
def list_cmds(self):
|
||||
"List all services commands"
|
||||
|
||||
ret = []
|
||||
for name, service in self.items():
|
||||
cmds = service.get_cmds()
|
||||
ret.extend(cmds)
|
||||
|
||||
# Check for invalid configs
|
||||
conf = []
|
||||
for cmd in ret:
|
||||
prefix = cmd.name.split(" ")[0]
|
||||
if prefix in self.RESERVED_CMD_PREFIX:
|
||||
_msg = f'Forbidden prefix! {cmd}'
|
||||
raise Exception (_msg)
|
||||
conf.append(cmd.name )
|
||||
dump = uniq(conf)
|
||||
|
||||
if conf != dump:
|
||||
_msg = f'Duplicates values! {conf}'
|
||||
raise Exception (_msg)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def get_linked_resources(self):
|
||||
"""
|
||||
Like get method, but only grab enabled services
|
||||
@ -798,18 +892,36 @@ class Catalog:
|
||||
|
||||
# return self.services.get_loading_order(reverse=reverse)
|
||||
|
||||
|
||||
# Shell helpers
|
||||
# ================
|
||||
|
||||
def shell_enable(self):
|
||||
def shell_enable(self, run_start=True):
|
||||
"Enable shell"
|
||||
return self._shell_action()
|
||||
|
||||
def shell_disable(self):
|
||||
|
||||
actions = ["shell_enable"]
|
||||
if run_start:
|
||||
actions.insert(0, "shell_start")
|
||||
# logger.warning("Shell Start")
|
||||
# logger.warning("Shell Enable")
|
||||
|
||||
return self._shell_action(actions)
|
||||
|
||||
|
||||
def shell_disable(self, run_stop=False):
|
||||
"Disable shell"
|
||||
return self._shell_action(reverse=True)
|
||||
|
||||
def _shell_action(self, reverse=False):
|
||||
actions = ["shell_disable"]
|
||||
if run_stop:
|
||||
actions.insert(0, "shell_stop")
|
||||
# cli_logger.info("Shell Stop")
|
||||
# cli_logger.info("Shell Disable")
|
||||
|
||||
return self._shell_action(actions)
|
||||
|
||||
|
||||
def _shell_action(self, action_names, reverse=False):
|
||||
"Run command order"
|
||||
|
||||
ident = self.ident
|
||||
@ -819,12 +931,10 @@ class Catalog:
|
||||
order, services = self.services.get_loading_order(reverse=reverse)
|
||||
|
||||
# Prepare context
|
||||
action_name = "shell_enable"
|
||||
log_action_name = "Enable"
|
||||
if reverse:
|
||||
action_name = "shell_disable"
|
||||
log_action_name = "Disable"
|
||||
logger.info(f"{log_action_name} identity: {ident.name}")
|
||||
cli_logger.info(f"Identity {ident.name} action: {','.join(action_names)}")
|
||||
|
||||
# Execute on each plugins commands
|
||||
output_code = []
|
||||
@ -833,38 +943,102 @@ class Catalog:
|
||||
res = services[srv_name].res
|
||||
|
||||
# Load service command
|
||||
command = service.commands.get(action_name, None)
|
||||
if not command:
|
||||
continue
|
||||
for action_name in action_names:
|
||||
command = service.commands.get(action_name, None)
|
||||
if not command:
|
||||
continue
|
||||
|
||||
# Build loop with at least ONE item
|
||||
cmd = command.cmd
|
||||
if not cmd:
|
||||
continue
|
||||
# Build loop with at least ONE item
|
||||
cmd = command.cmd
|
||||
if not cmd:
|
||||
continue
|
||||
|
||||
# Create context var dict
|
||||
ctx_vars = dict()
|
||||
ctx_vars.update(service.input)
|
||||
ctx_vars.update(vars)
|
||||
ctx_vars.update(res.resolve_inputs(vars=ctx_vars))
|
||||
# Create context var dict
|
||||
ctx_vars = dict()
|
||||
ctx_vars.update(service.input)
|
||||
ctx_vars.update(vars)
|
||||
ctx_vars.update(res.resolve_inputs(vars=ctx_vars))
|
||||
|
||||
loops = res.loop_extend() or [res]
|
||||
res_vars = [x.resolve_inputs(vars=ctx_vars) for x in loops]
|
||||
loops = res.loop_extend() or [res]
|
||||
res_vars = [x.resolve_inputs(vars=ctx_vars) for x in loops]
|
||||
|
||||
ctx_vars.update(
|
||||
{
|
||||
"item": res_vars[0],
|
||||
"loop": res_vars,
|
||||
}
|
||||
)
|
||||
ctx_vars.update(
|
||||
{
|
||||
"item": res_vars[0],
|
||||
"loop": res_vars,
|
||||
}
|
||||
)
|
||||
|
||||
logger.debug(f"{log_action_name} service: {res.name}")
|
||||
logger.debug(f"{log_action_name} service: {res.name}")
|
||||
|
||||
# pprint (ctx_vars)
|
||||
cmd = jinja_render(cmd, ctx_vars)
|
||||
output_code.append(f"# Loading of {res.name} ({service.name})")
|
||||
output_code.append(f"# =====================")
|
||||
output_code.append(cmd)
|
||||
output_code.append("\n")
|
||||
# pprint (ctx_vars)
|
||||
cmd = jinja_render(cmd, ctx_vars)
|
||||
output_code.append(f"# Loading: {action_name} {res.name} ({service.name})")
|
||||
output_code.append(f"# =====================")
|
||||
output_code.append(cmd)
|
||||
output_code.append("\n")
|
||||
|
||||
return "\n".join(output_code)
|
||||
|
||||
|
||||
|
||||
|
||||
def run_svc_cmd(self, cmd):
|
||||
"Run a command against the services"
|
||||
|
||||
cmd, args = self.services.get_svc_command(cmd)
|
||||
|
||||
|
||||
|
||||
|
||||
# pprint (cmd.cmd)
|
||||
pprint (args)
|
||||
|
||||
service = cmd.service
|
||||
|
||||
pprint (service)
|
||||
pprint (service.__dict__)
|
||||
# pprint (dir(service))
|
||||
res = service.get_linked_resource()
|
||||
# pprint (res)
|
||||
|
||||
vars = self.context.get_vars()
|
||||
|
||||
ctx_vars = dict()
|
||||
ctx_vars.update(vars)
|
||||
ctx_vars.update(service.inputs)
|
||||
|
||||
# ctx_vars.update(res.resolve_inputs(vars=ctx_vars))
|
||||
|
||||
# loops = res.loop_extend() or [res]
|
||||
# res_vars = [x.resolve_inputs(vars=ctx_vars) for x in loops]
|
||||
|
||||
# ctx_vars.update(
|
||||
# {
|
||||
# "item": res_vars[0],
|
||||
# "loop": res_vars,
|
||||
# }
|
||||
# )
|
||||
|
||||
pprint (ctx_vars)
|
||||
|
||||
|
||||
if cmd.cmd:
|
||||
mode = "cmd"
|
||||
payload = cmd.cmd
|
||||
real_cmd = jinja_render(payload, ctx_vars)
|
||||
|
||||
|
||||
elif cmd.shell:
|
||||
mode = "shell"
|
||||
payload = cmd.shell
|
||||
real_cmd = jinja_render(payload, ctx_vars)
|
||||
|
||||
|
||||
else:
|
||||
raise Exception("MIssing cmd or shell in config !")
|
||||
|
||||
|
||||
|
||||
|
||||
print ("RUN CMD", mode, "\n\n\n====\n", real_cmd)
|
||||
240
iam/cli_click.py
240
iam/cli_click.py
@ -45,7 +45,7 @@ else:
|
||||
import rich_click as click
|
||||
from rich_click import RichGroup
|
||||
|
||||
from rich import box, print
|
||||
from rich import box #, print
|
||||
from rich.console import Console
|
||||
# Overrides defaults
|
||||
from rich.pretty import pprint
|
||||
@ -67,6 +67,8 @@ else:
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
cli_logger = logging.getLogger("iam.cli")
|
||||
|
||||
|
||||
# Global vars
|
||||
# ======================
|
||||
@ -97,7 +99,7 @@ DEFAULT_LOG_LEVEL = 30 # warning
|
||||
DEBUG = os.environ.get("IAM_DEBUG", "False")
|
||||
DEFAULT_IDENT = os.environ.get("IAM_IDENT", os.environ.get("SHELL_IDENT", ""))
|
||||
DEFAULT_FORMAT = os.environ.get("IAM_FORMAT", "table")
|
||||
|
||||
DEFAULT_HELP_OPTIONS=["-h", "--help"]
|
||||
|
||||
# list_view.formats_enum
|
||||
|
||||
@ -110,7 +112,7 @@ _cmd2_options = [click.option("--cmd2-opt")]
|
||||
|
||||
CONTEXT_SETTINGS = dict(
|
||||
show_default=True,
|
||||
help_option_names=["-h", "--help"],
|
||||
help_option_names=DEFAULT_HELP_OPTIONS,
|
||||
auto_envvar_prefix=APP_NAME.upper(),
|
||||
)
|
||||
|
||||
@ -219,7 +221,8 @@ def get_var(name, default=None):
|
||||
|
||||
|
||||
# @click.group(cls=NestedHelpGroup, context_settings=CONTEXT_SETTINGS)
|
||||
@click.group(cls=NestedHelpGroup)
|
||||
@click.group(cls=NestedHelpGroup
|
||||
)
|
||||
@global_options
|
||||
@format_options
|
||||
@click.version_option()
|
||||
@ -259,7 +262,7 @@ def cli_app(
|
||||
# Define loggers
|
||||
loggers = {
|
||||
"iam": {"level": log_level},
|
||||
"iam.cli": {"level": "INFO"},
|
||||
"iam.cli": {"level": "DEBUG", "handlers": ["info"]},
|
||||
}
|
||||
|
||||
# Instanciate logger
|
||||
@ -275,8 +278,6 @@ def cli_app(
|
||||
"table_settings": table_box_params,
|
||||
}
|
||||
|
||||
pprint(cli_config)
|
||||
|
||||
render_item = lambda *args, conf={}, **kwargs: item_view.render(
|
||||
*args, conf={**render_config, **prune(conf)}, **kwargs
|
||||
)
|
||||
@ -630,7 +631,7 @@ def svc_show(ctx, name, fmt_name=None, fmt_fields=None, fmt_sort=None, verbose=N
|
||||
def svc_commands(ctx, fmt_name=None, fmt_fields=None, fmt_sort=None, verbose=None):
|
||||
"Show service"
|
||||
|
||||
columns = ["name", "type", "desc"]
|
||||
columns = ["service", "name", "type", "desc"]
|
||||
|
||||
data = []
|
||||
for svc_name, svc in ctx.obj.app.list_services().items():
|
||||
@ -641,10 +642,7 @@ def svc_commands(ctx, fmt_name=None, fmt_fields=None, fmt_sort=None, verbose=Non
|
||||
for cmd_name, conf in items.items():
|
||||
# target[cmd_name] = conf
|
||||
|
||||
data.append([cmd_name, source, conf])
|
||||
|
||||
# pprint(ret)
|
||||
# pprint(ret, expand_all=True)
|
||||
data.append([svc_name, cmd_name, source, conf])
|
||||
|
||||
# Render data
|
||||
ctx.obj.render_list(
|
||||
@ -659,7 +657,7 @@ def svc_commands(ctx, fmt_name=None, fmt_fields=None, fmt_sort=None, verbose=Non
|
||||
)
|
||||
|
||||
|
||||
@cli__svc.command("run")
|
||||
@cli__svc.command("run_v1")
|
||||
@click.argument("name")
|
||||
@click.argument("command")
|
||||
@format_options
|
||||
@ -687,23 +685,12 @@ def cli__shell():
|
||||
@format_options
|
||||
@click.pass_context
|
||||
def shell_idents(
|
||||
ctx, fmt_name=None, fmt_fields=None, fmt_sort=None, verbose=None, reverse=False
|
||||
ctx, fmt_name=None, fmt_fields=None, fmt_sort=None, verbose=None,
|
||||
):
|
||||
"Shell identities"
|
||||
columns = ["name"]
|
||||
data = [[x] for x in ctx.obj.app.get_idents()]
|
||||
|
||||
# print(" ".join(ret))
|
||||
|
||||
# return
|
||||
|
||||
# columns = ["order", "name"]
|
||||
# data = []
|
||||
# services, _ = ctx.obj.app.catalog.services.get_loading_order(reverse=reverse)
|
||||
# for index, name in enumerate(services):
|
||||
# # table.add_row(str(index), name)
|
||||
# data.append([str(index), name])
|
||||
|
||||
# Render data
|
||||
ctx.obj.render_list(
|
||||
data,
|
||||
@ -748,44 +735,191 @@ def shell_order(
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@cli__shell.command("enable")
|
||||
@click.argument("ident")
|
||||
# @format_options
|
||||
@click.option(
|
||||
"skip_start", "--no-start", "-b", is_flag=True, show_default=False, default=False, help="Disable background process start"
|
||||
)
|
||||
@click.pass_context
|
||||
def shell_enable(ctx, ident, verbose=None):
|
||||
def shell_enable(ctx, skip_start=True, verbose=None):
|
||||
"Enable identity in shell"
|
||||
|
||||
app = ctx.obj.app
|
||||
print(app.shell_enable(run_start=not skip_start))
|
||||
|
||||
|
||||
|
||||
@cli__shell.command("disable")
|
||||
@click.option(
|
||||
"run_stop", "--kill", "-k", is_flag=True, show_default=False, default=False, help="Kill background process on leave"
|
||||
)
|
||||
@click.pass_context
|
||||
def shell_disable(ctx, run_stop=False, verbose=None):
|
||||
"Disable identity in shell"
|
||||
|
||||
ret = ctx.obj.app.shell_disable(run_stop=run_stop)
|
||||
print(ret)
|
||||
|
||||
|
||||
@cli__shell.command("kill")
|
||||
@click.option(
|
||||
"all_idents", "--all", "-a", is_flag=True, show_default=False, default=False, help="Kill on all users"
|
||||
)
|
||||
@click.pass_context
|
||||
def shell_kill(ctx, all_idents=False, verbose=None):
|
||||
"Disable identity in shell"
|
||||
|
||||
ret = []
|
||||
|
||||
app = ctx.obj.app
|
||||
if not all_idents:
|
||||
ret.append(app.shell_enable(run_start=False))
|
||||
ret.append(app.shell_disable(run_stop=True))
|
||||
|
||||
else:
|
||||
for ident in app.idents.names():
|
||||
cli_logger.warning(f"Kill ident {ident}")
|
||||
app.init_ident(ident)
|
||||
ret.append(app.shell_enable(run_start=False))
|
||||
ret.append(app.shell_disable(run_stop=True))
|
||||
|
||||
print('\n'.join(ret))
|
||||
|
||||
|
||||
|
||||
@cli__shell.command("switch")
|
||||
@click.argument("ident", required=False)
|
||||
# @format_options
|
||||
@click.option(
|
||||
"skip_start", "--no-start", "-b", is_flag=True, show_default=False, default=False, help="Disable background process start"
|
||||
)
|
||||
@click.option(
|
||||
"run_stop", "--kill", "-k", is_flag=True, show_default=False, default=False, help="Kill background process on leave"
|
||||
)
|
||||
|
||||
@click.pass_context
|
||||
def shell_switch(ctx, ident="", run_stop=False, skip_start=True, verbose=None):
|
||||
"Enable identity in shell"
|
||||
|
||||
app = ctx.obj.app
|
||||
|
||||
# Disable existing
|
||||
# logger.info(f"Disabling ident: {app.ident_name}")
|
||||
ret1 = app.shell_disable()
|
||||
print("-- %< --" * 8)
|
||||
print(ret1)
|
||||
print("-- %< --" * 8)
|
||||
|
||||
# Enable new
|
||||
# logger.info(f"Enabling ident: {ident}")
|
||||
app.init_ident(ident)
|
||||
ret2 = app.shell_enable()
|
||||
|
||||
# Output
|
||||
print("-- %< --" * 8)
|
||||
print(ret2)
|
||||
print("-- %< --" * 8)
|
||||
src_ident = app.catalog.ident.name
|
||||
dst_ident = ident
|
||||
|
||||
|
||||
@cli__shell.command("disable")
|
||||
# @format_options
|
||||
if src_ident == dst_ident:
|
||||
print (">&2 echo 'No need to change'")
|
||||
else:
|
||||
ret = []
|
||||
|
||||
# Disable existing
|
||||
# logger.info(f"Disabling ident: {app.ident_name}")
|
||||
ret.append(app.shell_disable(run_stop=run_stop))
|
||||
|
||||
# Enable new
|
||||
# logger.info(f"Enabling ident: {ident}")
|
||||
app.init_ident(dst_ident)
|
||||
ret.append(app.shell_enable(run_start=not skip_start))
|
||||
|
||||
# Output
|
||||
print('\n'.join(ret))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TmpGroup(click.Group):
|
||||
def format_help(self, ctx, formatter):
|
||||
|
||||
val = "List of available commands!"
|
||||
formatter.write(val)
|
||||
|
||||
|
||||
|
||||
@cli_app.command("run",
|
||||
# cls=TmpGroup,
|
||||
context_settings=dict(
|
||||
ignore_unknown_options=True,
|
||||
allow_extra_args=True,
|
||||
help_option_names=[]
|
||||
)
|
||||
)
|
||||
@click.argument('cmd_params', nargs=-1, type=click.UNPROCESSED)
|
||||
@click.pass_context
|
||||
def shell_disable(ctx, verbose=None):
|
||||
"Disable identity in shell"
|
||||
def cli_app_run(ctx, cmd_params):
|
||||
|
||||
ret = ctx.obj.app.shell_disable()
|
||||
print("Will run cmd:", cmd_params)
|
||||
|
||||
print("-- %< --" * 8)
|
||||
# Check first help parameter only
|
||||
show_help = False
|
||||
show_list = False
|
||||
for idx, param in enumerate(cmd_params):
|
||||
if idx == 0:
|
||||
if param in DEFAULT_HELP_OPTIONS:
|
||||
show_help = True
|
||||
if param in ["list", "ls"]:
|
||||
show_list = True
|
||||
|
||||
if show_help:
|
||||
ctx = click.get_current_context()
|
||||
click.echo(ctx.get_help())
|
||||
return
|
||||
|
||||
|
||||
# Get instanciated app
|
||||
app = ctx.obj.app
|
||||
|
||||
if show_list:
|
||||
ret = app.catalog.services.list_cmds()
|
||||
data = [[x.name, x.desc] for x in ret]
|
||||
|
||||
|
||||
# Render data
|
||||
ctx.obj.render_list(
|
||||
data,
|
||||
["name", "desc"],
|
||||
conf={
|
||||
"table_title": f"Services commands",
|
||||
# "fmt_name": fmt_name,
|
||||
# "fmt_sort": fmt_sort,
|
||||
# "fmt_fields": fmt_fields,
|
||||
},
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
# Run the output
|
||||
ret = app.catalog.run_svc_cmd(cmd=cmd_params)
|
||||
pprint (ret, expand_all=True)
|
||||
|
||||
|
||||
|
||||
# @cli_app.command("run2",
|
||||
# context_settings=dict(
|
||||
# ignore_unknown_options=True,
|
||||
# allow_extra_args=True,
|
||||
# )
|
||||
# )
|
||||
# @click.pass_context
|
||||
# def cli_app_run(ctx):
|
||||
# print("Hello world")
|
||||
# pprint (ctx.args)
|
||||
|
||||
# return
|
||||
|
||||
|
||||
@cli__shell.command("install")
|
||||
@click.pass_context
|
||||
def shell_install(ctx, verbose=None):
|
||||
"Install iam in your shell"
|
||||
|
||||
ret = ctx.obj.app.shell_install()
|
||||
|
||||
# print("-- %< --" * 8)
|
||||
print(ret)
|
||||
print("-- %< --" * 8)
|
||||
# print("-- %< --" * 8)
|
||||
|
||||
|
||||
|
||||
# Exception handler
|
||||
@ -796,8 +930,8 @@ def clean_terminate(err):
|
||||
# Choose dead end way
|
||||
if APP_EXCEPTION is not None and isinstance(err, APP_EXCEPTION):
|
||||
err_name = err.__class__.__name__
|
||||
logger.error(err)
|
||||
logger.critical("MyApp exited with error: %s", err_name)
|
||||
# logger.error(err)
|
||||
logger.critical("%s: %s" % (err_name, err))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
192
iam/cli_views.py
192
iam/cli_views.py
@ -1,192 +0,0 @@
|
||||
import enum
|
||||
import logging
|
||||
from enum import Enum
|
||||
from pprint import pformat, pprint
|
||||
from types import SimpleNamespace
|
||||
|
||||
from iam.framework import (empty, get_app_logger, iterate_any, open_yaml,
|
||||
prune, to_csv, to_json, to_yaml)
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.pretty import pprint
|
||||
from rich.prompt import Prompt
|
||||
from rich.table import Table
|
||||
|
||||
from .lib.cli_views import ViewItem, ViewKind, ViewList
|
||||
|
||||
# Iam Implementations
|
||||
# ===============================
|
||||
|
||||
|
||||
MISSING_PKG = []
|
||||
|
||||
try:
|
||||
import hcl2
|
||||
except ModuleNotFoundError:
|
||||
MISSING_PKG.append("hcl2")
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ModuleNotFoundError:
|
||||
MISSING_PKG.append("yaml")
|
||||
|
||||
|
||||
# Main views
|
||||
# ======================
|
||||
|
||||
|
||||
# def view_list(data, columns, title=None, fmt=None, **kwargs):
|
||||
# "Show list view"
|
||||
|
||||
# fmt = fmt or OutputFormat.DEFAULT
|
||||
# ret = None
|
||||
# _kwargs = {
|
||||
# key[len(fmt.value) + 1 :]: val
|
||||
# for key, val in kwargs.items()
|
||||
# if key.startswith(fmt.value)
|
||||
# }
|
||||
|
||||
# # print ("YOOO", fmt, OutputFormat.YAML)
|
||||
# if fmt == OutputFormat.YAML:
|
||||
# ret = to_yaml(restructure_list_to_dict(data, columns))
|
||||
|
||||
# elif fmt == OutputFormat.JSON:
|
||||
# ret = to_json(restructure_list_to_dict(data, columns), nice=True)
|
||||
|
||||
# elif fmt == OutputFormat.PYTHON:
|
||||
# ret = pformat(restructure_list_to_dict(data, columns), indent=2)
|
||||
|
||||
# elif fmt == OutputFormat.CSV:
|
||||
# ret = to_csv(restructure_list_to_csv(data, columns))
|
||||
|
||||
# elif fmt == OutputFormat.ENV:
|
||||
# ret = to_vars(restructure_list_to_env(data, columns), export=True)
|
||||
|
||||
# elif fmt == OutputFormat.VARS:
|
||||
# ret = to_vars(restructure_list_to_env(data, columns))
|
||||
|
||||
# elif fmt == OutputFormat.RICH_TABLE:
|
||||
# ret = to_rich_table(data, columns=columns, title=title, **_kwargs)
|
||||
|
||||
# else:
|
||||
# raise Exception(f"Unmanagable format: {fmt}")
|
||||
|
||||
# console.print(ret)
|
||||
|
||||
|
||||
# def view_show(data, columns=None, title=None):
|
||||
# "Show single view"
|
||||
|
||||
# ret = None
|
||||
# _kwargs = {
|
||||
# key[len(fmt.value) + 1 :]: val
|
||||
# for key, val in kwargs.items()
|
||||
# if key.startswith(fmt.value)
|
||||
# }
|
||||
|
||||
# # print ("YOOO", fmt, OutputFormat.YAML)
|
||||
# if fmt == OutputFormat.YAML:
|
||||
# ret = to_yaml(data)
|
||||
|
||||
# elif fmt == OutputFormat.JSON:
|
||||
# ret = to_json(data, indent=2)
|
||||
|
||||
# elif fmt == OutputFormat.PYTHON:
|
||||
# ret = pformat(data, indent=2)
|
||||
|
||||
# elif fmt == OutputFormat.CSV:
|
||||
# ret = to_csv(data)
|
||||
|
||||
# elif fmt == OutputFormat.RICH_TABLE:
|
||||
# data = list(zip(*data))
|
||||
# data.insert(0, ["Field", "Value"])
|
||||
# ret = to_rich_table(data, **_kwargs)
|
||||
|
||||
# else:
|
||||
# raise Exception(f"Unmanagable format: {fmt}")
|
||||
|
||||
# return ret
|
||||
|
||||
|
||||
# # DEPRECATED
|
||||
# # ======================
|
||||
|
||||
|
||||
# def output_list(payload, fmt=None, **kwargs):
|
||||
# "Render output format"
|
||||
# assert False, "DEPRECATED"
|
||||
# fmt = fmt or OutputFormat.YAML
|
||||
|
||||
# # Requested format
|
||||
# # payload = [
|
||||
# # ["Header1", "Header2"], # First line is always headers
|
||||
# # [["val1", "val2"]], # First row
|
||||
# # [["val1", "val2"]], # Second row, etc ...
|
||||
# # ]
|
||||
|
||||
# ret = None
|
||||
# # _kwargs = {key.lstrip(f"{fmt.value}_"): val for key, val in kwargs.items() if key.startswith(fmt.value)}
|
||||
# _kwargs = {
|
||||
# key[len(fmt.value) + 1 :]: val
|
||||
# for key, val in kwargs.items()
|
||||
# if key.startswith(fmt.value)
|
||||
# }
|
||||
|
||||
# # print ("YOOO", fmt, OutputFormat.YAML)
|
||||
# if fmt == OutputFormat.YAML:
|
||||
# ret = to_yaml(payload)
|
||||
# elif fmt == OutputFormat.JSON:
|
||||
# ret = to_json(payload, indent=2)
|
||||
# elif fmt == OutputFormat.PYTHON:
|
||||
# ret = pformat(payload, indent=2)
|
||||
# elif fmt == OutputFormat.CSV:
|
||||
# ret = to_csv(payload)
|
||||
# elif fmt == OutputFormat.RICH_TABLE:
|
||||
# # pprint (kwargs)
|
||||
# # pprint (_kwargs)
|
||||
# return to_rich_table(payload, **_kwargs)
|
||||
# else:
|
||||
# raise Exception(f"Unmanagable format list: {fmt}")
|
||||
|
||||
# assert isinstance(ret, str)
|
||||
# return ret
|
||||
|
||||
|
||||
# def output_show(payload, fmt=None, **kwargs):
|
||||
# "Show one item"
|
||||
# assert False, "DEPRECATED"
|
||||
|
||||
# # Requested format
|
||||
# # payload = [
|
||||
# # ["Header1", "Header2"], # First line is always headers
|
||||
# # [["val1", "val2"]], # First row ONLY
|
||||
# # [["val1", "val2"]], # Second row, etc ...
|
||||
# # ]
|
||||
|
||||
# ret = None
|
||||
# _kwargs = {
|
||||
# key[len(fmt.value) + 1 :]: val
|
||||
# for key, val in kwargs.items()
|
||||
# if key.startswith(fmt.value)
|
||||
# }
|
||||
|
||||
# # print ("YOOO", fmt, OutputFormat.YAML)
|
||||
# if fmt == OutputFormat.YAML:
|
||||
# ret = to_yaml(payload)
|
||||
|
||||
# elif fmt == OutputFormat.JSON:
|
||||
# ret = to_json(payload, indent=2)
|
||||
# elif fmt == OutputFormat.PYTHON:
|
||||
# ret = pformat(payload, indent=2)
|
||||
# elif fmt == OutputFormat.CSV:
|
||||
# ret = to_csv(payload)
|
||||
# elif fmt == OutputFormat.RICH_TABLE:
|
||||
# # Return data
|
||||
# payload = list(zip(*payload))
|
||||
# payload.insert(0, ["Field", "Value"])
|
||||
# ret = to_rich_table(payload, **_kwargs)
|
||||
|
||||
# else:
|
||||
# raise Exception(f"Unmanagable format show: {fmt}")
|
||||
|
||||
# return ret
|
||||
@ -16,3 +16,7 @@ class UnknownResourceKind(IamException):
|
||||
|
||||
class MissingConfigFiles(IamException):
|
||||
"Raised when iam can't find any valid configuration file"
|
||||
|
||||
|
||||
class UnknownServiceCommand(IamException):
|
||||
"Raised when a command is not matched against services"
|
||||
|
||||
@ -42,12 +42,12 @@ def get_app_logger(loggers=None, level="WARNING", colors=False, format="default"
|
||||
formatters = {
|
||||
"default": {
|
||||
"()": fclass,
|
||||
"format": "[%(levelname)s] %(message)s",
|
||||
"format": "[%(levelname)8s] %(message)s",
|
||||
# 'datefmt': '%Y-%m-%d %H:%M:%S',
|
||||
},
|
||||
"extended": {
|
||||
"()": fclass,
|
||||
"format": "[%(levelname)s] %(name)s: %(message)s",
|
||||
"format": "[%(levelname)8s] %(name)s: %(message)s",
|
||||
"datefmt": "%H:%M:%S",
|
||||
},
|
||||
"audit": {
|
||||
@ -57,7 +57,7 @@ def get_app_logger(loggers=None, level="WARNING", colors=False, format="default"
|
||||
},
|
||||
"debug": {
|
||||
"()": fclass,
|
||||
"format": "%(msecs)03d [%(levelname)s] %(name)s: %(message)s [%(filename)s/%(funcName)s:%(lineno)d]",
|
||||
"format": "%(msecs)03d [%(levelname)8s] %(name)s: %(message)s [%(filename)s/%(funcName)s:%(lineno)d]",
|
||||
"datefmt": "%H:%M:%S",
|
||||
},
|
||||
}
|
||||
@ -81,15 +81,24 @@ def get_app_logger(loggers=None, level="WARNING", colors=False, format="default"
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr", # Default is stderr
|
||||
},
|
||||
"info": {
|
||||
"level": "INFO",
|
||||
"formatter": format,
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr", # Default is stderr
|
||||
},
|
||||
},
|
||||
# Where logs come from
|
||||
"loggers": {
|
||||
|
||||
# Used to catch ALL logs
|
||||
"": { # root logger
|
||||
"handlers": ["default"],
|
||||
"level": "WARNING",
|
||||
"propagate": False,
|
||||
},
|
||||
|
||||
|
||||
# # Used to catch all logs of myapp and sublibs
|
||||
# 'myapp': {
|
||||
# 'handlers': ['default'],
|
||||
@ -297,6 +306,9 @@ class DictCtrl(_DictBase):
|
||||
def keys(self):
|
||||
return self._items.keys()
|
||||
|
||||
def names(self):
|
||||
return list(self._items.keys())
|
||||
|
||||
def has(self, name):
|
||||
"Return true or false if an item exists"
|
||||
return True if name in self._items else False
|
||||
|
||||
@ -16,6 +16,12 @@ except ModuleNotFoundError:
|
||||
MISSING_PKGS.append("Table")
|
||||
|
||||
|
||||
# TODO:
|
||||
# toml/hcl support
|
||||
# duckdb support => https://stackoverflow.com/a/70538527
|
||||
|
||||
|
||||
|
||||
# MISSING_PKGS = []
|
||||
# try:
|
||||
# from rich.console import Console
|
||||
@ -311,33 +317,32 @@ class _RootView:
|
||||
}
|
||||
)
|
||||
fmt_ = SimpleNamespace(**fmt_config)
|
||||
print("FORMAT CONFIG")
|
||||
pprint(conf)
|
||||
pprint(fmt_)
|
||||
# print("FORMAT CONFIG")
|
||||
# pprint(conf)
|
||||
# pprint(fmt_)
|
||||
|
||||
assert fmt_.name, f"Format name can't be None: {fmt_.name}"
|
||||
|
||||
# check module presence
|
||||
pprint(self.formats_modules)
|
||||
mod_spec = self.formats_modules.get(fmt_.name, None)
|
||||
print("MOD_NAME", fmt_.name, mod_spec)
|
||||
if mod_spec:
|
||||
# Extract specs
|
||||
mod_package = None
|
||||
mod_name = mod_spec
|
||||
if isinstance(mod_spec, (list, set, tuple)):
|
||||
mod_name = mod_spec[0]
|
||||
mod_package = mod_spec[1]
|
||||
# if mod_spec:
|
||||
# # Extract specs
|
||||
# mod_package = None
|
||||
# mod_name = mod_spec
|
||||
# if isinstance(mod_spec, (list, set, tuple)):
|
||||
# mod_name = mod_spec[0]
|
||||
# mod_package = mod_spec[1]
|
||||
|
||||
# # Check module presence
|
||||
# # print("CHECKING MODE NAME", mod_name)
|
||||
# ret = is_module_present(mod_name)
|
||||
# if not ret:
|
||||
# _msg = f"Missing python module '{mod_name}' to support '{fmt_.name}' output."
|
||||
# if mod_package:
|
||||
# _msg = f"{_msg} Please first install package: {mod_package}"
|
||||
# logger.warning(_msg)
|
||||
# # raise Exception(_msg)
|
||||
|
||||
# Check module presence
|
||||
print("CHECKING MODE NAME", mod_name)
|
||||
ret = is_module_present(mod_name)
|
||||
if not ret:
|
||||
_msg = f"Missing python module '{mod_name}' to support '{fmt_.name}' output."
|
||||
if mod_package:
|
||||
_msg = f"{_msg} Please first install package: {mod_package}"
|
||||
logger.warning(_msg)
|
||||
# raise Exception(_msg)
|
||||
|
||||
# Fetch renderer method
|
||||
# ---------------------------
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import sys
|
||||
import importlib
|
||||
import json
|
||||
import logging
|
||||
@ -235,9 +236,23 @@ def iterate_any(payload):
|
||||
|
||||
# raise Exception(f"Could not iterate over: {payload}")
|
||||
|
||||
def get_root_pkg_dir(name):
|
||||
"""Return the dir where the actual paasify source code lives"""
|
||||
|
||||
assert not "." in name, "Only resrved for root pacakges"
|
||||
|
||||
# Look into each paths
|
||||
for cand in sys.path:
|
||||
target = os.path.join(cand, name)
|
||||
if os.path.isdir(target):
|
||||
return target
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def get_pkg_dir(name):
|
||||
"""Return the dir where the actual paasify source code lives"""
|
||||
"""Return the dir where the actual paasify source code lives, it loads the module !!!"""
|
||||
|
||||
# pylint: disable=import-outside-toplevel
|
||||
mod = import_module_pkg(name)
|
||||
|
||||
@ -49,11 +49,11 @@ plugin_base = {
|
||||
"desc": "Disable shell ident",
|
||||
"cmd": "unset SHELL_IDENT",
|
||||
},
|
||||
"new": {
|
||||
"id new": {
|
||||
"desc": "Create shell identy",
|
||||
"cmd": "add_ident {{ param }}",
|
||||
},
|
||||
"delete": {
|
||||
"id delete": {
|
||||
"desc": "Delete shell identy",
|
||||
"cmd": "rm_ident {{ param }}",
|
||||
},
|
||||
|
||||
@ -134,12 +134,12 @@ providers:
|
||||
unset MINIO_ACCESS_KEY MINIO_SECRET_KEY
|
||||
|
||||
|
||||
new_alias:
|
||||
minio new alias:
|
||||
desc: Create alias
|
||||
cmd: |
|
||||
mc alias set {{ident}} {{api_url}} {{minio_user}} {{minio_password}}
|
||||
|
||||
rm_alias:
|
||||
minio delete alias:
|
||||
desc: Remove alias
|
||||
cmd: |
|
||||
mc alias rm {{ident}}
|
||||
|
||||
@ -14,9 +14,10 @@ providers:
|
||||
|
||||
commands:
|
||||
|
||||
new:
|
||||
ssh new:
|
||||
desc: Create new SSH key
|
||||
cmd: |
|
||||
|
||||
shell: |
|
||||
SSH_KEY_ALG={{ssh_key_alg}}
|
||||
|
||||
SSH_KEY_VERSION="$(date +'%Y%m%d')"
|
||||
@ -30,7 +31,9 @@ providers:
|
||||
-N "{{ssh_key_secret}}" \
|
||||
-C "$SSH_KEY_COMMENT"
|
||||
|
||||
delete:
|
||||
|
||||
|
||||
ssh delete:
|
||||
desc: Delete existing SSH key
|
||||
cmd: |
|
||||
find $HOME/.ssh/{ident}/ -name "{user}_*"
|
||||
@ -119,28 +122,92 @@ providers:
|
||||
|
||||
commands:
|
||||
|
||||
shell_start:
|
||||
desc: Start ssh-agent
|
||||
cmd: |
|
||||
socket=$HOME/.local/state/ssh-agent/{{user}}
|
||||
start=true
|
||||
|
||||
running=2
|
||||
if [[ ! -e "$socket.env" ]]; then
|
||||
running=2
|
||||
elif [[ -e "$socket" ]]; then
|
||||
running=$(SSH_AUTH_SOCK=$socket ssh-add -l &>/dev/null; echo $rc)
|
||||
fi
|
||||
|
||||
if [[ "$running" -eq 2 ]]; then
|
||||
# Start agent
|
||||
>&2 echo "Start ssh-agent for {{ident}}"
|
||||
mkdir -p "${socket%/*}"
|
||||
ssh-agent -a $socket -t {{ssh_agent_tmout}} > $socket.env
|
||||
fi
|
||||
|
||||
unset socket start running
|
||||
|
||||
# if [[ -d "/run/user/$(id -u)" ]]; then
|
||||
# socket=/run/user/$(id -u)/ssh-agent/{{user}}
|
||||
# else
|
||||
|
||||
# fi
|
||||
|
||||
|
||||
shell_enable:
|
||||
desc: Enable ssh-agent
|
||||
|
||||
cmd: |
|
||||
export SSH_AUTH_SOCK={{ssh_agent_socket_dir}}/{{user}}
|
||||
ssh-agent -a $SSH_AUTH_SOCK -t {{ssh_agent_tmout}}
|
||||
# SSH_AGENT_PID= ???
|
||||
socket=$HOME/.local/state/ssh-agent/{{user}}
|
||||
|
||||
if [[ -e "$socket.env" ]]; then
|
||||
# >&2 echo "Enable ssh-agent for {{ident}}"
|
||||
source "$socket.env" >/dev/null
|
||||
fi
|
||||
|
||||
unset socket
|
||||
|
||||
|
||||
|
||||
shell_disable:
|
||||
desc: Disable ssh-agent
|
||||
cmd: ssh-agent -k && unset SSH_AUTH_SOCK
|
||||
cmd: |
|
||||
unset SSH_AUTH_SOCK SSH_AGENT_PID
|
||||
|
||||
|
||||
shell_stop:
|
||||
desc: Kill ssh-agent
|
||||
cmd: |
|
||||
socket=$HOME/.local/state/ssh-agent/{{user}}
|
||||
|
||||
if [[ -e "$socket.env" ]]; then
|
||||
# >&2 echo "Enable ssh-agent for {{ident}}"
|
||||
source "$socket.env" >/dev/null
|
||||
# fi
|
||||
|
||||
# if [[ -n "$SSH_AGENT_PID" ]]; then
|
||||
>&2 echo "Kill ssh-agent for {{ident}}"
|
||||
eval "(ssh-agent -k)" >/dev/null
|
||||
[[ -e "$socket.env" ]] && rm "$socket.env" || true
|
||||
fi
|
||||
unset socket
|
||||
|
||||
# env_file="$HOME/.local/state/ssh-agent/{{user}}.env"
|
||||
|
||||
# if [[ -f "$env_file" ]]; then
|
||||
# source "$env_file"
|
||||
# fi
|
||||
# if [[ -f "$env_file" ]]; then
|
||||
# rm "$env_file"
|
||||
# fi
|
||||
|
||||
|
||||
local.ssh_agent_keys:
|
||||
desc: Local ssh-agent keys
|
||||
|
||||
commands:
|
||||
enable:
|
||||
ssh add:
|
||||
desc: Unload keys into ssh-agent
|
||||
cmd: ssh-agent -d {ssh_key_file}
|
||||
|
||||
disable:
|
||||
ssh rm:
|
||||
desc: Load keys into ssh-agent
|
||||
cmd: |
|
||||
ssh-add {% for item in loop %} {{item.ssh_key_file}} {% endfor %}
|
||||
@ -263,15 +330,16 @@ providers:
|
||||
commands:
|
||||
|
||||
shell_enable:
|
||||
desc: Enable git identity
|
||||
desc: Enable PS1
|
||||
cmd: |
|
||||
OLD_PS1=$PS1
|
||||
export PS1="\[\033[0;34m\]({{ident}})\[\033[00m\] ${PS1}"
|
||||
export OLD_PS1=$PS1
|
||||
export PS1="\033[0;34m\]({{ident}})\033[00m\] ${PS1}"
|
||||
|
||||
shell_disable:
|
||||
desc: Disable git identity
|
||||
desc: Disable PS1
|
||||
cmd: |
|
||||
export PS1=$OLD_PS1
|
||||
export PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
|
||||
# export PS1="$OLD_PS1"
|
||||
|
||||
|
||||
|
||||
|
||||
169
poetry.lock
generated
169
poetry.lock
generated
@ -1,34 +1,5 @@
|
||||
# This file is automatically @generated by Poetry 1.6.0 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "23.1.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
|
||||
{file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
|
||||
dev = ["attrs[docs,tests]", "pre-commit"]
|
||||
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
|
||||
tests = ["attrs[tests-no-zope]", "zope-interface"]
|
||||
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
|
||||
[[package]]
|
||||
name = "autopage"
|
||||
version = "0.5.1"
|
||||
description = "A library to provide automatic paging for console output"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "autopage-0.5.1-py3-none-any.whl", hash = "sha256:0fbf5efbe78d466a26753e1dee3272423a3adc989d6a778c700e89a3f8ff0d88"},
|
||||
{file = "autopage-0.5.1.tar.gz", hash = "sha256:01be3ee61bb714e9090fcc5c10f4cf546c396331c620c6ae50a2321b28ed3199"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "23.9.1"
|
||||
@ -87,47 +58,6 @@ files = [
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "cliff"
|
||||
version = "4.3.0"
|
||||
description = "Command Line Interface Formulation Framework"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "cliff-4.3.0-py3-none-any.whl", hash = "sha256:db3dc8774f47db9aa86796921ff158d0f023630261c2746c4fff12584b75f5b2"},
|
||||
{file = "cliff-4.3.0.tar.gz", hash = "sha256:fc5b6ebc8fb815332770b2485ee36c09753937c37cce4f3227cdd4e10b33eacc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
autopage = ">=0.4.0"
|
||||
cmd2 = ">=1.0.0"
|
||||
importlib-metadata = ">=4.4"
|
||||
PrettyTable = ">=0.7.2"
|
||||
PyYAML = ">=3.12"
|
||||
stevedore = ">=2.0.1"
|
||||
|
||||
[[package]]
|
||||
name = "cmd2"
|
||||
version = "2.4.3"
|
||||
description = "cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "cmd2-2.4.3-py3-none-any.whl", hash = "sha256:f1988ff2fff0ed812a2d25218a081b0fa0108d45b48ba2a9272bb98091b654e6"},
|
||||
{file = "cmd2-2.4.3.tar.gz", hash = "sha256:71873c11f72bd19e2b1db578214716f0d4f7c8fa250093c601265a9a717dee52"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=16.3.0"
|
||||
pyperclip = ">=1.6"
|
||||
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
wcwidth = ">=0.1.7"
|
||||
|
||||
[package.extras]
|
||||
dev = ["codecov", "doc8", "flake8", "invoke", "mypy", "nox", "pytest (>=4.6)", "pytest-cov", "pytest-mock", "sphinx", "sphinx-autobuild", "sphinx-rtd-theme", "twine (>=1.11)"]
|
||||
test = ["codecov", "coverage", "gnureadline", "pytest (>=4.6)", "pytest-cov", "pytest-mock"]
|
||||
validate = ["flake8", "mypy", "types-pkg-resources"]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
@ -170,25 +100,6 @@ files = [
|
||||
[package.dependencies]
|
||||
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "6.8.0"
|
||||
description = "Read metadata from Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
|
||||
{file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
perf = ["ipython"]
|
||||
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.12.0"
|
||||
@ -350,17 +261,6 @@ files = [
|
||||
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pbr"
|
||||
version = "5.11.1"
|
||||
description = "Python Build Reasonableness"
|
||||
optional = false
|
||||
python-versions = ">=2.6"
|
||||
files = [
|
||||
{file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"},
|
||||
{file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.11.0"
|
||||
@ -376,23 +276,6 @@ files = [
|
||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "prettytable"
|
||||
version = "3.9.0"
|
||||
description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "prettytable-3.9.0-py3-none-any.whl", hash = "sha256:a71292ab7769a5de274b146b276ce938786f56c31cf7cea88b6f3775d82fe8c8"},
|
||||
{file = "prettytable-3.9.0.tar.gz", hash = "sha256:f4ed94803c23073a90620b201965e5dc0bccf1760b7a7eaf3158cab8aaffdf34"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
wcwidth = "*"
|
||||
|
||||
[package.extras]
|
||||
tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"]
|
||||
|
||||
[[package]]
|
||||
name = "pyaml"
|
||||
version = "23.9.6"
|
||||
@ -424,16 +307,6 @@ files = [
|
||||
[package.extras]
|
||||
plugins = ["importlib-metadata"]
|
||||
|
||||
[[package]]
|
||||
name = "pyperclip"
|
||||
version = "1.8.2"
|
||||
description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pyperclip-1.8.2.tar.gz", hash = "sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyreadline3"
|
||||
version = "3.4.1"
|
||||
@ -551,20 +424,6 @@ rich = ">=10.7.0"
|
||||
[package.extras]
|
||||
dev = ["pre-commit"]
|
||||
|
||||
[[package]]
|
||||
name = "stevedore"
|
||||
version = "5.1.0"
|
||||
description = "Manage dynamic plugins for Python applications"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"},
|
||||
{file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.9.0"
|
||||
@ -597,33 +456,7 @@ files = [
|
||||
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.8"
|
||||
description = "Measures the displayed width of unicode strings in a terminal"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "wcwidth-0.2.8-py2.py3-none-any.whl", hash = "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704"},
|
||||
{file = "wcwidth-0.2.8.tar.gz", hash = "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.17.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"},
|
||||
{file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "6c7761768920ef58522d19560d56ce366cca74dc275b4e019acf10838923d63d"
|
||||
content-hash = "1747400a30523d50e0ccaf55386f60f05b4d6e5e222aeb8a737d4e78b702a210"
|
||||
|
||||
@ -20,11 +20,13 @@ pyxdg = "^0.28"
|
||||
coloredlogs = "^15.0.1"
|
||||
rich = "^13.6.0"
|
||||
rich-click = "^1.6.1"
|
||||
colorama = "^0.4.6"
|
||||
|
||||
|
||||
[tool.poetry.scripts]
|
||||
iam2 = "iam.cli:run"
|
||||
iam = "iam.cli_click:run"
|
||||
iam2 = "iam.cli_typer:run"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^23.9.1"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user