Files
SaraSuite/Cli.py
T
sarahandClaude Opus 5.5 6e4c571e38 Add SaraSort, listed under SaraSortd
Manifests can name a Parent program; it's listed (indented) right under it,
in the window and in `list`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 22:57:49 +02:00

95 lines
3.8 KiB
Python

"""Command-line mode, for machines without a desktop (e.g. a Fedora Server box):
SaraSuite list
SaraSuite install <Name> [--set Id=Value ...] [--option Id=on|off ...]
SaraSuite update <Name>
SaraSuite options <Name> [--option Id=on|off ...] (no --option: list them)
SaraSuite remove <Name> [--configs] [--keep-runtime]
Install starts from your defaults (Settings, or the manifest's) unless set.
"""
import argparse
from Installer import Apply, DefaultAnswers, DefaultOptions, FetchCommit, GetStatus, Remove
from Manifests import LoadPrograms
def _Pairs(Items: list[str]) -> dict[str, str]:
Pairs = {}
for Item in Items:
Key, Separator, Value = Item.partition("=")
if not Separator:
raise SystemExit(f"Expected Id=Value, got {Item!r}")
Pairs[Key] = Value
return Pairs
def _Switches(Items: list[str]) -> dict[str, bool]:
return {Key: Value.lower() in ("on", "yes", "true", "1") for Key, Value in _Pairs(Items).items()}
def Run(Arguments: list[str]) -> int:
Parser = argparse.ArgumentParser(prog="SaraSuite")
Commands = Parser.add_subparsers(dest="Command", required=True)
Commands.add_parser("list")
Install = Commands.add_parser("install")
Install.add_argument("Name")
Install.add_argument("--set", action="append", default=[], dest="Answers")
Install.add_argument("--option", action="append", default=[], dest="Options")
Commands.add_parser("update").add_argument("Name")
OptionsCommand = Commands.add_parser("options")
OptionsCommand.add_argument("Name")
OptionsCommand.add_argument("--option", action="append", default=[], dest="Options")
RemoveCommand = Commands.add_parser("remove")
RemoveCommand.add_argument("Name")
RemoveCommand.add_argument("--configs", action="store_true")
RemoveCommand.add_argument("--keep-runtime", action="store_true")
Args = Parser.parse_args(Arguments)
Programs = {Program.Name.lower(): Program for Program in LoadPrograms()}
if Args.Command == "list":
for Program in Programs.values():
Current = GetStatus(Program)
State = "update available" if Current.UpdateAvailable else "installed" if Current.Installed else "not installed"
Name = f" {Program.Name}" if Program.Parent else Program.Name
print(f"{Name:12} {State:16} {Current.Error}")
return 0
Program = Programs.get(Args.Name.lower())
if Program is None:
print(f"Unknown program {Args.Name!r}. Known: {', '.join(P.Name for P in Programs.values())}")
return 1
Current = GetStatus(Program)
Installed = Current.Installed
if Args.Command == "install":
if Installed:
print(f"{Program.Name} is already installed; use update.")
return 1
Options = DefaultOptions(Program)
Options.update(_Switches(Args.Options))
Answers = DefaultAnswers(Program)
Answers.update(_Pairs(Args.Answers))
Apply(Program, print, Options, Answers)
elif Args.Command == "update":
if not Installed:
print(f"{Program.Name} isn't installed.")
return 1
Apply(Program, print)
elif Args.Command == "options":
if not Installed:
print(f"{Program.Name} isn't installed.")
return 1
if not Args.Options:
for Option in Program.Options:
State = "on" if Current.Receipt.Options.get(Option.Id) else "off"
print(f"{Option.Id:20} {State:4} {Option.Label}")
return 0
Options = dict(Current.Receipt.Options)
Options.update(_Switches(Args.Options))
Apply(Program, print, Options, Source=FetchCommit(Program, Current.Receipt.Commit, print))
elif Args.Command == "remove":
Remove(Program, Args.configs, not Args.keep_runtime, print)
return 0