kist
Version:
Lightweight Package Pipeline Processor with Plugin Architecture
157 lines • 6.32 kB
JavaScript
import { __awaiter } from "tslib";
import fs from "fs";
import path from "path";
import { pipeline } from "stream/promises";
import { Action } from "../../core/pipeline/Action.js";
import { FileCache } from "../../core/cache/FileCache.js";
const STREAMING_THRESHOLD = 5 * 1024 * 1024;
export class FileCopyAction extends Action {
constructor() {
super();
this.fileCache = FileCache.getInstance();
}
execute(options) {
return __awaiter(this, void 0, void 0, function* () {
const srcFile = options.srcFile;
const srcFiles = options.srcFiles;
const destDir = options.destDir;
const useCache = options.useCache;
const parallel = options.parallel;
if ((!srcFile && !srcFiles) || !destDir) {
throw new Error("Missing required options: srcFile/srcFiles or destDir.");
}
if (srcFiles && srcFiles.length > 0) {
yield this.copyMultipleFiles(srcFiles, destDir, {
useCache,
parallel,
});
return;
}
if (srcFile) {
yield this.copySingleFile(srcFile, destDir, { useCache });
}
});
}
copySingleFile(srcFile_1, destDir_1) {
return __awaiter(this, arguments, void 0, function* (srcFile, destDir, options = {}) {
if (options.useCache) {
const hasChanged = yield this.fileCache.hasFileChanged(srcFile);
if (!hasChanged) {
this.logDebug(`Skipping unchanged file: ${srcFile}`);
return;
}
}
this.logInfo(`Copying file from ${srcFile} to ${destDir}.`);
try {
yield this.copyFileToDirectory(srcFile, destDir);
if (options.useCache) {
yield this.fileCache.updateFileEntry(srcFile);
}
this.logInfo(`File copied successfully from ${srcFile} to ${destDir}.`);
}
catch (error) {
this.logError(`Error copying file from ${srcFile} to ${destDir}: ${error}`);
throw error;
}
});
}
copyMultipleFiles(srcFiles_1, destDir_1) {
return __awaiter(this, arguments, void 0, function* (srcFiles, destDir, options = {}) {
const startTime = performance.now();
let filesToCopy = srcFiles;
if (options.useCache) {
filesToCopy = yield this.fileCache.getChangedFiles(srcFiles);
const skipped = srcFiles.length - filesToCopy.length;
if (skipped > 0) {
this.logInfo(`Skipping ${skipped} unchanged files.`);
}
}
if (filesToCopy.length === 0) {
this.logInfo("All files are up to date, nothing to copy.");
return;
}
this.logInfo(`Copying ${filesToCopy.length} files to ${destDir}.`);
try {
if (options.parallel) {
yield this.copyFilesInParallel(filesToCopy, destDir, 10);
}
else {
for (const file of filesToCopy) {
yield this.copyFileToDirectory(file, destDir);
}
}
if (options.useCache) {
yield this.fileCache.updateFileEntries(filesToCopy);
}
const duration = performance.now() - startTime;
this.logInfo(`Copied ${filesToCopy.length} files in ${duration.toFixed(2)}ms.`);
}
catch (error) {
this.logError(`Error copying files: ${error}`);
throw error;
}
});
}
copyFilesInParallel(srcFiles_1, destDir_1) {
return __awaiter(this, arguments, void 0, function* (srcFiles, destDir, maxConcurrent = 10) {
const executing = new Set();
for (const srcFile of srcFiles) {
const copyPromise = this.copyFileToDirectory(srcFile, destDir).finally(() => executing.delete(copyPromise));
executing.add(copyPromise);
if (executing.size >= maxConcurrent) {
yield Promise.race(executing);
}
}
yield Promise.all(executing);
});
}
copyFileToDirectory(srcFile, destDir) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield this.ensureDirectoryExists(destDir);
const fileName = path.basename(srcFile);
const destFilePath = path.join(destDir, fileName);
const stat = yield fs.promises.stat(srcFile);
if (stat.size > STREAMING_THRESHOLD) {
yield this.streamCopyFile(srcFile, destFilePath);
}
else {
yield fs.promises.copyFile(srcFile, destFilePath);
}
}
catch (error) {
this.logError(`Error copying file: ${error}`);
throw error;
}
});
}
streamCopyFile(srcFile, destFile) {
return __awaiter(this, void 0, void 0, function* () {
const readStream = fs.createReadStream(srcFile);
const writeStream = fs.createWriteStream(destFile);
yield pipeline(readStream, writeStream);
});
}
ensureDirectoryExists(dirPath) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield fs.promises.mkdir(dirPath, { recursive: true });
}
catch (error) {
if (error instanceof Error) {
const nodeError = error;
if (nodeError.code !== "EEXIST") {
throw nodeError;
}
}
else {
throw error;
}
}
});
}
describe() {
return "Copies a file from a source location to a destination directory, ensuring directories exist and handling errors gracefully.";
}
}
//# sourceMappingURL=FileCopyAction.js.map