"""Command-line mode, for machines without a desktop (e.g. a Fedora Server box): SaraSuite list SaraSuite install [--set Id=Value ...] [--option Id=on|off ...] SaraSuite update SaraSuite options [--option Id=on|off ...] (no --option: list them) SaraSuite remove [--configs] [--keep-runtime] SaraSuite self-update (AppImage only) Install starts from your defaults (Settings, or the manifest's) unless set. """ import argparse import SelfUpdate from Catalog import UpdateCatalog from Core import AppVersion 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") Commands.add_parser("self-update") Args = Parser.parse_args(Arguments) if Args.Command == "self-update": Latest = SelfUpdate.LatestRelease() if Latest is None or not SelfUpdate.IsNewer(Latest.Version): print(f"SaraSuite {AppVersion} is the latest.") return 0 SelfUpdate.Install(Latest, print) return 0 UpdateCatalog(print) # the program list from the SaraSuite repo (AppImage only) 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