From 886c90dd6f33e2eabcb7b37b5780a27322c65b12 Mon Sep 17 00:00:00 2001 From: VAN BOSSUYT Nicolas Date: Mon, 19 Feb 2024 15:29:03 +0100 Subject: [PATCH] Make sure plugins are loaded when printiung help or usages --- cutekit/builder.py | 1 - cutekit/cli.py | 44 +++++++++++++++++++++++++++++++++----------- cutekit/model.py | 6 ++++-- cutekit/plugins.py | 2 +- cutekit/pods.py | 3 +++ cutekit/shell.py | 13 +++++++++++-- 6 files changed, 52 insertions(+), 17 deletions(-) diff --git a/cutekit/builder.py b/cutekit/builder.py index 1ef1d46..abc7184 100644 --- a/cutekit/builder.py +++ b/cutekit/builder.py @@ -3,7 +3,6 @@ import logging import dataclasses as dt from pathlib import Path -import sys from typing import Callable, Literal, TextIO, Union from . import cli, shell, rules, model, ninja, const, vt100 diff --git a/cutekit/cli.py b/cutekit/cli.py index 1054421..1baf84b 100644 --- a/cutekit/cli.py +++ b/cutekit/cli.py @@ -1,8 +1,8 @@ -import sys from enum import Enum from types import GenericAlias import typing as tp import dataclasses as dt +import logging from typing import Any, Callable, Optional, Union from cutekit import vt100, const @@ -10,6 +10,8 @@ from cutekit import vt100, const T = tp.TypeVar("T") +_logger = logging.getLogger(__name__) + # --- Scan -------------------------------------------------------------- # @@ -542,6 +544,7 @@ class Command: callable: Optional[tp.Callable] = None subcommands: dict[str, "Command"] = dt.field(default_factory=dict) populated: bool = False + path: list[str] = dt.field(default_factory=list) def _spliceArgs(self, args: list[str]) -> tuple[list[str], list[str]]: rest = args[:] @@ -554,12 +557,12 @@ class Command: rest = [] return curr, rest - def help(self, cmd): - vt100.title(f"{cmd}") + def help(self): + vt100.title(f"{self.longName}") print() vt100.subtitle("Usage") - print(vt100.indent(f"{cmd}{self.usage()}")) + print(vt100.indent(f"{' '.join(self.path)}{self.usage()}")) print() vt100.subtitle("Description") @@ -631,23 +634,38 @@ class Command: return sub raise ValueError(f"Unknown subcommand '{name}'") + def invoke(self, argv: list[str]): + if self.callable: + if self.schema: + args = self.schema.parse(argv) + self.callable(args) + else: + self.callable() + def eval(self, args: list[str]): cmd = args.pop(0) curr, rest = self._spliceArgs(args) + if "-h" in curr or "--help" in curr: - self.help(cmd) + if len(self.path) == 0: + # HACK: This is a special case for the root command + # it need to always be run because it might + # load some plugins that will register subcommands + # that need to be displayed in the help. + self.invoke([]) + self.help() return + if "-u" in curr or "--usage" in curr: + if len(self.path) == 0: + # HACK: Same as the help flag, the root command needs to be + # always run to load plugins + self.invoke([]) print("Usage: " + cmd + self.usage(), end="\n\n") return try: - if self.callable: - if self.schema: - args = self.schema.parse(curr) - self.callable(args) - else: - self.callable() + self.invoke(curr) if self.subcommands: if len(rest) > 0: @@ -692,14 +710,18 @@ def command(shortName: Optional[str], longName: str, description: str = "") -> C schema = Schema.extractFromCallable(fn) path = _splitPath(longName) cmd = _resolvePath(path) + + _logger.info(f"Registering command '{'.'.join(path)}'") if cmd.populated: raise ValueError(f"Command '{longName}' is already defined") + cmd.shortName = shortName cmd.longName = len(path) > 0 and path[-1] or "" cmd.description = description cmd.schema = schema cmd.callable = fn cmd.populated = True + cmd.path = [const.ARGV0] + path return fn return wrap diff --git a/cutekit/model.py b/cutekit/model.py index b6dbbb4..56dcca5 100644 --- a/cutekit/model.py +++ b/cutekit/model.py @@ -565,6 +565,8 @@ class Registry(DataClassJsonMixin): @staticmethod def load(project: Project, mixins: list[str], props: Props) -> "Registry": + _logger.info(f"Loading model for project '{project.id}'") + r = Registry(project) r._append(project) @@ -752,8 +754,8 @@ def view( class GraphArgs(TargetArgs): - onlyLibs: bool = cli.arg(False, "only-libs", "Show only libraries") - showDisabled: bool = cli.arg(False, "show-disabled", "Show disabled components") + onlyLibs: bool = cli.arg(None, "only-libs", "Show only libraries") + showDisabled: bool = cli.arg(None, "show-disabled", "Show disabled components") scope: str = cli.arg( None, "scope", "Show only the specified component and its dependencies" ) diff --git a/cutekit/plugins.py b/cutekit/plugins.py index ad3516b..b3d2bc1 100644 --- a/cutekit/plugins.py +++ b/cutekit/plugins.py @@ -52,7 +52,7 @@ def loadAll(): class PluginsArgs: - safemod: bool = cli.arg(None, "safemode", "disable plugin loading") + safemod: bool = cli.arg(None, "safemode", "Disable plugin loading") def setup(args: PluginsArgs): diff --git a/cutekit/pods.py b/cutekit/pods.py index 30a9935..03be55c 100644 --- a/cutekit/pods.py +++ b/cutekit/pods.py @@ -1,4 +1,5 @@ import sys +import logging from typing import Optional import docker # type: ignore import os @@ -6,6 +7,7 @@ import dataclasses as dt from . import cli, model, shell, vt100, const +_logger = logging.getLogger(__name__) podPrefix = "CK__" projectRoot = "/project" @@ -111,6 +113,7 @@ def setup(args: PodSetupArgs): """ if not args.pod: return + _logger.info(f"Reincarnating into pod '{args.pod}'...") if isinstance(args.pod, str): pod = args.pod.strip() pod = podPrefix + pod diff --git a/cutekit/shell.py b/cutekit/shell.py index db6bf9b..04c1c88 100644 --- a/cutekit/shell.py +++ b/cutekit/shell.py @@ -38,7 +38,12 @@ def uname() -> Uname: distrib = {"NAME": "Unknown"} result = Uname( - un.system, distrib["NAME"], un.node, un.release, un.version, un.machine + un.system, + distrib["NAME"], + un.node, + un.release, + un.version, + un.machine, ) match result.machine: @@ -49,6 +54,8 @@ def uname() -> Uname: case _: pass + _logger.debug(f"uname: {result}") + return result @@ -128,6 +135,7 @@ def wget(url: str, path: Optional[str] = None) -> str: ) if os.path.exists(path): + _logger.debug(f"Using cached {path} for {url}") return path _logger.debug(f"Downloading {url} to {path}") @@ -292,6 +300,8 @@ def cpTree(src: str, dst: str): def cloneDir(url: str, path: str, dest: str) -> str: + _logger.debug(f"Cloning {url} to {dest}") + with tempfile.TemporaryDirectory() as tmp: mkdir(tmp) exec( @@ -378,7 +388,6 @@ def gzip(path: str, dest: Optional[str] = None) -> str: """ Compress a file or directory """ - if dest is None: dest = path + ".gz"