macOS support (code only, no build yet)

This commit is contained in:
sarah committed 2026-10-14 13:18:20 +02:00
1 parent 1feb6d4336
commit ca04dcd4a7
17 files changed
+572 -126

No files matched your search

+44 -27
View File
@@ -79,34 +79,44 @@ an option off takes out what it placed and puts back any file it had replaced; t
places it. It reapplies the installed commit, so the program itself isn't updated. The
**Update** button only shows up when there's an update (or a broken install to repair).
## Windows
## Windows and macOS
`SaraSuite.exe` is the Windows version. Each build only lists the programs for its own system
(a manifest's `Platforms`), and does everything the Windows way:
`SaraSuite.exe` is the Windows version; on macOS SaraSuite runs from source for now (there's no
Mac build yet, see below). Each one only lists the programs for its own system (a manifest's
`Platforms`), and does everything that system's way:
| Linux | Windows |
| --- | --- |
| `~/.config/SaraSuite/` (settings) | `%APPDATA%\SaraSuite\` |
| `~/.local/share/SaraSuite/` (programs, receipts) | `%LOCALAPPDATA%\SaraSuite\` |
| `~/.cache/...` | `%LOCALAPPDATA%\...` |
| desktop entry | Start Menu shortcut (`[[Shortcuts]]`) |
| systemd user service | `ServiceRun.py`, started at login by a shortcut in the Startup folder; its PID is in `%LOCALAPPDATA%\SaraSuite\Services\<Name>.pid` |
| Linux | Windows | macOS |
| --- | --- | --- |
| `~/.config/SaraSuite/` (settings) | `%APPDATA%\SaraSuite\` | `~/Library/Application Support/SaraSuite/` |
| `~/.local/share/SaraSuite/` (programs, receipts) | `%LOCALAPPDATA%\SaraSuite\` | the same folder as the settings, as Mac apps do |
| `~/.cache/...` | `%LOCALAPPDATA%\...` | `~/Library/Caches/...` |
| desktop entry | Start Menu shortcut (`[[Shortcuts]]`) | `~/Applications/<Name>.app`, a small app bundle (`[[Shortcuts]]`) |
| systemd user service | `ServiceRun.py`, started at login by a shortcut in the Startup folder | `ServiceRun.py`, started at login by a LaunchAgent, `~/Library/LaunchAgents/srhtnin.<Name>.plist` |
| system `python3` | the `py` launcher / `python.exe`; if there's none, SaraSuite installs Python for the user with winget | a standalone Python that uv installs into SaraSuite's own folder (`Python/`, uv itself in `Tools/`); no admin, Homebrew or Xcode tools |
| AppImage self-update (rename over it) | `.exe` self-update (the running one is renamed to `SaraSuite.old.exe`, deleted on the next start) | `SaraSuite-macOS.zip` self-update (unpacked next to `SaraSuite.app`, then swapped in) |
A service run by `ServiceRun.py` restarts 10 seconds after it fails, like the unit's
`Restart=on-failure`, and keeps its output in SaraSuite's `Services/<Name>.log`, its PID next to it
in `<Name>.pid` (that's how SaraSuite and SaraSort tell it runs, and stop it).
Linux without systemd (no `/run/systemd/system`: runit on Void, OpenRC, s6, dinit, ...) runs
services like Windows does (`Services.py`): `ServiceRun.py` runs them, started at login by an XDG
autostart entry, `~/.config/autostart/<Name>.desktop`, which desktop sessions start whatever the
init system is. It restarts a service 10 seconds after it fails, like the unit's
`Restart=on-failure`, and keeps its output in `~/.local/share/SaraSuite/Services/<Name>.log` (its
PID next to it, in `<Name>.pid`). Units aren't written there, and `RestartUnits` stops the process
instead (D-Bus starts `xdg-desktop-portal` again when it's needed). A window manager that doesn't
run XDG autostart entries needs to start them itself (e.g. `dex -a` in its startup config).
| system `python3` | the `py` launcher / `python.exe`; if there's none, SaraSuite installs Python for the user with winget |
| AppImage self-update (rename over it) | `.exe` self-update (the running one is renamed to `SaraSuite.old.exe`, deleted on the next start) |
services the same way (`Services.py`), started at login by an XDG autostart entry,
`~/.config/autostart/<Name>.desktop`, which desktop sessions start whatever the init system is.
Units aren't written there, and `RestartUnits` stops the process instead (D-Bus starts
`xdg-desktop-portal` again when it's needed). A window manager that doesn't run XDG autostart
entries needs to start them itself (e.g. `dex -a` in its startup config).
Programs run on Windows with `pythonw.exe -X utf8` (no console window; UTF-8 mode, since Python
on Windows otherwise reads text files in the old ANSI code page). Nothing needs admin rights.
Linux-only features (SaraFem's file picker portal and default-file-manager option) simply
aren't offered there.
on Windows otherwise reads text files in the old ANSI code page). Nothing needs admin rights on
either system. Linux-only features (SaraFem's file picker portal and default-file-manager option)
simply aren't offered there, and on macOS SaraTune has no media keys (see its README).
macOS is written but not tested on a real Mac yet (Apple Silicon only). Things to know there:
- SaraSortd sorting `~/Downloads`, `~/Documents` or `~/Desktop` needs permission: macOS asks the
first time, or the Python in `~/Library/Application Support/SaraSuite/Python/` can be given
Full Disk Access in System Settings > Privacy & Security.
- A program's Dock icon is the Flet client's, not its own; its app bundle in `~/Applications`
(what Launchpad and Spotlight show) has the right one.
## Running and building
@@ -116,6 +126,9 @@ aren't offered there.
- Windows: `Packaging/BuildExe.sh` builds `dist/SaraSuite.exe` with the Windows Python inside a
Wine prefix (`build/WinBuild/`, set up on its first run), since PyInstaller can't build for
Windows from Linux directly. The .exe's header has an "Add to Start menu" button.
- macOS: there's no build yet (PyInstaller can only build a Mac app on a Mac). Run it from
source: `python3 -m venv .venv && .venv/bin/pip install -r requirements.txt`, then
`.venv/bin/python Main.py` (any Python 3.10+ for SaraSuite itself; the programs get uv's).
- 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:
@@ -131,7 +144,7 @@ aren't offered there.
## Where things live
On Linux (on Windows, the same layout under `%LOCALAPPDATA%` and `%APPDATA%`; see Windows above):
On Linux (on Windows and macOS, the same layout in their own folders; see Windows and macOS above):
| Path | What |
| --- | --- |
@@ -155,17 +168,18 @@ Targets, templates and `Set` values can use `{Variables}`: `Name`, `GitHost`, `H
`Desktop` (e.g. `cosmic`), plus every Question's `Id`. Linux only: `PortalsDir` (your own xdg-desktop-portal folder where it's 1.17+, else
`/usr/share/...`), `PortalsConf` (`<desktop>-portals.conf`, or `portals.conf` without a desktop name),
`DesktopPortal` (`<desktop>;` or nothing), `SystemdUserDir`,
`ApplicationsDir`, `DBusServicesDir`. Windows only: `StartMenuDir`, `StartupDir`.
`ApplicationsDir`, `DBusServicesDir`. Windows only: `StartMenuDir`, `StartupDir`. macOS only:
`ApplicationsDir` (`~/Applications`), `LaunchAgentsDir`.
Every list item (`[[Options]]`, `[[Templates]]`, `[[Services]]`, ...) can carry
`Platform = "Linux"` or `"Windows"` to only apply on that system; items without one apply on both.
`Platform = "Linux"`, `"Windows"` or `"macOS"` to only apply on that system; items without one apply everywhere.
In TOML templates, write paths as literal strings (`'{ConfigDir}'`): Windows paths are full of
backslashes, which a `"..."` string would read as escapes.
```toml
Name = "Example"
Description = "Shown on the program's card."
Platforms = ["Linux", "Windows"] # where it runs (default ["Linux"])
Platforms = ["Linux", "Windows", "macOS"] # where it runs (default ["Linux"])
Parent = "SaraSortd" # optional: listed (indented) under that program
RestartUnits = ["xdg-desktop-portal.service"] # try-restarted after install/update/remove
@@ -215,7 +229,8 @@ WorkingDir = "{ConfigDir}"
Option = "Autostart"
[[Services]] # Windows: run by ServiceRun.py from a Startup-folder shortcut
Platform = "Windows" # (both: add ../../ServiceRun.py as a Template to {ProgramDir})
Platform = "Windows" # (macOS: the same with Platform = "macOS", from a LaunchAgent;
# both: add ../../ServiceRun.py as a Template to {ProgramDir})
Name = "Example"
Script = "Example.py" # relative to the app folder
WorkingDir = "{ConfigDir}"
@@ -226,6 +241,8 @@ Platform = "Windows"
Name = "Example"
Script = "Main.py" # relative to the app folder, which is also its working folder
Icon = "assets/Icon.png" # turned into an .ico
# macOS: the same with Platform = "macOS" makes ~/Applications/<Name>.app
# (the venv's python Script; the icon becomes an .icns)
[[IniEdits]] # one key in a file SaraSuite doesn't own; restored on removal
File = "{ConfigHome}/mimeapps.list"