alwaysai
Version:
The alwaysAI command-line interface (CLI)
148 lines (134 loc) • 3.88 kB
text/typescript
import {
readdir as fsReaddir,
access as fsAccess,
readFile as fsReadFile,
writeFile as fsWriteFile,
rename as fsRename
} from 'fs';
import { readdir as fspReaddir } from 'fs/promises';
import { promisify } from 'util';
import { isAbsolute, resolve, join } from 'path';
import * as tarJs from 'tar';
import * as mkdirpJs from 'mkdirp';
import { rimraf as rimrafJs } from 'rimraf';
import { Spawner, Cmd } from './types';
import { SpawnerBase } from './spawner-base';
import { GnuSpawner } from './gnu-spawner';
import pump = require('pump');
import { Readable } from 'node:stream';
export function JsSpawner(context: { path?: string } = {}): Spawner {
const gnuSpawner = GnuSpawner({ resolvePath, ...SpawnerBase(translate) });
return {
...gnuSpawner,
resolvePath,
readdir,
async readFile(path) {
return await promisify(fsReadFile)(resolvePath(path), {
encoding: 'utf8'
});
},
async writeFile(path, data) {
await promisify(fsWriteFile)(resolvePath(path), data, {
encoding: 'utf8'
});
},
mkdirp,
rimraf,
tar,
walk,
async rename(oldPath, newPath) {
await promisify(fsRename)(resolvePath(oldPath), resolvePath(newPath));
},
async untar(input, cwd) {
await new Promise<void>((resolve, reject) => {
const writable = tarJs.extract({ cwd: resolvePath(cwd) });
pump(input, writable, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
},
exists
};
function resolvePath(...paths: (string | undefined)[]) {
return resolve(context.path ?? '', ...paths.map((path) => path ?? ''));
}
function translate(cmd: Cmd) {
if (cmd.superuser) {
throw new Error(
`${JsSpawner.name} does not support cmd option "superuser"`
);
}
const translated: Cmd = {
...cmd
};
if (cmd.cwd) {
translated.cwd = resolvePath(cmd.cwd);
}
return translated;
}
async function mkdirp(path = '') {
await mkdirpJs(resolvePath(path));
}
async function rimraf(path = '') {
await rimrafJs(resolvePath(path));
}
function readdir(path = '') {
return promisify(fsReaddir)(resolvePath(path));
}
async function tar(...paths: string[]) {
for (const path in paths) {
if (isAbsolute(path)) {
throw new Error('Paths passed to spawner.tar must not be absolute');
}
}
const packageStream = tarJs.create(
{ sync: true, gzip: true, cwd: resolvePath() },
paths
) as unknown as Readable;
// ^^ The @types for tar.create are not correct
return packageStream;
}
async function exists(path: string) {
if (!path) {
throw new Error('path is mandatory');
}
try {
await promisify(fsAccess)(resolvePath(path));
return true;
} catch (ex) {
return false;
}
}
async function walk(dir?: string): Promise<string[]> {
const relPath = dir ?? '';
const path = resolvePath(relPath);
const dirPromises: Promise<string[]>[] = [];
const fileResults = await new Promise(
(
_resolve: (results: string[]) => void,
_reject: (err: Error) => void
) => {
fspReaddir(path, { withFileTypes: true })
.then((files) => {
const nonDirFiles: string[] = [];
files.forEach((file) => {
const filePath = join(relPath, file.name);
if (file.isDirectory()) {
dirPromises.push(walk(filePath));
} else {
nonDirFiles.push(filePath);
}
});
_resolve(nonDirFiles);
})
.catch((e: Error) => _reject(e));
}
);
const dirResults = await Promise.all(dirPromises);
return dirResults.flat().concat(fileResults);
}
}