Retain aircraft through native landing and qualify bounded input diagnostics
This commit is contained in:
+32
-14
@@ -18,7 +18,7 @@ import uuid
|
||||
import zipfile
|
||||
|
||||
from source_bundle import build, inventory, PROJECTS
|
||||
from headless_game import assert_no_game, assert_prefix_idle, cleanup
|
||||
from headless_game import assert_no_game, assert_prefix_idle, cleanup_owned_run
|
||||
from native_report import analyze
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
@@ -109,7 +109,9 @@ def copied_authored_unchanged(source, authored):
|
||||
return copied_authored_snapshot(source, authored) == authored
|
||||
|
||||
|
||||
def command_for(steam, session, project, silent_workbench=False):
|
||||
def command_for(steam, session, project, silent_workbench=False, exit_after_init=False):
|
||||
if silent_workbench and exit_after_init:
|
||||
raise ValueError("Choose only one Workbench exit mode")
|
||||
if project not in PROJECTS:
|
||||
raise ValueError('Unknown successor project')
|
||||
command = ['gamescope', '--backend', 'headless', '-W', '1280', '-H', '720',
|
||||
@@ -125,6 +127,8 @@ def command_for(steam, session, project, silent_workbench=False):
|
||||
'-packAddonCacheDir', 'Z:'+str(session/'cache'/project)]
|
||||
if silent_workbench:
|
||||
command.append('-wbSilent')
|
||||
elif exit_after_init:
|
||||
command.append('-exitAfterInit')
|
||||
return command
|
||||
|
||||
|
||||
@@ -195,8 +199,8 @@ def quiet_streams(application_id, sink, compat):
|
||||
subprocess.run(['pactl', *args], check=True, timeout=5, stdout=subprocess.DEVNULL)
|
||||
|
||||
|
||||
def run_project(steam, compat, session, project, timeout, authored, silent_workbench=False):
|
||||
command = command_for(steam, session, project, silent_workbench)
|
||||
def run_project(steam, compat, session, project, timeout, authored, silent_workbench=False, exit_after_init=False):
|
||||
command = command_for(steam, session, project, silent_workbench, exit_after_init)
|
||||
proton = Path(command[command.index('--')+1])
|
||||
executable = Path(command[command.index('--')+3])
|
||||
profile = session/'profiles'/project
|
||||
@@ -218,7 +222,8 @@ def run_project(steam, compat, session, project, timeout, authored, silent_workb
|
||||
save(evidence/'launch.json', {'command': command, 'native_command': native_command, 'authored': authored, 'started_unix': time.time(),
|
||||
'executable_sha256': digest(executable), 'proton_sha256': digest(proton),
|
||||
'child_recorder_sha256': digest(recorder), 'native_environment_sha256': digest(environment_path),
|
||||
'silent_workbench_experiment': silent_workbench})
|
||||
'silent_workbench_experiment': silent_workbench,
|
||||
'exit_after_init_experiment': exit_after_init})
|
||||
run_id = uuid.uuid4().hex
|
||||
sink, application_id = 'erri_pack_'+run_id, 'org.escapistsrereintroduced.pack.'+run_id
|
||||
env = os.environ.copy()
|
||||
@@ -231,6 +236,7 @@ def run_project(steam, compat, session, project, timeout, authored, silent_workb
|
||||
module = None
|
||||
exit_code = None
|
||||
result, cleanup_ok, runner_error = 'timeout', True, None
|
||||
cleanup_report = None
|
||||
launch_log = evidence/'launch.log'
|
||||
deadline = time.monotonic()+timeout
|
||||
launcher_exited_at = None
|
||||
@@ -273,12 +279,19 @@ def run_project(steam, compat, session, project, timeout, authored, silent_workb
|
||||
finally:
|
||||
if child is not None:
|
||||
try:
|
||||
# Reuse guarded ordinary runner cleanup, only after owning the
|
||||
# shared prefix lock and proving that prefix was initially idle.
|
||||
cleanup(child, proton, env)
|
||||
assert_prefix_idle(compat)
|
||||
# Shared post-run adapter: normal shutdown first, then only its
|
||||
# proven canonical adopted helpers, followed by strict idle proof.
|
||||
# This never upgrades the completion result observed before cleanup.
|
||||
cleanup_report = cleanup_owned_run(child, proton, env, compat)
|
||||
cleanup_ok = isinstance(cleanup_report, dict) and cleanup_report.get('cleanup_confirmed') is True
|
||||
if not cleanup_ok:
|
||||
detail = 'Owned packaging cleanup unconfirmed'
|
||||
if isinstance(cleanup_report, dict):
|
||||
detail += ': ' + '; '.join(str(item) for item in cleanup_report.get('errors', []))
|
||||
runner_error = (runner_error + '; ' if runner_error else '') + detail
|
||||
except (OSError, ValueError, subprocess.SubprocessError) as error:
|
||||
cleanup_ok, runner_error = False, str(error)
|
||||
cleanup_ok = False
|
||||
runner_error = (runner_error + '; ' if runner_error else '') + 'Owned packaging cleanup: ' + str(error)
|
||||
if module is not None:
|
||||
try:
|
||||
subprocess.run(['pactl', 'unload-module', module], check=True, timeout=5, stdout=subprocess.DEVNULL)
|
||||
@@ -306,8 +319,9 @@ def run_project(steam, compat, session, project, timeout, authored, silent_workb
|
||||
'candidate_created': candidate, 'native_exit_code': native_exit, 'launcher_exit_code': exit_code,
|
||||
'completion_observed': result, 'display_cleanup_after_native_exit': result == 'native-child-exited',
|
||||
'silent_workbench_experiment': silent_workbench,
|
||||
'exit_after_init_experiment': exit_after_init,
|
||||
'native_status_sha256': digest(status_path) if status_path.is_file() and not status_path.is_symlink() else None,
|
||||
'cleanup_confirmed': cleanup_ok,
|
||||
'cleanup_confirmed': cleanup_ok, 'cleanup_report': cleanup_report,
|
||||
'copied_authored_unchanged': unchanged, 'runner_error': runner_error,
|
||||
'logs': logs, 'errors': errors, 'packages': packages,
|
||||
'package_contents_verified': False, 'native_consumption_verified': False,
|
||||
@@ -323,7 +337,9 @@ def run(a, root=ROOT):
|
||||
validate_session(root, steam, compat, session)
|
||||
if not 30 <= a.timeout <= 1800:
|
||||
raise ValueError('--timeout must be 30..1800 seconds per addon')
|
||||
command = command_for(steam, session, a.project)
|
||||
silent_workbench = getattr(a, 'silent_workbench', False)
|
||||
exit_after_init = getattr(a, 'exit_after_init', False)
|
||||
command = command_for(steam, session, a.project, silent_workbench, exit_after_init)
|
||||
separator = command.index('--')
|
||||
for path in (Path(command[separator+1]), Path(command[separator+3]), steam/'steamapps/common/Arma Reforger/addons/data/ArmaReforger.gproj'):
|
||||
if not path.is_file():
|
||||
@@ -344,7 +360,7 @@ def run(a, root=ROOT):
|
||||
continue_on_failure = getattr(a, 'continue_on_failure', False)
|
||||
stopped_reason = None
|
||||
for project in order:
|
||||
report = run_project(steam, compat, session, project, a.timeout, authored, getattr(a, 'silent_workbench', False))
|
||||
report = run_project(steam, compat, session, project, a.timeout, authored, silent_workbench, exit_after_init)
|
||||
reports.append(report)
|
||||
# Diagnostic continuation never grants authority to reuse an unsafe
|
||||
# prefix or a changed source copy. Timeout/interruption also stop.
|
||||
@@ -392,7 +408,9 @@ def main(argv=None):
|
||||
parser.add_argument('--compat', type=Path, required=True, help='Idle disposable cloned Tools prefix under /tmp')
|
||||
parser.add_argument('--steam', type=Path, default=Path.home()/'.local/share/Steam')
|
||||
parser.add_argument('--timeout', type=int, default=300, help='30..1800 seconds per addon')
|
||||
parser.add_argument('--silent-workbench', action='store_true', help='Opt-in documented -wbSilent experiment; packing compatibility still requires native evidence')
|
||||
lifecycle = parser.add_mutually_exclusive_group()
|
||||
lifecycle.add_argument('--silent-workbench', action='store_true', help='Opt-in documented -wbSilent experiment; packing compatibility still requires native evidence')
|
||||
lifecycle.add_argument('--exit-after-init', action='store_true', help='Opt-in documented -exitAfterInit experiment; natural exit and all native error gates remain mandatory')
|
||||
parser.add_argument('--continue-on-failure', action='store_true', help='Diagnostic only: continue completed, safely cleaned addon attempts after validation failures; any failure keeps overall exit nonzero and unqualified')
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user