first cycle lab release

This commit is contained in:
2026-10-04 00:30:09 +07:00
parent 85f6897365
commit d134daafd8
92 changed files with 5623 additions and 9 deletions
+82
View File
@@ -0,0 +1,82 @@
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import crypto from 'node:crypto';
import { fileURLToPath } from 'node:url';
import { runtime } from '../../platform/runtime.mjs';
const repository = fileURLToPath(new URL('../../', import.meta.url));
const sha = file => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
export function seal(release) {
const manifestFile = path.join(release, 'manifest.json');
const manifest = JSON.parse(fs.readFileSync(manifestFile));
for (const entry of manifest.release_files) entry.sha256 = sha(path.join(release, entry.path));
fs.writeFileSync(manifestFile, JSON.stringify(manifest, null, 2) + '\n');
const files = [...manifest.release_files.map(entry => entry.path), 'manifest.json'].sort();
fs.writeFileSync(path.join(release, 'SHA256SUMS'), files.map(file => `${sha(path.join(release, file))} ${file}\n`).join(''));
}
export function fixture(t) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mcpack-runtime-'));
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
fs.mkdirSync(path.join(root, 'platform'));
fs.copyFileSync(path.join(repository, 'platform/compatibility.json'), path.join(root, 'platform/compatibility.json'));
fs.writeFileSync(path.join(root, 'package.json'), '{"type":"module"}');
fs.mkdirSync(path.join(root, '.tools'));
// Build a minimal sealed release so tests work in a clean clone without dist.
const release = path.join(root, 'release');
fs.mkdirSync(path.join(release, 'server/config'), { recursive: true });
fs.writeFileSync(path.join(release, 'fixture.mrpack'), 'runtime fixture payload');
fs.writeFileSync(path.join(release, 'server/compose.yaml'), 'services: {}\n');
fs.copyFileSync(path.join(repository, 'server/.env.example'), path.join(release, 'server/.env.example'));
const executable = path.join(root, '.tools/docker-compose');
fs.writeFileSync(executable, `#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
const args=process.argv.slice(2),env=process.env;
const m=JSON.parse(fs.readFileSync(path.join(env.MC_RELEASE_DIR,'manifest.json')));
const stateFile=${JSON.stringify(path.join(root, '.tools/docker-state.json'))};
const state=fs.existsSync(stateFile)?JSON.parse(fs.readFileSync(stateFile)):{present:false,running:false};
if(args.includes('config')){
const wrong=fs.existsSync(${JSON.stringify(path.join(root, '.tools/wrong-contract'))});
console.log(JSON.stringify({services:{minecraft:{image:m.server.image,environment:{TYPE:'MODRINTH',ONLINE_MODE:wrong?'true':'false',ENFORCE_SECURE_PROFILE:'false',MODRINTH_MODPACK:'/modpacks/'+m.artifact},volumes:[{type:'bind',source:path.join(env.MC_ROOT,'runtime'),target:'/data'},{type:'bind',source:env.MC_RELEASE_DIR,target:'/modpacks',read_only:true},{type:'bind',source:path.join(env.MC_RELEASE_DIR,'server/config'),target:'/config',read_only:true}]}}}));
}else if(args.includes('ps')){
console.log(JSON.stringify(state.present||fs.existsSync(${JSON.stringify(path.join(root, '.tools/existing-project'))})?[{ID:'a'.repeat(64)}]:[]));
}else{
fs.writeFileSync(${JSON.stringify(path.join(root, '.tools/invocation.json'))},JSON.stringify({args,uid:env.MC_UID,gid:env.MC_GID,bind:env.MC_BIND_ADDRESS,root:env.MC_ROOT,release:env.MC_RELEASE_DIR}));
const command=args[6];
const eventsFile=${JSON.stringify(path.join(root, '.tools/events.json'))};
const events=fs.existsSync(eventsFile)?JSON.parse(fs.readFileSync(eventsFile)):[];
events.push({command,locked:fs.existsSync(path.join(env.MC_ROOT,'.mcpack-runtime.lock'))});
fs.writeFileSync(eventsFile,JSON.stringify(events));
if(command==='up'&&fs.existsSync(${JSON.stringify(path.join(root, '.tools/fail-start'))}))process.exit(19);
if(command==='stop'&&fs.existsSync(${JSON.stringify(path.join(root, '.tools/fail-stop'))}))process.exit(18);
if(command==='up'||command==='start')Object.assign(state,{present:true,running:true});
if(command==='stop')state.running=false;
if(command==='down')Object.assign(state,{present:false,running:false});
fs.writeFileSync(stateFile,JSON.stringify(state));
}
`);
fs.chmodSync(executable, 0o755);
const docker = path.join(root, '.tools/docker');
fs.writeFileSync(docker, `#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
const stateFile=${JSON.stringify(path.join(root, '.tools/docker-state.json'))};
const state=fs.existsSync(stateFile)?JSON.parse(fs.readFileSync(stateFile)):{present:false,running:false};
const other=fs.existsSync(${JSON.stringify(path.join(root, '.tools/existing-project'))});
if(process.argv[2]==='exec'){console.log('Minecraft status fixture');process.exit(0);}
console.log(JSON.stringify([{Id:'a'.repeat(64),RestartCount:0,Mounts:[{Type:'bind',Destination:'/data',Source:other?'/another/runtime':path.join(process.env.MC_ROOT,'runtime')}],State:{Status:state.running?'running':'exited',Running:state.running,Restarting:false,Paused:false,Dead:false,StartedAt:'fixture-start',ExitCode:0,Health:{Status:'healthy'}}}]));
`);
fs.chmodSync(docker, 0o755);
const verified = JSON.parse(fs.readFileSync(path.join(root, 'platform/compatibility.json'))).verified[0];
fs.writeFileSync(path.join(release, 'manifest.json'), JSON.stringify({ schema_version: 1, artifact: 'fixture.mrpack', pack: { name: 'fixture', version: '1.0.0', minecraft: verified.minecraft, loader: { id: verified.loader, version: verified.loader_version } }, server: { image: verified.image, java_major: verified.java_major, compose_project: 'fixture-server' }, tools: { compose: { sha256: sha(executable) } }, release_files: ['fixture.mrpack', 'server/compose.yaml', 'server/.env.example'].map(file => ({ path: file })) }));
seal(release);
const host = path.join(root, 'host');
fs.mkdirSync(host);
fs.copyFileSync(path.join(repository, 'server/.env.example'), path.join(host, '.env'));
fs.writeFileSync(path.join(host, '.env'), fs.readFileSync(path.join(host, '.env'), 'utf8').replace('MC_EULA=FALSE', 'MC_EULA=TRUE'));
const env = { ...process.env, PATH: `${path.join(root, '.tools')}${path.delimiter}${process.env.PATH}`, MC_ROOT: host, MC_RELEASE_DIR: release, MC_PROJECT_NAME: 'fixture-server' };
return { root, host, release, env, run: args => runtime({ repository: root, args, env }) };
}