From c0f3d4cbfa54f4a16d8229d1fb6cbcac60bd5f76 Mon Sep 17 00:00:00 2001 From: SRHTNIN Date: Thu, 8 Oct 2026 19:06:24 +0200 Subject: [PATCH] Make SaraTag installable through SaraSuite. --- .saratag/Core.py | 41 +++++++++++++++++-- Packaging/SaraSuite/Manifest.toml | 37 +++++++++++++++++ Packaging/SaraSuite/Templates/Launch.sh | 4 ++ Packaging/SaraSuite/Templates/Location.toml | 3 ++ Packaging/SaraSuite/Templates/SaraTag.desktop | 9 ++++ README.md | 15 +++++-- 6 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 Packaging/SaraSuite/Manifest.toml create mode 100644 Packaging/SaraSuite/Templates/Launch.sh create mode 100644 Packaging/SaraSuite/Templates/Location.toml create mode 100644 Packaging/SaraSuite/Templates/SaraTag.desktop diff --git a/.saratag/Core.py b/.saratag/Core.py index 9c0b017..d74aadf 100755 --- a/.saratag/Core.py +++ b/.saratag/Core.py @@ -1,6 +1,7 @@ from __future__ import annotations import copy +import os import sys import tomllib from pathlib import Path @@ -11,15 +12,48 @@ ApplicationName = "SaraTag" ApplicationVersion = "0.1.0-beta" -def GetApplicationDirectory() -> Path: - """Return the portable directory containing SaraTag.""" +def GetProgramDirectory() -> Path: + """Return the directory containing SaraTag's program files.""" if getattr(sys, "frozen", False): return Path(sys.executable).resolve().parent return Path(__file__).resolve().parent.parent -ApplicationDirectory = GetApplicationDirectory() +def GetDataDirectory(ProgramDirectory: Path) -> Path: + """Return where SaraTagConf.toml, the Records, history and Lexicons live. + + In order: the SARATAG_DATA_DIR environment variable; DataDir in + .saratag/Location.toml (SaraSuite writes it, pointing at + ~/.config/SaraSuite/SaraTag); otherwise the program directory itself, + so a plain copy (and SaraView's mount) stays portable. + """ + Override = os.environ.get("SARATAG_DATA_DIR", "").strip() + if Override: + return Path(Override).expanduser().resolve() + + LocationPath = ProgramDirectory / ".saratag" / "Location.toml" + if LocationPath.is_file(): + try: + with LocationPath.open("rb") as LocationFile: + DataDir = tomllib.load(LocationFile).get("DataDir") + except (OSError, tomllib.TOMLDecodeError): + DataDir = None + if isinstance(DataDir, str) and DataDir.strip(): + return Path(DataDir).expanduser().resolve() + + return ProgramDirectory + + +ProgramDirectory = GetProgramDirectory() +# The name is older than the data/program split: SaraFem, SaraView and the +# functions below all use it as the data directory. +ApplicationDirectory = GetDataDirectory(ProgramDirectory) + + +def GetApplicationDirectory() -> Path: + """Kept for older callers: the data directory.""" + return ApplicationDirectory SaraTagConfPath = ApplicationDirectory / "SaraTagConf.toml" SaraTagRecordsPath = ApplicationDirectory / ".SaraTagRecords.toml" SaraTagHistoryPath = ApplicationDirectory / ".SaraTagHistory.toml" @@ -828,6 +862,7 @@ def EnsureTextFile(FilePath: Path, DefaultContent: str) -> bool: def EnsureConfigFiles() -> list[Path]: """Ensure SaraTag's portable configuration files exist.""" CreatedFiles: list[Path] = [] + ApplicationDirectory.mkdir(parents=True, exist_ok=True) if EnsureTextFile(SaraTagConfPath, DefaultSaraTagConf): CreatedFiles.append(SaraTagConfPath) diff --git a/Packaging/SaraSuite/Manifest.toml b/Packaging/SaraSuite/Manifest.toml new file mode 100644 index 0000000..0b1e2dc --- /dev/null +++ b/Packaging/SaraSuite/Manifest.toml @@ -0,0 +1,37 @@ +# Kept in sync between SaraSuite/Programs/SaraTag/ and SaraTag/Packaging/SaraSuite/. +Name = "SaraTag" +Description = "Tag files with Books (sidecars) defined by Lexicons: browse, filter and sort by tag, edit tags on many files at once." + +[Version] +File = "Core.py" +Pattern = 'AppVersion = "([^"]+)"' + +[Source] +Git = "{GitHost}/SaraTag" +# .saratag/Core.py is the data library SaraFem and SaraView load too. +# SaraTagConf.toml is left out: SaraTag makes its own in {ConfigDir}. +Include = ["*.py", "requirements.txt", "assets/**", ".saratag/*.py"] +Exclude = ["Packaging"] + +[Python] +RequirementsFile = "requirements.txt" + +[[Templates]] +Source = "Location.toml" +Target = "{AppDir}/.saratag/Location.toml" # tells .saratag/Core.py where the data lives + +[[Templates]] +Source = "Launch.sh" +Target = "{AppDir}/Packaging/Launch.sh" +Executable = true + +[[Templates]] +Source = "SaraTag.desktop" +Target = "{ApplicationsDir}/SaraTag.desktop" + +# Made by SaraTag itself. The Lexicons are your tag definitions: only tick +# "remove configs" if you don't need them any more. +[[Leftovers]] +Path = "{ConfigDir}" +Kind = "Config" +Note = "SaraTag's settings, Records, Libraries, history and Lexicons (Books next to your files are never touched)" diff --git a/Packaging/SaraSuite/Templates/Launch.sh b/Packaging/SaraSuite/Templates/Launch.sh new file mode 100644 index 0000000..c606b43 --- /dev/null +++ b/Packaging/SaraSuite/Templates/Launch.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# Written by SaraSuite. Runs from the app folder so Flet finds assets/. +cd "{AppDir}" || exit 1 +exec "{Python}" Main.py "$@" diff --git a/Packaging/SaraSuite/Templates/Location.toml b/Packaging/SaraSuite/Templates/Location.toml new file mode 100644 index 0000000..7d04cd3 --- /dev/null +++ b/Packaging/SaraSuite/Templates/Location.toml @@ -0,0 +1,3 @@ +# Written by SaraSuite. Where SaraTag keeps SaraTagConf.toml, its Records, +# history and Lexicons (see .saratag/Core.py). +DataDir = "{ConfigDir}" diff --git a/Packaging/SaraSuite/Templates/SaraTag.desktop b/Packaging/SaraSuite/Templates/SaraTag.desktop new file mode 100644 index 0000000..afcc970 --- /dev/null +++ b/Packaging/SaraSuite/Templates/SaraTag.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=SaraTag +Comment=Tag files with Books defined by Lexicons +Exec={AppDir}/Packaging/Launch.sh +Icon={AppDir}/assets/Icon.png +Terminal=false +Categories=Utility;Graphics; +StartupNotify=true diff --git a/README.md b/README.md index 9ac7064..6fda6fb 100644 --- a/README.md +++ b/README.md @@ -40,15 +40,22 @@ appearance and export/import, SaraTag's own settings, and `SaraTagConf.toml`'s B | --- | --- | | `~/.config/SaraSuite/Config.toml` | shared SaraSuite settings (theme, font, title bar) | | `~/.config/SaraSuite/SaraTag/Config.toml` | SaraTag's own GUI settings | -| `SaraTagConf.toml` | SaraTag's data settings (portable, next to the program) | +| `SaraTagConf.toml` | SaraTag's data settings | | `.SaraTagRecords.toml` | Records and Libraries | | `.SaraTagHistory.toml` | where each Record/Library was left, recent files, updater runs | -| `Lexicons/` | Lexicons (not in git) | +| `Lexicons/` | Lexicons | + +The last four live in SaraTag's data folder, which `.saratag/Core.py` picks in this order: +`$SARATAG_DATA_DIR`; `DataDir` in `.saratag/Location.toml` (installed by SaraSuite, pointing at +`~/.config/SaraSuite/SaraTag/`); otherwise the program folder itself, so a plain copy stays portable. +Missing files are created on start. None of them are in git. ## Running -`python3 -m venv .venv && .venv/bin/pip install -r requirements.txt`, then `Packaging/Launch.sh` -(or `.venv/bin/python Main.py`; `SaraTag.py` still works too). +- SaraSuite: install SaraTag from it. `Packaging/SaraSuite/` is the manifest (`Manifest.toml` + `Templates/`), + kept in sync with SaraSuite's `Programs/SaraTag/`. +- From source: `python3 -m venv .venv && .venv/bin/pip install -r requirements.txt`, then `Packaging/Launch.sh` + (or `.venv/bin/python Main.py`; `SaraTag.py` still works too). ## Files