@quenty/nevermore-template-helpers
Version:
Helpers to generate Nevermore package and game templates
116 lines • 4.17 kB
JavaScript
import { execa } from 'execa';
import * as fs from 'fs/promises';
import * as os from 'os';
import * as path from 'path';
import { OutputHelper } from '@quenty/cli-output-helpers';
/**
* Manages a build directory lifecycle for rojo builds.
* Handles temp directory creation/cleanup and persistent build directories.
*/
export class BuildContext {
_targetdir;
_cleaned = false;
_trackedFiles = [];
constructor(dir) {
this._targetdir = dir;
}
/**
* Create and initialize a BuildContext. The directory is ready to use
* when this resolves.
*/
static async createAsync(options = {}) {
const prefix = options.prefix ?? 'build-';
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
return new BuildContext(dir);
}
/** Absolute path to the managed build directory. */
get buildDir() {
return this._targetdir;
}
/** Resolve a relative path within the build directory. */
resolvePath(relativePath) {
return path.join(this._targetdir, relativePath);
}
/**
* Run rojo build using this context's directory.
* Returns the full plugin output path when in plugin mode, undefined otherwise.
*/
async rojoBuildAsync(options) {
const { projectPath, output, plugin, pluginsFolder } = options;
if (output && plugin) {
throw new Error('rojoBuildAsync: specify either output or plugin, not both');
}
if (!output && !plugin) {
throw new Error('rojoBuildAsync: must specify either output or plugin');
}
if (plugin && !pluginsFolder) {
throw new Error('rojoBuildAsync: plugin requires pluginsFolder for cleanup tracking');
}
const args = ['build', projectPath];
// On Linux, rojo's --plugin flag is not supported. Build to a temp
// file with -o and copy to the plugins folder ourselves.
const usePluginFallback = plugin && process.platform === 'linux';
if (output) {
args.push('-o', output);
}
else if (usePluginFallback) {
const tempOutput = path.join(this._targetdir, plugin);
args.push('-o', tempOutput);
}
else if (plugin) {
args.push('--plugin', plugin);
}
await execa('rojo', args);
if (plugin && pluginsFolder) {
const pluginPath = path.join(pluginsFolder, plugin);
if (usePluginFallback) {
const tempOutput = path.join(this._targetdir, plugin);
await fs.mkdir(pluginsFolder, { recursive: true });
await fs.copyFile(tempOutput, pluginPath);
}
this._trackedFiles.push(pluginPath);
return pluginPath;
}
return undefined;
}
/**
* Execute a Lune transform script with the given arguments.
*/
async executeLuneTransformScriptAsync(scriptPath, ...args) {
await execa('lune', ['run', scriptPath, ...args]);
}
/**
* Write a file into the build directory.
* @returns Absolute path to the written file.
*/
async writeFileAsync(relativePath, content) {
const fullPath = path.join(this._targetdir, relativePath);
await fs.mkdir(path.dirname(fullPath), { recursive: true });
await fs.writeFile(fullPath, content, 'utf-8');
return fullPath;
}
/**
* Clean up the build directory and tracked files. Idempotent — safe to call multiple times.
*/
async cleanupAsync() {
if (this._cleaned)
return;
this._cleaned = true;
for (const filePath of this._trackedFiles) {
try {
await fs.unlink(filePath);
}
catch {
// best effort — file may already be gone
}
}
try {
OutputHelper.verbose(`[Build] Cleaning up build directory: ${this._targetdir}`);
await fs.rm(this._targetdir, { recursive: true, force: true });
}
catch {
// best effort
}
}
}
//# sourceMappingURL=build-context.js.map