mirror of
https://git.srhtnin.garden/sarah/SaraSuite.git
synced 2026-10-15 02:33:17 +02:00
Release both builds; Windows docs
This commit is contained in:
1 parent
6fe282f686
commit
9f99adc519
3 files changed
+76
-21
No files matched your search
@@ -23,7 +23,7 @@ import tomlkit
|
||||
AppName = "SaraSuite"
|
||||
# Compared with the latest Gitea release to offer self-updates (SelfUpdate.py).
|
||||
# Bump it, then run Packaging/Release.py, to publish a new SaraSuite.
|
||||
AppVersion = "1.1.1"
|
||||
AppVersion = "1.2.0"
|
||||
IsFrozen = bool(getattr(sys, "frozen", False)) # running from the AppImage / .exe
|
||||
IsWindows = sys.platform == "win32"
|
||||
Platform = "Windows" if IsWindows else "Linux" # matches manifests' Platforms / Platform
|
||||
|
||||
+25
-16
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Publish a SaraSuite release: build the AppImage, create the Gitea release
|
||||
v<AppVersion> (from Core.py) with it attached, and copy it to the Shared
|
||||
folder. Running SaraSuites then offer to update themselves (SelfUpdate.py).
|
||||
"""Publish a SaraSuite release: build the AppImage (Linux) and SaraSuite.exe
|
||||
(Windows, built under Wine by BuildExe.sh), create the Gitea release
|
||||
v<AppVersion> (from Core.py) with both attached, and copy them to the Shared
|
||||
folder. Running SaraSuites then offer to update themselves (SelfUpdate.py),
|
||||
each to its own platform's file.
|
||||
|
||||
Packaging/Release.py # after bumping AppVersion in Core.py
|
||||
Packaging/Release.py --notes "What changed"
|
||||
@@ -25,7 +27,11 @@ from pathlib import Path
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
RepoDir = Path(__file__).resolve().parent.parent
|
||||
AppImage = RepoDir / "dist" / "SaraSuite-x86_64.AppImage"
|
||||
# Each running SaraSuite downloads the one for its own platform (SelfUpdate.AssetName).
|
||||
Builds = [
|
||||
("Packaging/BuildAppImage.sh", RepoDir / "dist" / "SaraSuite-x86_64.AppImage"),
|
||||
("Packaging/BuildExe.sh", RepoDir / "dist" / "SaraSuite.exe"),
|
||||
]
|
||||
SharedDir = Path("/mnt/files/Shared/SaraSuite")
|
||||
|
||||
|
||||
@@ -93,26 +99,29 @@ def Main() -> None:
|
||||
Range = f"{Previous[0]}..HEAD" if Previous else "HEAD"
|
||||
Notes = Git("log", "--format=- %s", Range) or "- First release with self-updates."
|
||||
|
||||
print(f"== Building SaraSuite {Version}")
|
||||
subprocess.run(["Packaging/BuildAppImage.sh"], cwd=RepoDir, check=True,
|
||||
env={**os.environ, "PATH": f"{Path.home()}/.local/bin:{os.environ['PATH']}"})
|
||||
for Script, Output in Builds:
|
||||
print(f"== Building {Output.name} {Version}")
|
||||
subprocess.run([Script], cwd=RepoDir, check=True,
|
||||
env={**os.environ, "PATH": f"{Path.home()}/.local/bin:{os.environ['PATH']}"})
|
||||
|
||||
print(f"== Creating release {Tag}")
|
||||
Created = Api("POST", f"{ApiBase}/releases", TokenValue, json.dumps({
|
||||
"tag_name": Tag, "target_commitish": Head, "name": f"SaraSuite {Version}", "body": Notes,
|
||||
}).encode())
|
||||
|
||||
print(f"== Uploading {AppImage.name} ({AppImage.stat().st_size // 1_000_000} MB)")
|
||||
Boundary = uuid.uuid4().hex
|
||||
Body = (
|
||||
f"--{Boundary}\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"{AppImage.name}\"\r\n"
|
||||
f"Content-Type: application/octet-stream\r\n\r\n"
|
||||
).encode() + AppImage.read_bytes() + f"\r\n--{Boundary}--\r\n".encode()
|
||||
Api("POST", f"{ApiBase}/releases/{Created['id']}/assets?name={AppImage.name}", TokenValue, Body,
|
||||
f"multipart/form-data; boundary={Boundary}")
|
||||
for _Script, Output in Builds:
|
||||
print(f"== Uploading {Output.name} ({Output.stat().st_size // 1_000_000} MB)")
|
||||
Boundary = uuid.uuid4().hex
|
||||
Body = (
|
||||
f"--{Boundary}\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"{Output.name}\"\r\n"
|
||||
f"Content-Type: application/octet-stream\r\n\r\n"
|
||||
).encode() + Output.read_bytes() + f"\r\n--{Boundary}--\r\n".encode()
|
||||
Api("POST", f"{ApiBase}/releases/{Created['id']}/assets?name={Output.name}", TokenValue, Body,
|
||||
f"multipart/form-data; boundary={Boundary}")
|
||||
|
||||
if SharedDir.is_dir():
|
||||
shutil.copy2(AppImage, SharedDir / AppImage.name)
|
||||
for _Script, Output in Builds:
|
||||
shutil.copy2(Output, SharedDir / Output.name)
|
||||
print(f"== Copied to {SharedDir}")
|
||||
Git("fetch", "--quiet", "--tags", "origin") # the new tag, for the next release's notes
|
||||
print(f"== Released {Tag}: {Origin.scheme}://{Origin.netloc}/{Owner}/{Repo}/releases/tag/{Tag}")
|
||||
|
||||
@@ -78,11 +78,34 @@ 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
|
||||
|
||||
`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:
|
||||
|
||||
| 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` |
|
||||
| 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) |
|
||||
|
||||
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.
|
||||
|
||||
## 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.
|
||||
- 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.
|
||||
- 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:
|
||||
@@ -98,6 +121,8 @@ places it. It reapplies the installed commit, so the program itself isn't update
|
||||
|
||||
## Where things live
|
||||
|
||||
On Linux (on Windows, the same layout under `%LOCALAPPDATA%` and `%APPDATA%`; see Windows above):
|
||||
|
||||
| Path | What |
|
||||
| --- | --- |
|
||||
| `~/.local/share/SaraSuite/Programs/<Name>/` | installed program (`App/`) and its `.venv/` |
|
||||
@@ -115,13 +140,20 @@ Manifests are bundled into the AppImage, so a new or changed manifest means rebu
|
||||
Anything the manifest can't describe goes in an optional `Programs/<Name>/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`.
|
||||
`DataHome`, `CacheHome`, `ProgramDir`, `AppDir`, `Python` (the venv's python), `PythonW`
|
||||
(Windows: its console-less pythonw.exe), `ConfigDir`, `DesktopName` (e.g. `COSMIC`),
|
||||
`Desktop` (e.g. `cosmic`), plus every Question's `Id`. Linux only: `SystemdUserDir`,
|
||||
`ApplicationsDir`, `DBusServicesDir`. Windows only: `StartMenuDir`, `StartupDir`.
|
||||
|
||||
Every list item (`[[Options]]`, `[[Templates]]`, `[[Services]]`, ...) can carry
|
||||
`Platform = "Linux"` or `"Windows"` to only apply on that system; items without one apply on both.
|
||||
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"])
|
||||
Parent = "SaraSortd" # optional: listed (indented) under that program
|
||||
RestartUnits = ["xdg-desktop-portal.service"] # try-restarted after install/update/remove
|
||||
|
||||
@@ -161,10 +193,24 @@ 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
|
||||
[[Services]] # Linux: systemd --user units, enabled + started
|
||||
Platform = "Linux"
|
||||
Unit = "Example.service"
|
||||
Option = "Autostart"
|
||||
|
||||
[[Services]] # Windows: run by ServiceRun.py from a Startup-folder shortcut
|
||||
Platform = "Windows" # (also add ../../ServiceRun.py as a Template to {ProgramDir})
|
||||
Name = "Example"
|
||||
Script = "Example.py" # relative to the app folder
|
||||
WorkingDir = "{ConfigDir}"
|
||||
Option = "Autostart"
|
||||
|
||||
[[Shortcuts]] # Windows: a Start Menu shortcut (pythonw.exe -X utf8 Script)
|
||||
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
|
||||
|
||||
[[IniEdits]] # one key in a file SaraSuite doesn't own; restored on removal
|
||||
File = "{ConfigHome}/mimeapps.list"
|
||||
Section = "Default Applications"
|
||||
|
||||
Reference in new issue
Block a user