from pathlib import Path import os,sys,json,shutil,subprocess,time,signal ROOT=Path('/home/jakub/devel/escapistsrereintroduced');sys.path.insert(0,str(ROOT/'tools')) from external_addons import policy,prepare_profile from source_manifest import addon_manifest from dedicated_native import PROBE base=Path('/tmp/erri-site-counts-native');base.mkdir(exist_ok=True) run=base/sys.argv[1];run.mkdir();source=run/'source';source.mkdir() for rel in addon_manifest(ROOT): dest=source/Path(rel).relative_to('addons/core');dest.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(ROOT/rel,dest) shutil.copy2('/tmp/erri-takeover-pair-source32/resourceDatabase.rdb',source/'resourceDatabase.rdb') if run.name.endswith('-unfixed'): (source/'Scripts/Game/ERR/00_Core/ERR_ItemStationLifecycle.c').unlink() shutil.copy2('/tmp/err-site-counts-diag.c',source/'Scripts/Game/ERR/00_Core/ERR_ZErrorsProbe.c') addons=run/'addons';addons.mkdir();steam=Path.home()/'.local/share/Steam' # Private compile-only profile: use the currently installed dependency projects. import re installed=steam/'steamapps/compatdata/1874880/pfx/drive_c/users/steamuser/Documents/My Games/ArmaReforger/addons' required={'595F2BF2F44836FB','629B2BA37EFFD577','5E524E4FEECCA92B','65930CB4CD0237B2'} projects={} for project in installed.glob('*/addon.gproj'): text=project.read_text();match=re.search(r'GUID "([A-Fa-f0-9]+)"',text) if match: projects[match[1].upper()]=(project,re.findall(r'"([A-Fa-f0-9]{16})"',text.split('Dependencies',1)[-1]) if 'Dependencies' in text else []) pending=list(required);seen=set() while pending: guid=pending.pop() if guid in seen or guid=='58D0FB3206B6F859':continue seen.add(guid);project,deps=projects[guid] (addons/('Dependency_'+guid)).symlink_to(project.parent,target_is_directory=True) pending.extend(deps) (addons/'Nogova').symlink_to('/home/jakub/devel/gabreta/addons/NogovaReforger',target_is_directory=True) (addons/'ERR_Core').symlink_to(source,target_is_directory=True) profile=run/'profile/profile';profile.mkdir(parents=True) (run/'network.py').write_text(PROBE) runtime=Path('/tmp/erri-takeover-dedicated-runtime') engine=['/tmp/runtime/ArmaReforgerServer','-server','{469880DFE1B48F95}Missions/Nogova_TerrainTest.conf','-addonsDir',str(addons),'-addons','2528466DE220D91C,70C981A53E02B64F','-profile',str(run/'profile'),'-noBackend','-noSound','-bindIP','127.0.0.1','-bindPort','2001','-maxFPS','30','-logconsole','-noSplash','-noThrow','-disableCrashReporter'] cmd=['bwrap','--unshare-net','--unshare-pid','--unshare-ipc','--unshare-uts','--die-with-parent','--cap-drop','ALL','--ro-bind','/','/','--tmpfs','/tmp','--ro-bind',str(runtime),'/tmp/runtime','--bind',str(run),str(run),'--proc','/proc','--dev','/dev','--chdir','/tmp/runtime','python',str(run/'network.py'),os.readlink('/proc/self/ns/net')]+engine with (run/'stdout.log').open('w') as log: p=subprocess.Popen(cmd,stdout=log,stderr=subprocess.STDOUT,start_new_session=True) reason='timeout';start=time.monotonic() try: while time.monotonic()-start<360: files=sorted((run/'profile/logs').glob('logs_*/console.log'));text=files[-1].read_text(errors='replace') if files else '' if 'ERR SITES COMPLETE' in text:reason='complete';break if "Can't compile" in text:reason='compile-failed';break if p.poll() is not None:reason='exit';break time.sleep(.3) finally: if p.poll() is None: os.killpg(p.pid,signal.SIGTERM) try:p.wait(timeout=8) except subprocess.TimeoutExpired:os.killpg(p.pid,signal.SIGKILL);p.wait() (run/'result.json').write_text(json.dumps({'reason':reason,'exit':p.returncode}));print(reason) print('\n'.join(line for line in text.splitlines() if 'ERR SITES' in line or 'SCRIPT (E)' in line))