UNPKG

kist

Version:

Lightweight Package Pipeline Processor with Plugin Architecture

122 lines 4.56 kB
import { AbstractProcess } from "../abstract/AbstractProcess.js"; import { FileCache } from "../cache/FileCache.js"; import { BuildCache } from "../cache/BuildCache.js"; import { ProgressReporter } from "../progress/ProgressReporter.js"; import { Stage } from "./Stage.js"; export class Pipeline extends AbstractProcess { config; stages; options; fileCache; buildCache; progress; constructor(config) { super(); this.config = config; this.stages = config.stages.map((stage) => new Stage(stage)); this.options = config.options; this.logInfo("Pipeline instance created."); } async run() { const startTime = performance.now(); this.logInfo("Starting pipeline execution..."); await this.initializeCaching(); this.initializeProgress(); const completedStages = new Set(); try { this.logDebug("Pipeline execution started with debug logging."); this.progress?.start(); const stagePromises = this.stages.map((stage, index) => stage.execute(completedStages).then(() => { this.progress?.increment(); })); await this.runWithConcurrencyControl(stagePromises); this.progress?.finish(); await this.saveCaches(); const duration = performance.now() - startTime; this.logInfo(`Pipeline execution completed successfully in ${this.formatDuration(duration)}.`); this.reportCacheStats(); } catch (error) { this.progress?.cancel(); this.logError("Pipeline execution failed:", error); await this.saveCaches(); if (this.options?.haltOnFailure !== false) { this.logError("Halting pipeline due to failure."); process.exit(1); } else { this.logWarn("Continuing pipeline execution despite errors."); } } } async initializeCaching() { const cacheOptions = this.options?.cache; if (!cacheOptions?.enabled) { return; } this.logInfo("Initializing build cache..."); this.fileCache = FileCache.getInstance({ cacheDir: cacheOptions.cacheDir, ttl: cacheOptions.ttl, }); await this.fileCache.initialize(); this.buildCache = BuildCache.getInstance({ cacheDir: cacheOptions.cacheDir, maxCacheSize: cacheOptions.maxCacheSize, ttl: cacheOptions.ttl, }); await this.buildCache.initialize(); this.logDebug("Build cache initialized."); } initializeProgress() { const perfOptions = this.options?.performance; if (perfOptions?.showProgress === false) { return; } this.progress = new ProgressReporter({ total: this.stages.length, label: "Pipeline", showPercentage: true, showEta: true, }); } async saveCaches() { await Promise.all([this.fileCache?.save(), this.buildCache?.save()]); } reportCacheStats() { if (this.fileCache) { const stats = this.fileCache.getStats(); this.logDebug(`File cache: ${stats.size} entries, ${stats.hitRate} hit rate`); } if (this.buildCache) { const stats = this.buildCache.getStats(); this.logDebug(`Build cache: ${stats.size} entries, ${stats.hitRate} hit rate`); } } formatDuration(ms) { if (ms < 1000) { return `${Math.round(ms)}ms`; } if (ms < 60000) { return `${(ms / 1000).toFixed(2)}s`; } const minutes = Math.floor(ms / 60000); const seconds = ((ms % 60000) / 1000).toFixed(1); return `${minutes}m ${seconds}s`; } async runWithConcurrencyControl(stagePromises) { const maxConcurrentStages = this.options?.performance?.maxConcurrentStages || this.options?.maxConcurrentStages || stagePromises.length; const executingStages = new Set(); for (const stagePromise of stagePromises) { executingStages.add(stagePromise); stagePromise.finally(() => executingStages.delete(stagePromise)); if (executingStages.size >= maxConcurrentStages) { await Promise.race(executingStages); } } await Promise.all(executingStages); } } //# sourceMappingURL=Pipeline.js.map