diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5b71ba8a..29bbb9fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,11 +13,12 @@ jobs: - uses: CERT-Polska/lint-python-action@v2 with: source: karton/ + python-version: 3.12 unittest: runs-on: ubuntu-latest strategy: matrix: - minor: [9, 10, 11, 12] + minor: [10, 11, 12, 13] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 diff --git a/README.md b/README.md index 7a496ee9..608ef676 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,26 @@ if __name__ == "__main__": GenericUnpacker.main() ``` +## Command line + +This package also provies a command-line utility called "karton". You can use it for simple management tasks (but it's not designed as a fully capable management tool). + +``` +$ karton configure # create a new configuration file + +$ karton list -s # list current binds +karton name version karton +------------------------------------------------------------------------ +karton.yaramatcher 1.2.0 5.3.0 +karton.autoit-ripper 1.2.1 5.3.3 +karton.mwdb-reporter 1.3.0 5.3.2 + +$ karton logs # start streaming all system logs + +$ karton delete karton.something # remove unused bind (will be GCed by system during the next operation) +``` + + ## Karton systems Some Karton systems are universal and useful to everyone. We decided to share them with the community. diff --git a/karton/core/main.py b/karton/core/main.py index bfa69519..cbf68a14 100644 --- a/karton/core/main.py +++ b/karton/core/main.py @@ -144,10 +144,23 @@ def configuration_wizard(config_filename: str) -> None: log.info("Saved the new configuration file in %s", os.path.abspath(config_filename)) -def print_bind_list(config: Config) -> None: +def print_bind_list(config: Config, output_format: str) -> None: backend = KartonBackend(config=config) - for bind in backend.get_binds(): - print(bind) + + if output_format == "table": + # Print a human-readable table-like version + print(f"{'karton name':50} {'version':10} {'karton':10}") + print("-" * 72) + for bind in backend.get_binds(): + print( + f"{bind.identity:50} {bind.service_version or "-":10} {bind.version:10}" + ) + elif output_format == "json": + # Use JSONL, each line is a JSON representing next bind + for bind in backend.get_binds(): + print(backend.serialize_bind(bind)) + else: + raise RuntimeError(f"Invalid output format: {output_format}") def delete_bind(config: Config, karton_name: str) -> None: @@ -180,7 +193,7 @@ def process(self, task): def main() -> None: - parser = argparse.ArgumentParser(description="Your red pill to the karton-verse") + parser = argparse.ArgumentParser(description="Karton-core management utility") parser.add_argument("--version", action="version", version=__version__) parser.add_argument("-c", "--config-file", help="Alternative configuration path") parser.add_argument( @@ -189,7 +202,14 @@ def main() -> None: subparsers = parser.add_subparsers(dest="command", help="sub-command help") - subparsers.add_parser("list", help="List active karton binds") + list_parser = subparsers.add_parser("list", help="List active karton binds") + list_parser.add_argument( + "-o", + "--output", + help="Short, human readable output, with names and versions only.", + default="table", + choices=("table", "json"), + ) logs_parser = subparsers.add_parser("logs", help="Start streaming logs") logs_parser.add_argument( @@ -253,7 +273,7 @@ def main() -> None: return if args.command == "list": - print_bind_list(config) + print_bind_list(config, args.output) elif args.command == "delete": karton_name = args.identity print(