mirror of
https://github.com/smogon/sprites.git
synced 2026-08-25 11:17:41 -05:00
Add pnpm deploy: pipe the assets tar to DEPLOY_COMMAND from .env
The deploy tool grows a deploy subcommand that runs the build, packs the tar, and streams it to the command .env names. Packing now finalizes the archive; without the end-of-archive marker, strict stream readers (Python tarfile, hence smogonctl) die on truncation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ pnpm-debug.log
|
||||
.cache/
|
||||
.build/
|
||||
build.config
|
||||
.env
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "node tools/build/index.ts",
|
||||
"deploy": "node tools/deploy/index.ts deploy assets.deploy.js",
|
||||
"check": "tsc --build tsconfig-workspace.json"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import program from 'commander';
|
||||
import * as script from './script.ts';
|
||||
import nodePath from 'path';
|
||||
import {spawn, type ChildProcess} from 'child_process';
|
||||
|
||||
function collect(value : string, previous : string[]) {
|
||||
return previous.concat([value]);
|
||||
@@ -72,6 +73,54 @@ program
|
||||
await runAq(aq, tar ? 'tar' : link ? 'link' : 'copy', outputDir, verbose);
|
||||
});
|
||||
|
||||
function waitExit(child : ChildProcess) : Promise<number | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
child.on('error', reject);
|
||||
child.on('close', code => resolve(code));
|
||||
});
|
||||
}
|
||||
|
||||
program
|
||||
.command('deploy [scripts...]')
|
||||
.option('-v, --verbose', 'Verbose')
|
||||
.action(async (scripts : string[], {verbose}) => {
|
||||
try {
|
||||
process.loadEnvFile('.env');
|
||||
} catch {
|
||||
console.error(`missing .env; set DEPLOY_COMMAND="ssh smogon smogonctl assets upload"`);
|
||||
process.exit(1);
|
||||
}
|
||||
const command = process.env.DEPLOY_COMMAND;
|
||||
if (command === undefined) {
|
||||
console.error(`DEPLOY_COMMAND not set in .env`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const build = spawn('pnpm', ['build'], {stdio: ['ignore', 'inherit', 'inherit']});
|
||||
if (await waitExit(build) !== 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const aq = new script.ActionQueue;
|
||||
for (const file of scripts) {
|
||||
const scr = new script.Script(file, 'file');
|
||||
script.run(scr, nodePath.dirname(file), aq);
|
||||
}
|
||||
if (!aq.valid) {
|
||||
aq.print(verbose ? 'all' : 'errors');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const upload = spawn(command, {shell: true, stdio: ['pipe', 'inherit', 'inherit']});
|
||||
// If the command dies early we report its exit code; don't also crash
|
||||
// on the resulting EPIPE.
|
||||
upload.stdin!.on('error', () => {});
|
||||
aq.pack().pipe(upload.stdin!);
|
||||
if (await waitExit(upload) !== 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
if (process.argv.slice(2).length === 0) {
|
||||
|
||||
@@ -151,24 +151,35 @@ export class ActionQueue {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let t = tar.pack();
|
||||
for (const entry of this.log) {
|
||||
if (entry.type !== 'Op')
|
||||
continue;
|
||||
const op = entry.op;
|
||||
if (op.type === 'Copy'){
|
||||
t.entry({name: entry.dst}, fs.readFileSync(op.src));
|
||||
} else if (op.type === 'Write') {
|
||||
t.entry({name: entry.dst}, op.data);
|
||||
}
|
||||
}
|
||||
// In this case, I guess its a file rather than a dir.
|
||||
t.pipe(fs.createWriteStream(dir))
|
||||
return new Promise<void>(resolve => {
|
||||
t.on('close', () => resolve())
|
||||
const out = fs.createWriteStream(dir);
|
||||
this.pack().pipe(out);
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
out.on('error', reject);
|
||||
out.on('finish', () => resolve());
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pack() : NodeJS.ReadableStream {
|
||||
if (!this.valid)
|
||||
throw new Error(`Invalid ActionQueue`);
|
||||
let t = tar.pack();
|
||||
for (const entry of this.log) {
|
||||
if (entry.type !== 'Op')
|
||||
continue;
|
||||
const op = entry.op;
|
||||
if (op.type === 'Copy'){
|
||||
t.entry({name: entry.dst}, fs.readFileSync(op.src));
|
||||
} else if (op.type === 'Write') {
|
||||
t.entry({name: entry.dst}, op.data);
|
||||
}
|
||||
}
|
||||
// Without this the archive has no end-of-archive marker, and strict
|
||||
// readers (Python tarfile in stream mode) die on the truncation.
|
||||
t.finalize();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
export class Script extends vm.Script {
|
||||
|
||||
Reference in New Issue
Block a user