Bundle libsecret for systems without it; first launch keeps Flet's message off the client path

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
sarahandClaude Opus 5.5 committed 2026-10-13 18:43:15 +02:00
1 parent 61c992f959
commit 5890b52da6
4 files changed
+122 -1

No files matched your search

+48 -1
View File
@@ -18,13 +18,47 @@ Used two ways:
case Flet just uses its normal client.
"""
import os
import shutil
import sys
from pathlib import Path
OriginalId = b"com.appveyor.flet"
# Flet's window needs libsecret, which isn't part of GTK and some systems don't
# install. SaraSuite keeps copies of it and what it needs (from its AppImage)
# here; MissingLibraries puts the ones this system lacks beside the client.
LibrariesDir = Path(os.environ.get("XDG_DATA_HOME") or Path.home() / ".local" / "share") / "SaraSuite" / "Libraries"
FallbackLibraries = ("libgpg-error.so.0", "libgcrypt.so.20", "libsecret-1.so.0")
CopiesDir = Path.home() / ".cache" / "SaraSuite" / "FletClient"
def _SystemHas(Name: str) -> bool:
"""Whether the system has a library (its standard folders and linker
cache; the same check as the AppImages' RestoreLibraryPath.py)."""
import subprocess
for Folder in ("/usr/lib64", "/usr/lib", "/lib64", "/lib", "/usr/lib/x86_64-linux-gnu", "/lib/x86_64-linux-gnu"):
if (Path(Folder) / Name).exists():
return True
try:
Cache = subprocess.run(["ldconfig", "-p"], capture_output=True, text=True, timeout=10,
env={"PATH": "/usr/sbin:/usr/bin:/sbin:/bin"}).stdout
except (OSError, subprocess.SubprocessError):
return False
return any(Line.strip().startswith(Name + " ") for Line in Cache.splitlines())
def AddMissingLibraries(ClientLib: Path) -> None:
"""Copies SaraSuite's fallback libraries the system doesn't have into the
client's lib folder (it looks there first: its RUNPATH is $ORIGIN/lib)."""
if not sys.platform.startswith("linux") or not LibrariesDir.is_dir() or not ClientLib.is_dir():
return
for Name in FallbackLibraries:
Source = LibrariesDir / Name
if Source.is_file() and not (ClientLib / Name).exists() and not _SystemHas(Name):
shutil.copy2(Source, ClientLib / Name)
def ClientFor(AppId: str) -> str:
"""Folder of a client copy whose app ID is AppId ("" if not possible).
AppId needs a dot (a GTK rule) and at most 17 characters, the length of
@@ -36,6 +70,7 @@ def ClientFor(AppId: str) -> str:
from flet_desktop import ensure_client_cached # the program's own Flet version
Original = Path(ensure_client_cached()) / "flet"
AddMissingLibraries(Original / "lib")
Binary = (Original / "flet").read_bytes()
Copy = CopiesDir / f"{Original.parent.name}-{AppId}" / "flet"
Patched = Binary.replace(
@@ -64,4 +99,16 @@ def ClientFor(AppId: str) -> str:
if __name__ == "__main__":
print(ClientFor(sys.argv[1]) if len(sys.argv) > 1 else "")
# Only the folder goes to stdout, which the launcher reads: Flet's own
# messages ("Preparing Flet ... for the first use", written straight to
# the file descriptor) go to stderr.
sys.stdout.flush()
Stdout = os.dup(1)
os.dup2(2, 1)
try:
Folder = ClientFor(sys.argv[1]) if len(sys.argv) > 1 else ""
finally:
sys.stdout.flush()
os.dup2(Stdout, 1)
os.close(Stdout)
print(Folder)