# SaraSuite Installs, updates and removes Sara programs (SaraSortd, SaraFem, and eventually the SaraView client). It's one AppImage file: download it, run it, pick a program. - **Install**: downloads the program's latest commit from its git repo, copies it into `~/.local/share/SaraSuite/Programs//` with its own Python venv, places its configs in `~/.config/SaraSuite//`, and writes its desktop entries, systemd user units, D-Bus services and so on. - **Update**: shown when the repo has a newer commit. Program files and integration files are replaced; configs are *merged*: your edits always win, defaults you never touched follow the new version, new keys are added (see `ConfigMerge.py`). - **Remove**: takes out everything the install placed (it's all recorded in a receipt) plus everything the program made by itself while running. Configs are only removed when "Remove configs" is ticked. Your own files are never removed: folders that might hold them are only removed when empty. Files that existed before SaraSuite installed over them are put back. ## Sources Programs come straight from git over HTTPS, no `git` binary needed: the latest commit is read from `.git/info/refs` and the files from `/archive/.tar.gz`, which GitHub and Gitea both serve the same way. Repos must be public (no login support yet). The host is one setting in `~/.config/SaraSuite/SaraSuite/Config.toml`; manifests refer to it as `{GitHost}`. It defaults to the Gitea on SpineS (only reachable over Tailscale): ```toml GitHost = "http://git.srhtnin.garden/sarah" ``` The only thing a program needs from the system is `python3` (for its venv). ## Running and building - AppImage: `Packaging/BuildAppImage.sh` builds `dist/SaraSuite-x86_64.AppImage` (PyInstaller one-file build + `appimagetool`, like SaraFem's). When run as an AppImage, the header has an "Add to app menu" button. - From source: `python3 -m venv .venv && .venv/bin/pip install -r requirements.txt`, then `Packaging/Launch.sh`. - Without a desktop (e.g. a server), the same file works from a terminal: ``` SaraSuite-x86_64.AppImage list SaraSuite-x86_64.AppImage install SaraSortd --set RootDir=~/Sorting --option Autostart=on SaraSuite-x86_64.AppImage update SaraSortd SaraSuite-x86_64.AppImage remove SaraSortd [--configs] [--keep-runtime] ``` ## Where things live | Path | What | | --- | --- | | `~/.local/share/SaraSuite/Programs//` | installed program (`App/`) and its `.venv/` | | `~/.local/share/SaraSuite/Receipts/.toml` | everything the install placed | | `~/.local/share/SaraSuite/Pristine//` | the default configs as last installed (the merge base) | | `~/.local/share/SaraSuite/Backups//` | files that were moved aside, and configs from before a merge | | `~/.cache/SaraSuite/Downloads/` | downloaded source, removed after installing | | `~/.config/SaraSuite//` | the program's configs | ## Adding a program Make `Programs//Manifest.toml`. Templates go in `Programs//Templates/`. Manifests are bundled into the AppImage, so a new or changed manifest means rebuilding it (installed programs then show an update, even without a new commit). Anything the manifest can't describe goes in an optional `Programs//Hooks.py`. Targets, templates and `Set` values can use `{Variables}`: `Name`, `GitHost`, `Home`, `ConfigHome`, `DataHome`, `CacheHome`, `SystemdUserDir`, `ApplicationsDir`, `DBusServicesDir`, `ProgramDir`, `AppDir`, `Python` (the venv's python), `ConfigDir`, `DesktopName` (e.g. `COSMIC`), `Desktop` (e.g. `cosmic`), plus every Question's `Id`. ```toml Name = "Example" Description = "Shown on the program's card." RestartUnits = ["xdg-desktop-portal.service"] # try-restarted after install/update/remove [Version] # optional, shown on the card File = "Example.py" Pattern = 'Version = "([^"]+)"' [Source] Git = "{GitHost}/Example" Branch = "main" # optional, default: the repo's default branch Include = ["*.py", "assets/**"] # default: everything Exclude = ["Packaging"] # .git, .venv, build, ... are always excluded [Python] RequirementsFile = "requirements.txt" # or: Requirements = ["toml"] [[Questions]] # asked at install time, usable as {RootDir} Id = "RootDir" Prompt = "Folder to use" Default = "~/Somewhere" Kind = "Path" # expanded to an absolute path [[Options]] # checkboxes at install time Id = "Autostart" Label = "Start on login" Default = true [[Configs]] # placed once, merged on updates Source = "Conf.toml" # in the source checkout Target = "{ConfigDir}/Conf.toml" Set = { "Paths.RootDir" = "{RootDir}" } [[Templates]] # owned by SaraSuite, rewritten on every update Source = "Example.service" # in Templates/ Target = "{SystemdUserDir}/Example.service" Option = "Autostart" # optional: only while the option is ticked Root = false # true: outside $HOME, written through pkexec Executable = false [[Services]] # systemd --user units, enabled + started Unit = "Example.service" Option = "Autostart" [[IniEdits]] # one key in a file SaraSuite doesn't own; restored on removal File = "{ConfigHome}/mimeapps.list" Section = "Default Applications" Key = "inode/directory" Value = "Example.desktop" [[Leftovers]] # made by the program itself, only touched on removal Path = "{CacheHome}/Example" # globs allowed Kind = "Runtime" # or "Config" Mode = "Remove" # or "IfEmpty" Note = "thumbnail cache" ``` `Hooks.py` can define `Leftovers(Context: dict) -> list[Manifests.Leftover]` for leftovers that depend on the program's own config (see `Programs/SaraSortd/Hooks.py`).