site 1.7.0: builder covers every mod in any combination
Stage 1 (arnoldasr's code) still ships as checked data; stage 2 (our mods) runs the patcher's own Python in the browser via self-hosted Pyodide 0.26.4, byte-identical to the patcher. Added cuenames, played, endwarn, quicksearch, usbautoload; phasemeter REVERSE and WAVEFORM modes included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2f9c182279
commit
f955e37927
19 files changed
+566
-93
No files matched your search
+33
-29
@@ -139,6 +139,25 @@ def apply_ops(app, stock, ops, hk, size):
|
||||
return bytes(out)
|
||||
|
||||
|
||||
MODS_ALL = ('extended_bpm', 'phasemeter', 'advanced_waveforms', 'beatjump', 'cuecolours', 'hotcuekeys',
|
||||
'ledsaver', 'keynotation', 'usbautoload', 'quicksearch', 'cuenames', 'played', 'endwarn', 'credit')
|
||||
|
||||
|
||||
def python_bundle(repo):
|
||||
"""Our patch code for the browser: mods/patch_cdj900nxs.py and every module
|
||||
in mods/cdj900nxs (not arnoldasr's checkout, not the tests)."""
|
||||
files = {'mods/patch_cdj900nxs.py': os.path.join(repo, 'mods', 'patch_cdj900nxs.py')}
|
||||
d = os.path.join(repo, 'mods', 'cdj900nxs')
|
||||
for n in sorted(os.listdir(d)):
|
||||
if n.endswith('.py'):
|
||||
files['mods/cdj900nxs/' + n] = os.path.join(d, n)
|
||||
out = {}
|
||||
for rel, path in files.items():
|
||||
with open(path, encoding='utf-8') as f:
|
||||
out[rel] = f.read()
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--repo', default=os.path.join(os.path.dirname(WEB), 'CDJ900NXSVirtual'))
|
||||
@@ -188,7 +207,7 @@ def main():
|
||||
upstream, up_apps = {}, {(): stock}
|
||||
for k in range(1, len(p.UPSTREAM) + 1):
|
||||
for up in itertools.combinations(p.UPSTREAM, k):
|
||||
app = p.patch(stock, list(up), public=True)
|
||||
app = p.patch_upstream(stock, list(up))
|
||||
# the asset blob itself (code of ours after it, advanced_waveforms'
|
||||
# fix, goes as data)
|
||||
blob_len = min(len(ASSETS(stock)[0]), len(app) - (p.DATA_BASE - BASE))
|
||||
@@ -201,30 +220,18 @@ def main():
|
||||
upstream[','.join(up)] = {'size': len(app), 'ops': encode(ops)}
|
||||
up_apps[up] = app
|
||||
print('%-40s %3d operations' % (','.join(up), len(ops)))
|
||||
for combo in combos:
|
||||
final = p.patch(stock, list(combo), public=True)
|
||||
ops = ops_for(stock, final, boxes if 'hotcuekeys' in combo else [])
|
||||
if apply_ops(stock, stock, ops, hk, len(final)) != final:
|
||||
raise SystemExit('%s: the operations do not give the patcher\'s result' % ','.join(combo))
|
||||
variants[','.join(combo)] = {'size': len(final), 'ops': encode(ops)}
|
||||
print('%-40s %3d operations' % (','.join(combo), len(ops)))
|
||||
|
||||
# the browser applies ours on top of whatever of arnoldasr's was applied:
|
||||
# check every pair, and note the result's SHA-256 for the browser to check
|
||||
expect = {}
|
||||
for k in range(0, len(p.UPSTREAM) + 1):
|
||||
for up in itertools.combinations(p.UPSTREAM, k):
|
||||
base = up_apps[up]
|
||||
if up:
|
||||
expect[','.join(up)] = sha(base)
|
||||
for combo in combos:
|
||||
final = p.patch(stock, list(up) + list(combo), public=True)
|
||||
alone = p.patch(stock, list(combo), public=True)
|
||||
ops = ops_for(stock, alone, boxes if 'hotcuekeys' in combo else [])
|
||||
if apply_ops(base, stock, ops, hk, len(alone)) != final:
|
||||
raise SystemExit('%s + %s: differs from the patcher' % (','.join(up), ','.join(combo)))
|
||||
expect[','.join(list(up) + list(combo))] = sha(final)
|
||||
print('checked: every combination of arnoldasr and ours gives the patcher bytes')
|
||||
# stage 1 only: the browser checks its result against these; stage 2 (ours)
|
||||
# runs there as Python, the patcher's own code (builder/py/bundle.json)
|
||||
expect = {','.join(up): sha(app) for up, app in up_apps.items() if up}
|
||||
bundle = python_bundle(args.repo)
|
||||
with open(os.path.join(WEB, 'builder', 'py', 'bundle.json'), 'w', encoding='utf-8', newline='\n') as f:
|
||||
json.dump(bundle, f, separators=(',', ':'))
|
||||
# stage 2 as the browser runs it: patch_ours on stage 1's application
|
||||
for names in (['credit'], list(MODS_ALL), ['phasemeter'], ['advanced_waveforms', 'cuecolours', 'cuenames']):
|
||||
up = tuple(n for n in p.UPSTREAM if n in names)
|
||||
if p.patch_ours(up_apps[up], stock, p.check_names(names)) != p.patch(stock, names):
|
||||
raise SystemExit('%s: stage 1 + stage 2 differs from the patcher' % ','.join(names))
|
||||
print('checked: stage 1 data + stage 2 Python give the patcher bytes; %d Python files' % len(bundle))
|
||||
|
||||
glyphs = {c: rows for c, rows in hk.GLYPHS.items()}
|
||||
data = {
|
||||
@@ -233,10 +240,7 @@ def main():
|
||||
'appSize': p.APP_SIZE,
|
||||
'dataBase': p.DATA_BASE,
|
||||
'upstream': upstream,
|
||||
'ours': variants,
|
||||
'expect': expect,
|
||||
'box': {'resTable': hk.RES_TABLE, 'width': w, 'height': h, 'glyphs': glyphs,
|
||||
'gap': 3, 'space': 5},
|
||||
'chunks': chunks,
|
||||
}
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(WEB), 'CDJ900NXSPatcher'))
|
||||
@@ -255,7 +259,7 @@ def main():
|
||||
f.write('window.BUILDER_DATA = ')
|
||||
json.dump(data, f, separators=(',', ':'))
|
||||
f.write(';\n')
|
||||
print('wrote %s (%d bytes, %d + %d variants, %d chunks)' % (out, os.path.getsize(out), len(upstream), len(variants), len(chunks)))
|
||||
print('wrote %s (%d bytes, %d variants, %d chunks)' % (out, os.path.getsize(out), len(upstream), len(chunks)))
|
||||
write_versions(p)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user