feat(rtos): 首次发布手机真机调试桥与S2探针

这个提交包含在:
sydxky 于 2026-11-14 13:25:37 +08:00 提交
当前提交 2f0f4b9702
59 个文件已更改
+4303

没有与搜索条件相匹配的文件

+98
查看文件
@@ -0,0 +1,98 @@
"""Verify ui.py against both native Glyphix emulator profiles (not a physical S2).
Build deviceprobe QuickApps first. Supply a compatible vendor global/launcher
image using --seed (or initialize the probe image). Never attaches to an
existing Inspector or terminates another user's emulator.
"""
import argparse
import hashlib
import json
from pathlib import Path
import shutil
import socket
import subprocess
import sys
import time
PROJECT = Path(__file__).resolve().parents[1]
ROOT = PROJECT.parent
sys.path.insert(0, str(PROJECT))
from ui import Inspector
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--output', required=True, type=Path)
parser.add_argument('--seed', type=Path, default=ROOT / 'com.sydxky.rtos.deviceprobe/.glyphix-work/image/generic-watch-466x466',
help='Initialized vendor image containing global/, global.pkg and apps/emulator.launcher.pkg')
args = parser.parse_args()
output = args.output.resolve()
output.mkdir(parents=True, exist_ok=True)
results = []
for shape, device in [('round', '466x466'), ('rect', '390x450')]:
with socket.socket() as sock:
if sock.connect_ex(('127.0.0.1', 14201)) == 0:
raise RuntimeError('Inspector port in use; will not attach to another runtime')
folder = output / shape
image = folder / 'image'
image.mkdir(parents=True, exist_ok=True)
seed = args.seed.resolve()
shutil.copytree(seed / 'global', image / 'global', dirs_exist_ok=True)
shutil.copy2(seed / 'global.pkg', image / 'global.pkg')
(image / 'apps').mkdir(exist_ok=True)
shutil.copy2(seed / 'apps/emulator.launcher.pkg', image / 'apps/emulator.launcher.pkg')
name = 'com.sydxky.rtos.deviceprobe'
package = ROOT / name / '.glyphix-work/dist' / ('generic-watch-' + device + '-quickapp') / name / 'bundle.pkg'
shutil.copy2(package, image / 'apps' / (name + '.pkg'))
(image / 'pkgs.db').write_text(json.dumps({'apps': {p: {'uri': 'pkg://' + p} for p in (name, 'emulator.launcher')}, 'dials': {}}), encoding='utf-8')
command = [str(ROOT / 'temp/glyphix-v0.7.2-windows-x64/bin/glyphix-emu.exe'), '--config', 'pkgs.db', '--target', name, '--inspector']
command += ['--width', '624', '--height', '624', '--dpi', '326', '--font-size', '32', '--round', '--surface', 'surface/surface-466x466.json'] if shape == 'round' else ['--width', '390', '--height', '450', '--dpi', '321', '--font-size', '29']
command += ['--memory-profile', '8192', '--font-map', 'font-faces', '--font-family', 'sans-serif']
client = Inspector('http://127.0.0.1:14201')
item = {'profile': shape, 'evidence_scope': 'native_emulator_not_S2', 'package_sha256': hashlib.sha256(package.read_bytes()).hexdigest(), 'passed': False}
results.append(item)
with open(folder / 'stdout.log', 'w', encoding='utf-8') as out, open(folder / 'stderr.log', 'w', encoding='utf-8') as err:
proc = subprocess.Popen(command, cwd=image, stdin=subprocess.PIPE, stdout=out, stderr=err, creationflags=subprocess.CREATE_NO_WINDOW)
try:
for _ in range(70):
if proc.poll() is not None:
raise RuntimeError('Emulator exited before Inspector startup')
try:
client.request('/logs')
break
except OSError:
time.sleep(.3)
else:
raise TimeoutError('Inspector did not start')
time.sleep(1)
item['before'] = client.screenshot(folder / 'before.png')
item['initial_visible'] = client.exists(('text', '点击次数:0'))
client.click(('text', '点击验证'))
item['after_visible'] = client.exists(('text', '点击次数:1'))
item['after'] = client.screenshot(folder / 'after.png')
plan = json.loads((PROJECT / 'examples/probe-inspector.json').read_text(encoding='utf-8'))
plan['steps'][0]['value'] = '点击次数:1'
plan['steps'][2]['value'] = '点击次数:2'
planfile = folder / 'plan.json'
planfile.write_text(json.dumps(plan, ensure_ascii=False), encoding='utf-8')
run = subprocess.run([sys.executable, str(PROJECT / 'ui.py'), '--target', 'inspector', '--inspector', client.base, 'run', str(planfile), '--output', str(folder / 'plan-results')], capture_output=True, timeout=90)
item['plan_exit'] = run.returncode
item['passed'] = item['initial_visible'] and item['after_visible'] and run.returncode == 0
if run.returncode:
raise RuntimeError(run.stderr.decode('utf-8', 'replace') or 'UI plan failed')
except Exception as error:
item['error'] = type(error).__name__
raise
finally:
if proc.poll() is None:
proc.terminate()
proc.wait(timeout=10)
proc.stdin.close()
(output / 'results.json').write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding='utf-8')
print(json.dumps(item, ensure_ascii=True), flush=True)
time.sleep(2)
return 0 if all(item['passed'] for item in results) else 1
if __name__ == '__main__':
sys.exit(main())