From db6220b57b40cf494fe9680a755735dac1eb3075 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Sun, 6 Jul 2025 14:37:03 +0200 Subject: [PATCH] Templates/list: display templates via exposed nix value --- lib/modules/clan/module.nix | 4 +- .../service-list-from-inputs.nix | 21 +++++++--- pkgs/clan-cli/clan_cli/clan/list.py | 39 ++++++++++++++----- .../clan_cli/tests/test_clan_nix_attrset.py | 5 --- pkgs/clan-cli/clan_lib/api/modules.py | 1 - pkgs/clan-cli/clan_lib/templates/__init__.py | 31 +++++---------- 6 files changed, 56 insertions(+), 45 deletions(-) diff --git a/lib/modules/clan/module.nix b/lib/modules/clan/module.nix index 917468e0f..7b0986649 100644 --- a/lib/modules/clan/module.nix +++ b/lib/modules/clan/module.nix @@ -229,8 +229,6 @@ in clanInternals = { inventoryClass = let - localModuleSet = - lib.filterAttrs (n: _: !inventory._legacyModules ? ${n}) inventory.modules // config.modules; flakeInputs = config.self.inputs; in { @@ -240,7 +238,7 @@ in imports = [ ../inventoryClass/builder/default.nix (lib.modules.importApply ../inventoryClass/service-list-from-inputs.nix { - inherit flakeInputs clanLib localModuleSet; + inherit flakeInputs clanLib; }) { inherit inventory directory; diff --git a/lib/modules/inventoryClass/service-list-from-inputs.nix b/lib/modules/inventoryClass/service-list-from-inputs.nix index a73d9c87a..7e913bed1 100644 --- a/lib/modules/inventoryClass/service-list-from-inputs.nix +++ b/lib/modules/inventoryClass/service-list-from-inputs.nix @@ -1,12 +1,9 @@ { flakeInputs, clanLib, - localModuleSet, }: { lib, config, ... }: - let - inspectModule = inputName: moduleName: module: let @@ -28,16 +25,30 @@ in { options.modulesPerSource = lib.mkOption { # { sourceName :: { moduleName :: {} }} + readOnly = true; + type = lib.types.raw; default = let inputsWithModules = lib.filterAttrs (_inputName: v: v ? clan.modules) flakeInputs; - in lib.mapAttrs ( inputName: v: lib.mapAttrs (inspectModule inputName) v.clan.modules ) inputsWithModules; }; options.localModules = lib.mkOption { - default = lib.mapAttrs (inspectModule "self") localModuleSet; + readOnly = true; + type = lib.types.raw; + default = config.modulesPerSource.self; + }; + options.templatesPerSource = lib.mkOption { + # { sourceName :: { moduleName :: {} }} + readOnly = true; + type = lib.types.raw; + default = + let + inputsWithTemplates = lib.filterAttrs (_inputName: v: v ? clan.templates) flakeInputs; + in + lib.mapAttrs (_inputName: v: lib.mapAttrs (_n: t: t) v.clan.templates) inputsWithTemplates; + }; } diff --git a/pkgs/clan-cli/clan_cli/clan/list.py b/pkgs/clan-cli/clan_cli/clan/list.py index ff80c20f1..58ae350d0 100644 --- a/pkgs/clan-cli/clan_cli/clan/list.py +++ b/pkgs/clan-cli/clan_cli/clan/list.py @@ -7,17 +7,38 @@ log = logging.getLogger(__name__) def list_command(args: argparse.Namespace) -> None: - template_list = list_templates("clan", args.flake) + templates = list_templates(args.flake) - print("Available local templates:") - for name, template in template_list.self.items(): - print(f" {name}: {template['description']}") + builtin_clan_templates = templates.builtins.get("clan", {}) - print("Available templates from inputs:") - for input_name, input_templates in template_list.inputs.items(): - print(f" {input_name}:") - for name, template in input_templates.items(): - print(f" {name}: {template['description']}") + print("Available templates") + print("├── ") + for i, (name, template) in enumerate(builtin_clan_templates.items()): + is_last_template = i == len(builtin_clan_templates.items()) - 1 + if not is_last_template: + print(f"│ ├── {name}: {template.get('description', 'no description')}") + else: + print(f"│ └── {name}: {template.get('description', 'no description')}") + + for i, (input_name, input_templates) in enumerate(templates.custom.items()): + custom_clan_templates = input_templates.get("clan", {}) + is_last_input = i == len(templates.custom.items()) - 1 + prefix = "│" if not is_last_input else " " + if not is_last_input: + print(f"├── inputs.{input_name}:") + else: + print(f"└── inputs.{input_name}:") + + for i, (name, template) in enumerate(custom_clan_templates.items()): + is_last_template = i == len(builtin_clan_templates.items()) - 1 + if not is_last_template: + print( + f"{prefix} ├── {name}: {template.get('description', 'no description')}" + ) + else: + print( + f"{prefix} └── {name}: {template.get('description', 'no description')}" + ) def register_list_parser(parser: argparse.ArgumentParser) -> None: diff --git a/pkgs/clan-cli/clan_cli/tests/test_clan_nix_attrset.py b/pkgs/clan-cli/clan_cli/tests/test_clan_nix_attrset.py index 8cda0d002..0e7de5f9f 100644 --- a/pkgs/clan-cli/clan_cli/tests/test_clan_nix_attrset.py +++ b/pkgs/clan-cli/clan_cli/tests/test_clan_nix_attrset.py @@ -17,7 +17,6 @@ from clan_lib.templates import ( TemplateName, get_clan_nix_attrset, get_template, - list_templates, ) from clan_lib.templates.filesystem import copy_from_nixstore @@ -96,10 +95,6 @@ def test_clan_core_templates( expected_templates = ["default", "flake-parts", "minimal", "minimal-flake-parts"] assert clan_core_template_keys == expected_templates - vlist_temps = list_templates("clan", clan_dir) - list_template_keys = list(vlist_temps.inputs[InputName("clan-core")].keys()) - assert list_template_keys == expected_templates - default_template = get_template( TemplateName("default"), "clan", diff --git a/pkgs/clan-cli/clan_lib/api/modules.py b/pkgs/clan-cli/clan_lib/api/modules.py index d6d624610..7e306a2c0 100644 --- a/pkgs/clan-cli/clan_lib/api/modules.py +++ b/pkgs/clan-cli/clan_lib/api/modules.py @@ -168,7 +168,6 @@ def list_modules(base_path: str) -> ModuleLists: modules = flake.select( "clanInternals.inventoryClass.{?modulesPerSource,?localModules}" ) - print("Modules found:", modules) return modules diff --git a/pkgs/clan-cli/clan_lib/templates/__init__.py b/pkgs/clan-cli/clan_lib/templates/__init__.py index 4b30131e5..ae2c556ae 100644 --- a/pkgs/clan-cli/clan_lib/templates/__init__.py +++ b/pkgs/clan-cli/clan_lib/templates/__init__.py @@ -1,10 +1,11 @@ import logging -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, Literal, NewType, TypedDict, cast from clan_lib.dirs import clan_templates from clan_lib.errors import ClanCmdError, ClanError from clan_lib.flake import Flake +from clan_lib.nix_models.clan import ClanTemplatesType from clan_lib.templates.filesystem import realize_nix_path log = logging.getLogger(__name__) @@ -168,32 +169,18 @@ class InputPrio: @dataclass class TemplateList: - inputs: dict[InputName, dict[TemplateName, Template]] = field(default_factory=dict) - self: dict[TemplateName, Template] = field(default_factory=dict) + builtins: ClanTemplatesType + custom: dict[str, ClanTemplatesType] -def list_templates( - template_type: TemplateType, clan_dir: Flake | None = None -) -> TemplateList: +def list_templates(flake: Flake) -> TemplateList: """ - List all templates of a specific type from a flake, without a path attribute. - As these paths are not yet downloaded into the nix store, and thus cannot be used directly. + Show information about a module """ - clan_exports = get_clan_nix_attrset(clan_dir) - result = TemplateList() + custom_templates = flake.select("clanInternals.inventoryClass.templatesPerSource") + builtin_templates = flake.select("clanInternals.templates") - for template_name, template in clan_exports["self"]["templates"][ - template_type - ].items(): - result.self[template_name] = template - - for input_name, attrset in clan_exports["inputs"].items(): - for template_name, template in attrset["templates"][template_type].items(): - if input_name not in result.inputs: - result.inputs[input_name] = {} - result.inputs[input_name][template_name] = template - - return result + return TemplateList(builtin_templates, custom_templates) def get_template(