Prepare 0.3.3 and migrate recognized legacy console wrappers

This commit is contained in:
Gerardo Betancourt committed 2026-10-28 12:07:52 -04:00
1 parent c0a679d989
commit b1ff87dd81
5 files changed
+55 -4

No files matched your search

@@ -1 +1 @@
__version__ = "0.3.2+private.20261028.2"
__version__ = "0.3.3"
@@ -78,6 +78,38 @@ def _new_entry(state):
"StartupWMClass=Gnome-terminal\n").encode()
def _new_wrapper(state):
command = ["/usr/bin/fb", "--state-dir", str(state), "console"]
return ("#!/usr/bin/python3\n"
'"""Open the packaged FrameBridge console using the retained local profile."""\n'
"import os\nimport sys\n"
"command = " + repr(command) + "\n"
"if sys.argv[1:] == ['--inside']:\n"
" command += ['--inside', '--mode', 'gui']\n"
"elif sys.argv[1:]:\n"
" raise SystemExit('Usage: framebridge-console')\n"
"os.execv(command[0], command)\n").encode()
def _migrate_wrapper(state, home):
path = home / ".local/bin/framebridge-console"
before, mode = _snapshot(path)
after = _new_wrapper(state)
if before == after:
return False
_need(hashlib.sha256(before).hexdigest() == LEGACY_WRAPPER_SHA256,
"CONSOLE_DESKTOP_LEGACY_WRAPPER_CHANGED")
backup = state / "console-wrapper-legacy.backup"
if backup.exists() or backup.is_symlink():
data, backup_mode = _snapshot(backup)
_need(data == before and backup_mode == 0o600, "CONSOLE_DESKTOP_WRAPPER_BACKUP_CHANGED")
else:
_atomic(backup, before)
_need(_snapshot(path)[0] == before, "CONSOLE_DESKTOP_WRAPPER_CHANGED_DURING_MIGRATION")
_atomic(path, after, mode)
return True
def _legacy_identity(node, runtime):
return {"socket": runtime / (node.lower() + "-tty1") / "console.sock",
"session": node.upper() + "-FBTERM"}
@@ -123,7 +155,9 @@ def migrate_legacy(state, *, home=None, node=None, runtime=None):
after = _new_entry(state)
if before == after:
_need(legacy_context(state, node, runtime) is not None, "CONSOLE_DESKTOP_RECORD_MISSING")
return {"ok": True, "changed": False, "reason": "ALREADY_MIGRATED"}
wrapper_changed = _migrate_wrapper(state, home)
return {"ok": True, "changed": wrapper_changed, "reason": "ALREADY_MIGRATED",
"wrapper_changed": wrapper_changed}
if before != _legacy_entry(home):
return {"ok": True, "changed": False, "reason": "CUSTOM_DESKTOP_ENTRY_PRESERVED"}
wrapper, _ = _snapshot(home / ".local/bin/framebridge-console")
@@ -166,6 +200,8 @@ def migrate_legacy(state, *, home=None, node=None, runtime=None):
_atomic(state / RECORD, (json.dumps(record, sort_keys=True, indent=2) + "\n").encode())
_need(_snapshot(desktop)[0] == before, "CONSOLE_DESKTOP_CHANGED_DURING_MIGRATION")
_atomic(desktop, after, mode)
wrapper_changed = _migrate_wrapper(state, home)
return {"ok": True, "changed": True, "desktop": str(desktop),
"wrapper_changed": wrapper_changed,
"session": identity["session"], "socket": str(identity["socket"]),
"backup": str(backup), "runtime_changed": False}
+1 -1
View File
@@ -11,7 +11,7 @@ from pathlib import Path
import re
CANDIDATE_VERSION = "0.3.2"
CANDIDATE_VERSION = "0.3.3"
VENDOR_RELATIVE = Path("original/geranas/FrameBridge-Fleet-Hub/vendor")
SOURCE_VENDOR = Path("sources/original-geranas/FrameBridge-Fleet-Hub/vendor")
GLIBC_BASELINE = (2, 34)
+15
View File
@@ -56,6 +56,9 @@ class DesktopMigrationTests(unittest.TestCase):
self.assertFalse(value["runtime_changed"])
self.assertEqual((self.state / "console-desktop-legacy.backup").read_bytes(), before)
self.assertEqual(self.desktop.read_bytes(), console_desktop._new_entry(self.state))
self.assertEqual(self.wrapper.read_bytes(), console_desktop._new_wrapper(self.state))
self.assertEqual((self.state / "console-wrapper-legacy.backup").read_bytes(), b"#!/usr/bin/python3\npass\n")
self.assertTrue(value["wrapper_changed"])
context = console_desktop.legacy_context(self.state, "TestHost", self.runtime)
self.assertEqual(context["session"], "TESTHOST-FBTERM")
self.assertEqual(context["socket"], self.runtime / "testhost-tty1/console.sock")
@@ -122,6 +125,18 @@ class ConsoleWindowSelectionTests(unittest.TestCase):
value = console.exists()
return console, value
def test_migrated_wrapper_targets_the_packaged_profile_without_a_shell(self):
state = Path("/home/user/profile")
with mock.patch("sys.argv", ["framebridge-console"]), mock.patch("os.execv") as execute:
exec(compile(console_desktop._new_wrapper(state), "wrapper", "exec"), {})
execute.assert_called_once_with("/usr/bin/fb", ["/usr/bin/fb", "--state-dir", str(state), "console"])
def test_migrated_inside_wrapper_does_not_create_another_viewer(self):
state = Path("/home/user/profile")
with mock.patch("sys.argv", ["framebridge-console", "--inside"]), mock.patch("os.execv") as execute:
exec(compile(console_desktop._new_wrapper(state), "wrapper", "exec"), {})
self.assertEqual(execute.call_args.args[1][-3:], ["--inside", "--mode", "gui"])
def test_monitor_receives_profile_jobs_root_as_an_explicit_argument(self):
args = SimpleNamespace(socket="/owned/socket", session="NODE-FBTERM", node="NODE",
jobs_root=Path("/profile with space/jobs"))