fix(sync): resolve versioned launcher symlinks

This commit is contained in:
fy59 2026-09-17 16:09:58 +02:00
parent 1552dcac1f
commit 05c93777d6
4 changed files with 19 additions and 3 deletions

View file

@ -14,6 +14,9 @@
SQLite value whether a real backup contains an active draft or legitimately
contains none.
- Made relocatable launchers resolve stable user-bin symlinks to their physical
versioned bundle before loading matching binaries and helpers.
- Closed the native candidate warning gate with checked path and HTTP response
bounds, strict GCC and Clang builds, full Clang ASan/UBSan validation, and a
stable concurrent object-I/O MTP double. Rebuilt the desktop, current Android

View file

@ -26,6 +26,8 @@ the separately authorized rollout are complete.
`trainlog-syncd`, the production generation MTP adapter and their matching
Python codecs. User units must point only into one versioned bundle; they
must not combine a packaged binary with helpers from a live checkout.
Stable user-bin symlinks are supported: each launcher resolves the link to
its physical bundle before locating `libexec` and `tools`.
2. `assembleDebug` is development evidence only. Rollout requires the existing
release signing identity, verification of its public certificate and a valid
increasing `versionCode`. A bounded `TRAINLOG_ANDROID_VERSION_CODE` build

View file

@ -66,6 +66,16 @@ class DeploymentToolsTest(unittest.TestCase):
self.assertTrue((output / "bin/trainlog-sync-once").is_file())
self.assertTrue((output / "bin/trainlog-syncd").is_file())
self.assertTrue((output / "libexec/trainlog-sync-once").is_file())
stable_bin = Path(directory) / "stable-bin"
stable_bin.mkdir()
(stable_bin / "trainlog").symlink_to(output / "bin/trainlog")
linked = subprocess.run(
[str(stable_bin / "trainlog"), "--version"],
capture_output=True,
text=True,
)
self.assertEqual(linked.returncode, 0, linked.stderr)
self.assertIn("trainlog 0.1.2", linked.stdout)
self.assertTrue(
any(
row["path"] == "tools/trainlog_syncd.py"

View file

@ -71,15 +71,15 @@ def main() -> int:
shutil.copy2(source, args.output / "catalog" / source.name)
launcher = args.output / "bin/trainlog"
launcher.write_text(
'#!/bin/sh\nset -eu\nroot=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)\nexport TRAINLOG_SYNC_TOOLS_DIR="$root/tools"\nexport TRAINLOG_SYNC_MTP_ADAPTER="$root/libexec/trainlog-generation-mtp-adapter"\nexec "$root/libexec/trainlog" "$@"\n'
'#!/bin/sh\nset -eu\nscript=$(readlink -f -- "$0")\nroot=$(CDPATH= cd -- "$(dirname -- "$script")/.." && pwd)\nexport TRAINLOG_SYNC_TOOLS_DIR="$root/tools"\nexport TRAINLOG_SYNC_MTP_ADAPTER="$root/libexec/trainlog-generation-mtp-adapter"\nexec "$root/libexec/trainlog" "$@"\n'
)
sync_once_launcher = args.output / "bin/trainlog-sync-once"
sync_once_launcher.write_text(
'#!/bin/sh\nset -eu\nroot=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)\nexec "$root/libexec/trainlog-sync-once" "$@"\n'
'#!/bin/sh\nset -eu\nscript=$(readlink -f -- "$0")\nroot=$(CDPATH= cd -- "$(dirname -- "$script")/.." && pwd)\nexec "$root/libexec/trainlog-sync-once" "$@"\n'
)
syncd_launcher = args.output / "bin/trainlog-syncd"
syncd_launcher.write_text(
'#!/bin/sh\nset -eu\nroot=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)\nexec python3 "$root/tools/trainlog_syncd.py" --sync-once "$root/bin/trainlog-sync-once" "$@"\n'
'#!/bin/sh\nset -eu\nscript=$(readlink -f -- "$0")\nroot=$(CDPATH= cd -- "$(dirname -- "$script")/.." && pwd)\nexec python3 "$root/tools/trainlog_syncd.py" --sync-once "$root/bin/trainlog-sync-once" "$@"\n'
)
files = sorted(path for path in args.output.rglob("*") if path.is_file())
inventory = {
@ -114,6 +114,7 @@ def main() -> int:
"libudev",
"libmtp",
"notcurses",
"coreutils-readlink",
],
"files": [
{