feat: 开源蟹蟹输入RTOS适配改版并采用MIT商用许可
这个提交包含在:
当前提交
29374caffd
116 个文件已更改
+351523
没有与搜索条件相匹配的文件
@@ -0,0 +1,119 @@
|
||||
"""Run real Glyphix native UI tests through its local Inspector (Python stdlib).
|
||||
|
||||
Build the input app and the minimal test fixture first; see the root README. No production
|
||||
credentials, paid requests, Windows input injection or third party modules.
|
||||
"""
|
||||
import argparse
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import time
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
APPS = ['inputmethod', 'imefixture']
|
||||
PROFILES = ['round', 'rect', 'round-quickapp', 'rect-quickapp']
|
||||
BASE = 'http://127.0.0.1:14201'
|
||||
|
||||
|
||||
def sha256(path):
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest().upper()
|
||||
|
||||
|
||||
def request(path, params=None, method='GET'):
|
||||
url = BASE + path + ('?' + urllib.parse.urlencode(params) if params else '')
|
||||
with urllib.request.urlopen(urllib.request.Request(url, method=method), timeout=15) as response:
|
||||
data = response.read()
|
||||
try:
|
||||
return json.loads(data)
|
||||
except (ValueError, UnicodeDecodeError):
|
||||
return data.decode('utf-8', errors='replace')
|
||||
|
||||
|
||||
def evaluate(script):
|
||||
return request('/fn/eval', {'lang': 'js', 'script': script}, 'POST')
|
||||
|
||||
|
||||
def resume():
|
||||
request('/control', {'pause': 'false'}, 'POST')
|
||||
|
||||
|
||||
def snapshot(name, output):
|
||||
try:
|
||||
tree = request('/snapshot.json')
|
||||
(output / (name + '.tree.json')).write_text(json.dumps(tree, ensure_ascii=False), encoding='utf-8')
|
||||
with urllib.request.urlopen(BASE + '/snapshot/' + tree['frames'][-1]['snapshot'], timeout=15) as response:
|
||||
(output / (name + '.png')).write_bytes(response.read())
|
||||
finally:
|
||||
# Capturing Inspector history pauses the runtime, including gestures/timers.
|
||||
resume()
|
||||
|
||||
|
||||
def prepare(profile, work):
|
||||
device = 'generic-watch-' + ('466x466' if profile.startswith('round') else '390x450')
|
||||
image = work / profile / 'image'
|
||||
image.mkdir(parents=True, exist_ok=True)
|
||||
seed = ROOT / 'com.sydxky.rtos.imefixture/.glyphix-work/image/generic-watch-466x466'
|
||||
if not (seed / 'global.pkg').is_file() or not (seed / 'apps/emulator.launcher.pkg').is_file():
|
||||
raise RuntimeError('Missing global assets/launcher: launch the round fixture emulator once with gx emulate first.')
|
||||
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')
|
||||
artifacts = {}
|
||||
for app in APPS:
|
||||
package = 'com.sydxky.rtos.' + app
|
||||
build = ROOT / package / '.glyphix-work'
|
||||
if profile.endswith('-quickapp'):
|
||||
source = build / 'dist' / (device + '-quickapp') / package / 'bundle.pkg'
|
||||
else:
|
||||
source = build / 'image' / device / 'apps' / (package + '.pkg')
|
||||
shutil.copy2(source, image / 'apps' / (package + '.pkg'))
|
||||
artifacts[app] = {'path': str(source), 'sha256': sha256(source), 'ux_sha256': sha256(ROOT / package / 'src/main/index.ux')}
|
||||
packages = ['com.sydxky.rtos.' + app for app in APPS] + ['emulator.launcher']
|
||||
(image / 'pkgs.db').write_text(json.dumps({'apps': {p: {'uri': 'pkg://' + p} for p in packages}, 'dials': {}}), encoding='utf-8')
|
||||
return image, artifacts
|
||||
|
||||
|
||||
def start(profile, work, first_app):
|
||||
# Do not attach to or terminate another user's running emulator.
|
||||
with socket.socket() as probe:
|
||||
if probe.connect_ex(('127.0.0.1', 14201)) == 0:
|
||||
raise RuntimeError('Inspector port 14201 is already in use; close the other emulator first.')
|
||||
image, artifacts = prepare(profile, work)
|
||||
executable = ROOT / 'temp/glyphix-v0.7.2-windows-x64/bin/glyphix-emu.exe'
|
||||
args = [str(executable), '--config', 'pkgs.db', '--target', 'com.sydxky.rtos.' + first_app, '--inspector']
|
||||
if profile.startswith('round'):
|
||||
args += ['--width', '624', '--height', '624', '--dpi', '326', '--font-size', '32', '--round', '--surface', 'surface/surface-466x466.json']
|
||||
else:
|
||||
args += ['--width', '390', '--height', '450', '--dpi', '321', '--font-size', '29']
|
||||
args += ['--memory-profile', '8192', '--font-map', 'font-faces', '--font-family', 'sans-serif']
|
||||
stdout = open(work / profile / 'stdout.log', 'w', encoding='utf-8')
|
||||
stderr = open(work / profile / 'stderr.log', 'w', encoding='utf-8')
|
||||
# Keep stdin open: the vendor emulator exits when its console input sees EOF.
|
||||
process = subprocess.Popen(args, cwd=image, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
try:
|
||||
deadline = time.time() + 20
|
||||
while time.time() < deadline:
|
||||
if process.poll() is not None:
|
||||
raise RuntimeError('Emulator exited before Inspector was ready; inspect ' + str(work / profile / 'stderr.log'))
|
||||
try:
|
||||
request('/logs')
|
||||
time.sleep(1)
|
||||
return process, artifacts
|
||||
except OSError:
|
||||
time.sleep(0.25)
|
||||
raise RuntimeError('Inspector startup timed out')
|
||||
except BaseException:
|
||||
if process.poll() is None:
|
||||
process.terminate()
|
||||
process.wait(timeout=10)
|
||||
raise
|
||||
finally:
|
||||
stdout.close()
|
||||
stderr.close()
|
||||
在新工单中引用
屏蔽一个用户