clan-cli: clan_cli.inventory -> clan_lib.inventory

This commit is contained in:
lassulus
2025-05-21 11:24:46 +02:00
parent 56a00e0afd
commit 2de3dcef15
6 changed files with 6 additions and 6 deletions

View File

@@ -0,0 +1,226 @@
"""
DEPRECATED:
Don't use this module anymore
Instead use:
'clan_lib.persist.inventoryStore'
Which is an abstraction over the inventory
Interacting with 'clan_lib.inventory' is NOT recommended and will be removed
"""
import json
from pathlib import Path
from typing import Any
from clan_lib.api import API
from clan_lib.errors import ClanError
from clan_lib.flake import Flake
from clan_lib.git import commit_file
from clan_lib.nix_models.inventory import Inventory
from clan_lib.persist.inventory_store import WriteInfo
from clan_lib.persist.util import (
apply_patch,
calc_patches,
delete_by_path,
determine_writeability,
)
def get_inventory_path(flake: Flake) -> Path:
"""
Get the path to the inventory file in the flake directory
"""
inventory_file = (flake.path / "inventory.json").resolve()
return inventory_file
def load_inventory_eval(flake: Flake) -> Inventory:
"""
Loads the evaluated inventory.
After all merge operations with eventual nix code in buildClan.
Evaluates clanInternals.inventory with nix. Which is performant.
- Contains all clan metadata
- Contains all machines
- and more
"""
data = flake.select("clanInternals.inventory")
try:
inventory = Inventory(data) # type: ignore
except json.JSONDecodeError as e:
msg = f"Error decoding inventory from flake: {e}"
raise ClanError(msg) from e
else:
return inventory
def get_inventory_current_priority(flake: Flake) -> dict:
"""
Returns the current priority of the inventory values
machines = {
__prio = 100;
flash-installer = {
__prio = 100;
deploy = {
targetHost = { __prio = 1500; };
};
description = { __prio = 1500; };
icon = { __prio = 1500; };
name = { __prio = 1500; };
tags = { __prio = 1500; };
};
}
"""
try:
data = flake.select("clanInternals.inventoryClass.introspection")
except json.JSONDecodeError as e:
msg = f"Error decoding inventory from flake: {e}"
raise ClanError(msg) from e
else:
return data
@API.register
def load_inventory_json(flake: Flake) -> Inventory:
"""
Load the inventory FILE from the flake directory
If no file is found, returns an empty dictionary
DO NOT USE THIS FUNCTION TO READ THE INVENTORY
Use load_inventory_eval instead
"""
inventory_file = get_inventory_path(flake)
if not inventory_file.exists():
return {}
with inventory_file.open() as f:
try:
res: dict = json.load(f)
inventory = Inventory(res) # type: ignore
except json.JSONDecodeError as e:
# Error decoding the inventory file
msg = f"Error decoding inventory file: {e}"
raise ClanError(msg) from e
return inventory
@API.register
def patch_inventory_with(flake: Flake, section: str, content: dict[str, Any]) -> None:
"""
Pass only the section to update and the content to update with.
Make sure you pass only attributes that you would like to persist.
ATTENTION: Don't pass nix eval values unintentionally.
"""
inventory_file = get_inventory_path(flake)
curr_inventory = {}
if inventory_file.exists():
with inventory_file.open("r") as f:
curr_inventory = json.load(f)
apply_patch(curr_inventory, section, content)
with inventory_file.open("w") as f:
json.dump(curr_inventory, f, indent=2)
commit_file(
inventory_file, flake.path, commit_message=f"inventory.{section}: Update"
)
@API.register
def get_inventory_with_writeable_keys(
flake: Flake,
) -> WriteInfo:
"""
Load the inventory and determine the writeable keys
Performs 2 nix evaluations to get the current priority and the inventory
"""
current_priority = get_inventory_current_priority(flake)
data_eval: Inventory = load_inventory_eval(flake)
data_disk: Inventory = load_inventory_json(flake)
writeables = determine_writeability(
current_priority, dict(data_eval), dict(data_disk)
)
return WriteInfo(writeables, data_eval, data_disk)
# TODO: remove this function in favor of a proper read/write API
@API.register
def set_inventory(
inventory: Inventory, flake: Flake, message: str, commit: bool = True
) -> None:
"""
Write the inventory to the flake directory
and commit it to git with the given message
"""
write_info = get_inventory_with_writeable_keys(flake)
# Remove internals from the inventory
inventory.pop("tags", None) # type: ignore
inventory.pop("options", None) # type: ignore
inventory.pop("assertions", None) # type: ignore
patchset, delete_set = calc_patches(
dict(write_info.data_disk),
dict(inventory),
dict(write_info.data_eval),
write_info.writeables,
)
persisted = dict(write_info.data_disk)
for patch_path, data in patchset.items():
apply_patch(persisted, patch_path, data)
for delete_path in delete_set:
delete_by_path(persisted, delete_path)
inventory_file = get_inventory_path(flake)
with inventory_file.open("w") as f:
json.dump(persisted, f, indent=2)
if commit:
commit_file(inventory_file, flake.path, commit_message=message)
# TODO: wrap this in a proper persistence API
def delete(flake: Flake, delete_set: set[str]) -> None:
"""
Delete keys from the inventory
"""
write_info = get_inventory_with_writeable_keys(flake)
data_disk = dict(write_info.data_disk)
for delete_path in delete_set:
delete_by_path(data_disk, delete_path)
inventory_file = get_inventory_path(flake)
with inventory_file.open("w") as f:
json.dump(data_disk, f, indent=2)
commit_file(
inventory_file,
flake.path,
commit_message=f"Delete inventory keys {delete_set}",
)
@API.register
def get_inventory(flake: Flake) -> Inventory:
return load_inventory_eval(flake)

View File

@@ -1,5 +1,5 @@
# DO NOT EDIT THIS FILE MANUALLY. IT IS GENERATED.
# This file was generated by running `pkgs/clan-cli/clan_cli/inventory/update.sh`
# This file was generated by running `pkgs/clan-cli/clan_lib.inventory/update.sh`
#
# ruff: noqa: N815
# ruff: noqa: N806

View File

@@ -8,7 +8,6 @@ from typing import Any
import clan_cli.clan.create
import pytest
from clan_cli.inventory import patch_inventory_with
from clan_cli.machines.create import CreateOptions as ClanCreateOptions
from clan_cli.machines.create import create_machine
from clan_cli.machines.machines import Machine
@@ -25,6 +24,7 @@ from clan_lib.cmd import RunOpts, run
from clan_lib.dirs import specific_machine_dir
from clan_lib.errors import ClanError
from clan_lib.flake import Flake
from clan_lib.inventory import patch_inventory_with
from clan_lib.nix import nix_command
from clan_lib.nix_models.inventory import Machine as InventoryMachine
from clan_lib.nix_models.inventory import MachineDeploy