90 lines
4.8 KiB
Python
90 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
||
"""Живой DAP-проход: C-макрос → breakpoint → обе console без DSS-вывода."""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
from pathlib import Path
|
||
import subprocess
|
||
import sys
|
||
import tempfile
|
||
import time
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
sys.path.insert(0, str(ROOT/'toolchain'))
|
||
from run_vscode_dap_probe import receive, send, wait_response
|
||
from sdbg.server import rpc_call
|
||
|
||
|
||
def main():
|
||
provider = 'osx' if '--osx' in sys.argv else 'sdbg'
|
||
source = ROOT/'tests/sdbg/fixtures/logmacro.c'
|
||
with tempfile.TemporaryDirectory(prefix='sprinter-macro-live-') as temp:
|
||
exe = Path(temp)/'logmacro.exe'
|
||
build = subprocess.run([str(ROOT/'bin/sprinter-cc'), '-o', str(exe),
|
||
'--src-debug', str(source)], cwd=ROOT,
|
||
env=dict(os.environ, SPRINTER_PYTHON=sys.executable),
|
||
capture_output=True, text=True)
|
||
if build.returncode:
|
||
raise RuntimeError('Не собрано приложение с SDBG_LOG: '+build.stdout+build.stderr)
|
||
process = subprocess.Popen([sys.executable, str(ROOT/'toolchain/sdbg_dap.py')], cwd=ROOT,
|
||
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||
stderr=subprocess.PIPE)
|
||
buffer = b''
|
||
try:
|
||
send(process, 1, 'initialize')
|
||
_, buffer, _ = wait_response(process, buffer, 'initialize', 10)
|
||
send(process, 2, 'launch', {'build': str(exe.with_name('.sprinter-cc-logmacro')),
|
||
'debugger': provider, 'dssTimeout': 30})
|
||
launched, buffer, events = wait_response(process, buffer, 'launch', 80)
|
||
if not any(event.get('event') == 'initialized' for event in events):
|
||
event, buffer = receive(process, buffer, 5)
|
||
if event.get('event') != 'initialized':
|
||
raise RuntimeError('Нет DAP initialized: '+str(event))
|
||
send(process, 3, 'configurationDone')
|
||
_, buffer, _ = wait_response(process, buffer, 'configurationDone', 10)
|
||
send(process, 4, 'stackTrace')
|
||
frames, buffer, _ = wait_response(process, buffer, 'stackTrace', 10)
|
||
if not frames['body']['stackFrames'][0]['name'].startswith('main'):
|
||
raise RuntimeError('Перед стартом нет main: '+str(frames['body']['stackFrames']))
|
||
send(process, 5, 'continue')
|
||
_, buffer, events = wait_response(process, buffer, 'continue', 10)
|
||
outputs = [event for event in events if event.get('event') == 'output']
|
||
deadline = time.monotonic()+25
|
||
while not any('total=1\n' == event.get('body', {}).get('output') for event in outputs):
|
||
if time.monotonic() >= deadline:
|
||
raise RuntimeError('SDBG_LOG не пришёл в DAP Debug Console: '+str(outputs[-4:]))
|
||
event, buffer = receive(process, buffer, deadline-time.monotonic())
|
||
if event.get('event') == 'terminated':
|
||
raise RuntimeError('DAP завершился до авторского лога')
|
||
if event.get('event') == 'output': outputs.append(event)
|
||
socket = launched['body']['socket']
|
||
identity = rpc_call(socket, 'status')
|
||
tail = rpc_call(socket, 'mame_console_tail', {'count': 50}, timeout=6,
|
||
session_id=identity['session_id'],
|
||
build_id=identity['build_id'])
|
||
if not any('total=1' in line for line in tail['lines']):
|
||
raise RuntimeError('В debugger console MAME нет total=1: '+str(tail))
|
||
print(json.dumps({'event': 'macro_dual_console_verified',
|
||
'provider': provider, 'dap_output': 'total=1',
|
||
'mame_console': [line for line in tail['lines'] if 'total=1' in line],
|
||
'entry': launched['body']['entry']}, ensure_ascii=False), flush=True)
|
||
send(process, 6, 'disconnect')
|
||
wait_response(process, buffer, 'disconnect', 10)
|
||
finally:
|
||
if process.poll() is None: process.terminate()
|
||
try: _, stderr = process.communicate(timeout=8)
|
||
except subprocess.TimeoutExpired:
|
||
process.kill()
|
||
_, stderr = process.communicate()
|
||
if stderr:
|
||
print(stderr.decode(errors='replace')[-3000:], file=sys.stderr)
|
||
|
||
|
||
if __name__ == '__main__':
|
||
try: main()
|
||
except (RuntimeError, TimeoutError, OSError, KeyError, ValueError) as error:
|
||
print('macro-log-probe: '+str(error), file=sys.stderr)
|
||
sys.exit(1)
|