@sprucelabs/spruce-skill-utils
Version:
Loosely coupled classes and functions to make skill development faster! 🏎
288 lines (287 loc) • 10 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const schema_1 = require("@sprucelabs/schema");
const fs_extra_1 = __importDefault(require("fs-extra"));
const constants_1 = require("../constants");
function existsSync(path) {
return !!fs_extra_1.default.statSync(path, { throwIfNoEntry: false });
}
const diskUtil = {
writeFile(destination, contents) {
fs_extra_1.default.outputFileSync(destination, contents);
},
readDir(destination) {
return fs_extra_1.default.readdirSync(destination);
},
readFile(source) {
if (!existsSync(source)) {
throw new Error(`No file to read at ${source}`);
}
return fs_extra_1.default.readFileSync(source).toString();
},
deleteFile(destination) {
if (existsSync(destination)) {
fs_extra_1.default.removeSync(destination);
}
},
createDir(destination) {
fs_extra_1.default.ensureDirSync(destination);
},
moveDir(source, destination) {
fs_extra_1.default.moveSync(source, destination);
},
moveFile(source, destination) {
fs_extra_1.default.moveSync(source, destination);
},
async copyDir(source, destination) {
this.createDir(destination);
return new Promise((resolve, reject) => {
(0, child_process_1.exec)(`cd ${source} && tar cf - . | (cd ${destination}; tar xf -)`, { maxBuffer: 1024 * 1024 * 5 }, (err, stdout) => {
if (err) {
reject(err);
return;
}
resolve(stdout);
});
});
},
deleteDir(target) {
const resolved = this.resolvePath(target);
if (existsSync(resolved)) {
fs_extra_1.default.removeSync(resolved);
}
},
doesFileExist(target) {
const resolved = this.resolvePath(target);
return existsSync(resolved);
},
isDir(target) {
const resolved = this.resolvePath(target);
if (this.doesDirExist(resolved)) {
return fs_extra_1.default.lstatSync(resolved).isDirectory();
}
return false;
},
isDirPath(path) {
const resolved = this.resolvePath(path);
if (this.isDir(resolved)) {
return true;
}
return path_1.default.extname(resolved).length === 0;
},
isFile(target) {
const resolved = this.resolvePath(target);
if (this.doesFileExist(resolved)) {
return fs_extra_1.default.lstatSync(resolved).isFile();
}
return false;
},
doesDirExist(target) {
const resolved = this.resolvePath(target);
return existsSync(resolved);
},
resolveHashSprucePath(cwd, ...filePath) {
const parts = cwd.split(path_1.default.sep);
do {
const path = path_1.default.join('/', ...parts, constants_1.HASH_SPRUCE_DIR);
if (this.doesDirExist(path)) {
return this.resolvePath(path, ...filePath);
}
parts.pop();
} while (parts.length > 0);
throw new Error(`.spruce directory not found at ${cwd}`);
},
doesHashSprucePathExist(cwd, ...filePath) {
try {
this.resolveHashSprucePath(cwd, ...filePath);
return true;
}
catch {
return false;
}
},
resolveBuiltHashSprucePath(cwd, ...filePath) {
const parts = cwd.split(path_1.default.sep);
do {
const path = path_1.default.join('/', ...parts, constants_1.HASH_SPRUCE_BUILD_DIR);
if (this.doesDirExist(path)) {
return this.resolvePath(path, ...filePath);
}
parts.pop();
} while (parts.length > 0);
throw new Error(`Built .spruce directory not found at ${cwd}. Try \`spruce build\` and try again.`);
},
doesBuiltHashSprucePathExist(cwd, ...filePath) {
try {
this.resolveBuiltHashSprucePath(cwd, ...filePath);
return true;
}
catch {
return false;
}
},
isFileDifferent(destination, contents) {
const currentContents = this.readFile(destination);
return currentContents != contents;
},
deleteEmptyDirs(dir) {
if (!dir) {
throw new schema_1.SchemaError({
code: 'MISSING_PARAMETERS',
parameters: ['dir'],
});
}
if (!this.doesDirExist(dir)) {
throw new schema_1.SchemaError({
code: 'INVALID_PARAMETERS',
parameters: ['dir'],
friendlyMessage: `No directory found at ${dir} to clean.`,
});
}
const dirname = path_1.default.resolve(dir);
const remove = (dir, depth = 0) => {
const thisDepth = depth + 1;
if (!diskUtil.isDir(dir)) {
return;
}
let files = fs_extra_1.default.readdirSync(dir);
for (let filepath of files) {
remove(path_1.default.join(dir, filepath), thisDepth);
}
let filesAfter = fs_extra_1.default.readdirSync(dir);
if (depth > 0 && filesAfter.length === 0) {
diskUtil.deleteDir(dir);
}
};
return remove(dirname);
},
resolvePath(cwd, ...filePath) {
let builtPath = path_1.default.join(...filePath);
if (builtPath[0] !== '/') {
// Relative to the cwd
if (builtPath.substr(0, 2) === './') {
builtPath = builtPath.substr(1);
}
builtPath = path_1.default.join(cwd, builtPath);
}
if (builtPath.search('#') > -1) {
builtPath = builtPath.replace('#spruce', constants_1.HASH_SPRUCE_DIR);
}
return builtPath;
},
resolveRelativePath(path1, path2) {
const path = path_1.default.relative(path1, path2);
if (path[0] !== '.') {
return `.${path_1.default.sep}${path}`;
}
return path;
},
resolveFile(...pathItems) {
const extensions = ['', '.js', '.ts'];
for (const extension of extensions) {
const items = [...pathItems];
items[pathItems.length - 1] += extension;
//@ts-ignore
const resolved = this.resolvePath(...items);
if (this.doesFileExist(resolved)) {
return resolved;
}
}
return false;
},
createTempDir(...files) {
const tmpDir = os_1.default.tmpdir();
const targetDir = path_1.default.join(tmpDir, ...files);
this.createDir(targetDir);
return targetDir;
},
createRandomTempDir() {
return this.createTempDir(uuid());
},
hasFileChanged(...filePath) {
if (!filePath || !(filePath.length > 0)) {
throw new schema_1.SchemaError({
code: 'MISSING_PARAMETERS',
parameters: ['file'],
});
}
//@ts-ignore
const file = this.resolvePath(...filePath);
const cacheFile = this.getFileChangedCacheFile(file);
let fileStat;
try {
fileStat = fs_extra_1.default.statSync(file);
}
catch (err) {
return true;
}
let cacheFileStat;
try {
cacheFileStat = fs_extra_1.default.statSync(cacheFile);
}
catch (err) {
//@ts-ignore
}
if (!cacheFileStat || cacheFileStat.ctimeMs < fileStat.ctimeMs) {
this.writeFile(cacheFile, '');
return true;
}
return false;
},
markFileAsUnchanged(...filePath) {
const cacheCheckFile = this.getFileChangedCacheFile(
//@ts-ignore
this.resolvePath(...filePath));
diskUtil.writeFile(cacheCheckFile, '');
},
resolveCacheDirForDir(dir) {
return this.resolvePath(dir, '.change_cache');
},
resolveFileInHashSpruceDir(cwd, ...filePath) {
const dirs = ['build', 'src'];
for (const dir of dirs) {
const path = this.resolvePath(cwd, ...[dir, constants_1.HASH_SPRUCE_DIR_NAME, ...filePath]);
const file = this.resolveFile(path);
if (file) {
return file;
}
}
const path = diskUtil.resolvePath(
//@ts-ignore
...[cwd, '[build|src]', constants_1.HASH_SPRUCE_DIR_NAME, ...filePath]);
throw new Error(`Could not find ${path}.[ts|js] in the hash spruce dir!`);
},
getFileChangedCacheFile(file) {
if (!file) {
throw new schema_1.SchemaError({
code: 'MISSING_PARAMETERS',
parameters: ['file'],
});
}
const dirname = path_1.default.dirname(file);
const filename = path_1.default.basename(file);
const changeCacheDir = this.resolveCacheDirForDir(dirname);
const cacheFile = this.resolvePath(changeCacheDir, filename.replace(/\.\./g, '__'));
if (!this.doesDirExist(changeCacheDir)) {
fs_extra_1.default.mkdirSync(changeCacheDir, { recursive: true });
}
const gitignoreFile = diskUtil.resolvePath(changeCacheDir, '.gitignore');
if (!diskUtil.doesFileExist(gitignoreFile)) {
diskUtil.writeFile(gitignoreFile, '*');
}
return cacheFile;
},
};
exports.default = diskUtil;
function uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}