fix(flatpak): console on host + dialog persistence
- term console via flatpak-spawn --host so host venvs resolve (bins.host_console_command) - QSettings sync() before subprocess kill in choices/tested-refs dialogs - console regression test: fails on the in-sandbox 0.2.1 console Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -81,9 +81,13 @@ class TermConsole(Console):
|
|||||||
bufsize=0)
|
bufsize=0)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.term = pexpect.spawn( shell_cmd,
|
# In Flatpak this returns a `flatpak-spawn --host` wrapper so the
|
||||||
echo=False,
|
# console behaves like a host shell (matching py_func / lua_func /
|
||||||
cwd=self.ppath)
|
# run); elsewhere it's the chosen command unchanged.
|
||||||
|
from interpreter.utils import bins
|
||||||
|
argv = bins.host_console_command(shell_cmd, self.ppath)
|
||||||
|
self.term = pexpect.spawn(argv[0], args=argv[1:],
|
||||||
|
echo=False, cwd=self.ppath)
|
||||||
|
|
||||||
self.q = BytesStore()
|
self.q = BytesStore()
|
||||||
self.t = threading.Thread(target=self.enqueue_output)
|
self.t = threading.Thread(target=self.enqueue_output)
|
||||||
|
|||||||
@@ -221,6 +221,11 @@ def main(args, conn=None):
|
|||||||
|
|
||||||
if conn:
|
if conn:
|
||||||
settings.setValue(SettingsLastChoices, result)
|
settings.setValue(SettingsLastChoices, result)
|
||||||
|
# Flush before sending: the parent terminates this subprocess as soon
|
||||||
|
# as it reads the result, so the QSettings destructor never runs and
|
||||||
|
# the write would race the kill (lost under Flatpak — see the
|
||||||
|
# tested-references dialog for the full rationale).
|
||||||
|
settings.sync()
|
||||||
conn.send([result, success])
|
conn.send([result, success])
|
||||||
conn.close()
|
conn.close()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ def main(args, conn=None):
|
|||||||
|
|
||||||
if conn:
|
if conn:
|
||||||
settings.setValue(SettingsLastReference, result)
|
settings.setValue(SettingsLastReference, result)
|
||||||
|
# Flush to disk *before* handing the result back: as soon as the parent
|
||||||
|
# receives it on the pipe it terminates this subprocess (SIGTERM, no
|
||||||
|
# handler), so the QSettings destructor never runs. Without sync() the
|
||||||
|
# write races the kill and is lost — reliably so under Flatpak, where
|
||||||
|
# the .conf is atomically renamed on the slower ~/.var/app overlay.
|
||||||
|
settings.sync()
|
||||||
conn.send([result, success])
|
conn.send([result, success])
|
||||||
conn.close()
|
conn.close()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ Public API
|
|||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import os
|
import os
|
||||||
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -177,6 +178,27 @@ def flatpak_host_spawn(interp_bin, cmd_args, host_cwd, extra_env=None):
|
|||||||
return spawn
|
return spawn
|
||||||
|
|
||||||
|
|
||||||
|
def host_console_command(shell_cmd, cwd):
|
||||||
|
"""Build the argv to start *shell_cmd* as an ordinary interactive console.
|
||||||
|
|
||||||
|
*shell_cmd* is the command the caller chose (a string — shell-split — or
|
||||||
|
an argv list); the choice is preserved verbatim.
|
||||||
|
|
||||||
|
Outside Flatpak the command is returned unchanged. Inside Flatpak a bare
|
||||||
|
spawn would run in the sandbox under the runtime python3, so a host venv
|
||||||
|
(``/path/venv/bin/python3 -m mod``) can't see its pip deps. We simply run
|
||||||
|
it on the host with ``flatpak-spawn --host`` so it behaves like any other
|
||||||
|
terminal: flatpak-spawn passes the current environment through unchanged
|
||||||
|
and the shell (sourced venv, profile, …) sets things up as the user wants.
|
||||||
|
No env forwarding or scrubbing — the launcher's leaked PYTHONPATH points at
|
||||||
|
/app paths absent on the host, so it's inert there.
|
||||||
|
"""
|
||||||
|
argv = shlex.split(shell_cmd) if isinstance(shell_cmd, str) else list(shell_cmd)
|
||||||
|
if not _in_flatpak():
|
||||||
|
return argv
|
||||||
|
return ["flatpak-spawn", "--host", f"--directory={cwd}", *argv]
|
||||||
|
|
||||||
|
|
||||||
def _which_host_flatpak(name):
|
def _which_host_flatpak(name):
|
||||||
"""Resolve a binary name (or absolute path) on the host via flatpak-spawn.
|
"""Resolve a binary name (or absolute path) on the host via flatpak-spawn.
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,17 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
- read_until: {expected: endOfCmd, timeout: 1, process_result: "'Hello' in r'''$(result)''' and 'PASS' in r'''$(result)''' "}
|
- read_until: {expected: endOfCmd, timeout: 1, process_result: "'Hello' in r'''$(result)''' and 'PASS' in r'''$(result)''' "}
|
||||||
|
|
||||||
|
{% if os == "Linux" %}
|
||||||
|
- console:
|
||||||
|
name: Console runs on host (not the Flatpak sandbox)
|
||||||
|
doc: Regression guard for the 0.2.1 Flatpak bug (term console spawned inside the sandbox instead of on the host). /.flatpak-info exists only inside the sandbox, so the host-only marker is emitted (and matched by read_until) ONLY when the shell really runs on the host. On a broken Flatpak the marker never appears, read_until times out and the item FAILS. The marker is built at runtime ($M) so it is never present in the command line itself. Passes on every other channel.
|
||||||
|
console_name: term
|
||||||
|
key: $(test)_PASS
|
||||||
|
steps:
|
||||||
|
- writeln: 'test -e /.flatpak-info && M=SANDBOX || M=HOST; echo "console_host_check_$M"'
|
||||||
|
- read_until: {expected: console_host_check_HOST, timeout: 5}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
- console:
|
- console:
|
||||||
name: Console closure
|
name: Console closure
|
||||||
execute_on_stop: true
|
execute_on_stop: true
|
||||||
|
|||||||
Reference in New Issue
Block a user