@bscotch/stitch
Version:
Stitch: The GameMaker Studio 2 Asset Pipeline Development Kit.
114 lines • 4.86 kB
JavaScript
import { Pathy } from '@bscotch/pathy';
import { formatTimestamp } from '@bscotch/utility';
import { spawn } from 'child_process';
import { GameMakerEngineStatic } from './GameMakerEngine.static.js';
export async function runGameMakerCommand(engine, project, worker, command, executionOptions, otherOptions) {
const childEnv = { ...process.env };
if (childEnv.PATH && engine.currentOs == 'windows') {
//This is because node's the ENV contain the PATH variable that conflicts with MSBuild
//See https://github.com/dotnet/msbuild/issues/5726
delete childEnv.PATH;
}
let args = Object.entries(executionOptions)
.map((option) => {
const [key, value] = option;
if (typeof value === 'undefined') {
return;
}
let arg = `--${key}`;
if (typeof value !== 'boolean') {
arg += `=${value}`;
}
return arg;
})
.filter((x) => x);
const cmd = (await engine.cliPath()).absolute;
args = [...args, `--project=${project.yypPathAbsolute}`, worker, command];
console.log('🚀 Running GameMaker CLI command:');
console.log(cmd, ...args);
const child = spawn(cmd, args, {
env: childEnv,
stdio: 'pipe',
});
// Set up writeable file streams
const timestamp = formatTimestamp(new Date(), {
secondsPrecision: 0,
timeSeparator: '',
});
const logDir = await GameMakerEngineStatic.logDir(project, otherOptions);
const logFilePathy = (fileName) => {
const logFileName = `${otherOptions?.excludeLogFileTimestamps ? '' : `${timestamp}.`}${fileName}.txt`;
const logFilePath = new Pathy(logDir.join(logFileName));
return logFilePath;
};
const results = {};
for (const pipe of ['stdout', 'stderr']) {
// Create a writeable filestream
child[pipe].on('data', (data) => {
const dataString = data.toString();
results[pipe] += dataString;
console[pipe === 'stderr' ? 'error' : 'log'](dataString);
});
}
return new Promise((resolve) => {
child.on('exit', async () => {
// The text "Igor complete." appears
// after the compile logs (if compile
// was successful) AND after the run
// (if the run exited normally).
const successMessage = 'Igor complete.';
const logParts = results.stdout.split(successMessage);
results.compileSucceeded = logParts.length > 1;
const wasRunnable = command === 'Run' && results.compileSucceeded;
const containedTwoIgorCompletes = logParts.length === 3;
results.runnerSucceeded = wasRunnable
? containedTwoIgorCompletes
: undefined;
// Add compiler & runner logs
for (const [index, source] of ['compiler', 'runner'].entries()) {
let content = logParts[index];
if (!content) {
continue;
}
const needsSuccessMessage = (index === 0 && results.compileSucceeded) ||
(index === 1 && results.runnerSucceeded);
if (needsSuccessMessage) {
content += successMessage;
}
const logName = `${source}Logs`;
results[logName] = content;
const logFileKey = `${source}LogsPath`;
const logFilePath = logFilePathy(source);
await logFilePath.write(content);
results[logFileKey] = logFilePath.absolute;
}
resolve(results);
});
});
}
export async function runBuildCommand(project, options) {
const target = options?.targetPlatform || 'windows';
const command = options?.compile
? target === 'windows'
? 'PackageZip'
: 'Package'
: 'Run';
const outputDir = new Pathy(options?.outDir || project.yypDirAbsolute);
const tempDir = new Pathy(project.yypDirAbsolute).join('tmp');
const results = await this.execute(project, target, command, {
user: (await this.userDirectory()).absolute,
runtimePath: (await this.runtimeDirectory()).absolute,
runtime: options?.yyc ? 'YYC' : 'VM',
config: options?.config,
verbose: true,
ignorecache: true,
cache: tempDir.join('igor/cache').absolute,
temp: tempDir.join('igor/temp').absolute,
// For some reason the filename has to be there
// but only the directory is used...
of: tempDir.join(`igor/out/${project.name}.win`).absolute,
tf: outputDir.join(`${project.name}.${GameMakerEngineStatic.artifactExtension(target)}`).absolute,
}, options);
return results;
}
//# sourceMappingURL=GameMakerEngine.run.js.map