Files
Medios-Macina/cmdnat/config.py

152 lines
4.5 KiB
Python
Raw Normal View History

2025-11-25 20:09:33 -08:00
from typing import List, Dict, Any
2025-12-11 23:21:45 -08:00
2025-12-12 21:55:38 -08:00
from cmdlet._shared import Cmdlet, CmdletArg
from SYS.config import load_config, save_config
2025-11-25 20:09:33 -08:00
CMDLET = Cmdlet(
name=".config",
summary="Manage configuration settings",
usage=".config [key] [value]",
2025-12-11 12:47:30 -08:00
arg=[
2025-11-25 20:09:33 -08:00
CmdletArg(
name="key",
description="Configuration key to update (dot-separated)",
required=False
),
CmdletArg(
name="value",
description="New value for the configuration key",
required=False
2025-11-25 20:09:33 -08:00
),
2025-12-29 17:05:03 -08:00
],
2025-11-25 20:09:33 -08:00
)
2025-12-29 17:05:03 -08:00
def flatten_config(config: Dict[str,
Any],
parent_key: str = "",
sep: str = ".") -> List[Dict[str,
Any]]:
2025-11-25 20:09:33 -08:00
items = []
for k, v in config.items():
2025-12-29 17:05:03 -08:00
if k.startswith("_"): # Skip internal keys
2025-11-25 20:09:33 -08:00
continue
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
new_key = f"{parent_key}{sep}{k}" if parent_key else k
if isinstance(v, dict):
items.extend(flatten_config(v, new_key, sep=sep))
else:
2025-12-29 17:05:03 -08:00
items.append(
{
"Key": new_key,
"Value": str(v),
"Type": type(v).__name__,
"_selection_args": [new_key],
}
)
2025-11-25 20:09:33 -08:00
return items
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
def set_nested_config(config: Dict[str, Any], key: str, value: str) -> bool:
2025-12-29 17:05:03 -08:00
keys = key.split(".")
2025-11-25 20:09:33 -08:00
d = config
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
# Navigate to the parent dict
for k in keys[:-1]:
if k not in d or not isinstance(d[k], dict):
d[k] = {}
d = d[k]
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
last_key = keys[-1]
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
# Try to preserve type if key exists
if last_key in d:
current_val = d[last_key]
if isinstance(current_val, bool):
2025-12-29 17:05:03 -08:00
if value.lower() in ("true", "yes", "1", "on"):
2025-11-25 20:09:33 -08:00
d[last_key] = True
2025-12-29 17:05:03 -08:00
elif value.lower() in ("false", "no", "0", "off"):
2025-11-25 20:09:33 -08:00
d[last_key] = False
else:
# Fallback to boolean conversion of string (usually True for non-empty)
# But for config, explicit is better.
print(f"Warning: Could not convert '{value}' to boolean. Using string.")
d[last_key] = value
elif isinstance(current_val, int):
try:
d[last_key] = int(value)
except ValueError:
print(f"Warning: Could not convert '{value}' to int. Using string.")
d[last_key] = value
elif isinstance(current_val, float):
try:
d[last_key] = float(value)
except ValueError:
print(f"Warning: Could not convert '{value}' to float. Using string.")
d[last_key] = value
else:
d[last_key] = value
else:
# New key, try to infer type
2025-12-29 17:05:03 -08:00
if value.lower() in ("true", "false"):
d[last_key] = value.lower() == "true"
2025-11-25 20:09:33 -08:00
elif value.isdigit():
d[last_key] = int(value)
else:
d[last_key] = value
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
return True
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
def _run(piped_result: Any, args: List[str], config: Dict[str, Any]) -> int:
# Reload config to ensure we have the latest on disk
# We don't use the passed 'config' because we want to edit the file
# and 'config' might contain runtime objects (like worker manager)
# But load_config() returns a fresh dict from disk (or cache)
# We should use load_config()
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
current_config = load_config()
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
# Parse args
# We handle args manually because of the potential for spaces in values
# and the @ expansion logic in CLI.py passing args
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
if not args:
# List mode
items = flatten_config(current_config)
# Sort by key
2025-12-29 17:05:03 -08:00
items.sort(key=lambda x: x["Key"])
2025-11-25 20:09:33 -08:00
# Emit items for ResultTable
import pipeline as ctx
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
for item in items:
ctx.emit(item)
return 0
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
# Update mode
key = args[0]
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
if len(args) < 2:
print(f"Error: Value required for key '{key}'")
return 1
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
value = " ".join(args[1:])
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
# Remove quotes if present
if (value.startswith('"') and value.endswith('"')) or (value.startswith("'")
and value.endswith("'")):
2025-11-25 20:09:33 -08:00
value = value[1:-1]
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
try:
set_nested_config(current_config, key, value)
save_config(current_config)
print(f"Updated '{key}' to '{value}'")
return 0
except Exception as e:
print(f"Error updating config: {e}")
return 1
2025-12-29 17:05:03 -08:00
2025-11-25 20:09:33 -08:00
CMDLET.exec = _run