Compare commits
2 Commits
80ecd3a919
...
4478ec3cab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4478ec3cab | ||
|
|
b7dbf54512 |
@@ -108,6 +108,8 @@ Pass 2 builds `ok_disk_names` — the set of disk names that already match the s
|
|||||||
|
|
||||||
**`selection.json`** — GUI selection state file, tracked in git. Persists which mods/groups are selected between GUI sessions. Written by the GUI; safe to delete (GUI recreates it on next save).
|
**`selection.json`** — GUI selection state file, tracked in git. Persists which mods/groups are selected between GUI sessions. Written by the GUI; safe to delete (GUI recreates it on next save).
|
||||||
|
|
||||||
|
**`run_tool` subprocess streaming:** Tool scripts are launched via `subprocess.Popen` (not `subprocess.run`) with `stdout=PIPE, stderr=STDOUT`, read line-by-line via `iter(proc.stdout.readline, "")`, and posted to the log queue immediately. Python's own output buffering is disabled with the `-u` flag and `PYTHONUNBUFFERED=1` in the environment — without these, output would batch inside the pipe and only appear when the script exits.
|
||||||
|
|
||||||
## Python Version Compatibility
|
## Python Version Compatibility
|
||||||
|
|
||||||
Minimum is Python **3.9**. All files that use `X | Y` union type annotations **must** have `from __future__ import annotations` as the first import. Without it, the `|` syntax raises `TypeError` at runtime on Python < 3.10. Every module in `arma_modlist_tools/` already has it; any new CLI script you add must include it too.
|
Minimum is Python **3.9**. All files that use `X | Y` union type annotations **must** have `from __future__ import annotations` as the first import. Without it, the `|` syntax raises `TypeError` at runtime on Python < 3.10. Every module in `arma_modlist_tools/` already has it; any new CLI script you add must include it too.
|
||||||
|
|||||||
24
gui/app.py
24
gui/app.py
@@ -191,23 +191,29 @@ class ArmaModManagerApp(ctk.CTk):
|
|||||||
|
|
||||||
def run_tool(self, script_args: list[str]) -> None:
|
def run_tool(self, script_args: list[str]) -> None:
|
||||||
"""Run a maintenance script via subprocess, streaming output to Logs."""
|
"""Run a maintenance script via subprocess, streaming output to Logs."""
|
||||||
|
import os
|
||||||
script = script_args[0]
|
script = script_args[0]
|
||||||
extra = script_args[1:]
|
extra = script_args[1:]
|
||||||
|
|
||||||
def worker() -> None:
|
def worker() -> None:
|
||||||
self.post_log(f"\n{'─'*50}\n {' '.join(script_args)}\n{'─'*50}\n")
|
self.post_log(f"\n{'─'*50}\n {' '.join(script_args)}\n{'─'*50}\n")
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(
|
env = os.environ.copy()
|
||||||
[sys.executable, str(PROJECT_ROOT / script)] + extra,
|
env["PYTHONUNBUFFERED"] = "1"
|
||||||
capture_output=True, text=True, cwd=str(PROJECT_ROOT),
|
proc = subprocess.Popen(
|
||||||
|
[sys.executable, "-u", str(PROJECT_ROOT / script)] + extra,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
text=True,
|
||||||
|
cwd=str(PROJECT_ROOT),
|
||||||
|
env=env,
|
||||||
)
|
)
|
||||||
if result.stdout:
|
for line in iter(proc.stdout.readline, ""):
|
||||||
self.post_log(result.stdout)
|
self.post_log(line)
|
||||||
if result.stderr:
|
proc.wait()
|
||||||
self.post_log(result.stderr)
|
ok = proc.returncode == 0
|
||||||
ok = result.returncode == 0
|
|
||||||
self.post_log(
|
self.post_log(
|
||||||
f"\n{'✓ Done' if ok else f'✗ Exited with code {result.returncode}'}.\n"
|
f"\n{'✓ Done' if ok else f'✗ Exited with code {proc.returncode}'}.\n"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.post_log(f"\n✗ Failed to start {script}: {e}\n")
|
self.post_log(f"\n✗ Failed to start {script}: {e}\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user