@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
347 lines (346 loc) ⢠15.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.manageIncrementalBuild = manageIncrementalBuild;
exports.registerIncrementalBuildCommands = registerIncrementalBuildCommands;
const path = __importStar(require("path"));
const fs = __importStar(require("fs-extra"));
const chalk_1 = __importDefault(require("chalk"));
const spinner_1 = require("../utils/spinner");
const error_handler_1 = require("../utils/error-handler");
const incremental_builder_1 = require("../utils/incremental-builder");
// Main command handler for incremental building
async function manageIncrementalBuild(options = {}) {
const spinner = new spinner_1.ProgressSpinner({ text: 'Initializing incremental builder...' });
try {
const rootPath = process.cwd();
// Validate that we're in a Re-Shell project
const packageJsonPath = path.join(rootPath, 'package.json');
if (!await fs.pathExists(packageJsonPath)) {
throw new error_handler_1.ValidationError('Not in a valid project directory (package.json not found)');
}
spinner.start();
const builder = await (0, incremental_builder_1.createIncrementalBuilder)(rootPath, {
maxParallelBuilds: options.maxParallelBuilds,
enableCache: options.enableCache !== false,
cacheLocation: options.cacheLocation,
cleanBuild: options.cleanBuild || false,
dryRun: options.dryRun || false,
verbose: options.verbose || false,
skipTests: options.skipTests || false,
failFast: options.failFast !== false,
buildTimeout: options.buildTimeout
});
spinner.stop();
// Handle different command modes
if (options.clearCache) {
await handleClearCache(builder);
}
else if (options.stats) {
await handleShowStats(builder, options);
}
else if (options.plan) {
await handleShowPlan(builder, options);
}
else {
await handleBuild(builder, options);
}
}
catch (error) {
spinner.stop();
if (error instanceof error_handler_1.ValidationError) {
throw error;
}
throw new error_handler_1.ValidationError(`Incremental build failed: ${error}`);
}
}
// Handle build execution
async function handleBuild(builder, options) {
console.log(chalk_1.default.cyan('\nš Incremental Build'));
console.log(chalk_1.default.gray('='.repeat(25)));
const plan = await builder.createBuildPlan(options.changedFiles);
if (plan.targets.length === 0) {
console.log(chalk_1.default.green('ā
No targets need rebuilding - all builds are up to date!'));
return;
}
// Show plan summary
console.log(`\nš Build Plan:`);
console.log(` ⢠Targets to build: ${chalk_1.default.yellow(plan.targets.length)}`);
console.log(` ⢠Estimated time: ${chalk_1.default.yellow(Math.round(plan.totalEstimatedTime / 1000))}s`);
console.log(` ⢠Parallel groups: ${chalk_1.default.yellow(plan.parallelGroups.length)}`);
if (options.verbose && plan.optimizations.length > 0) {
console.log(`\nš” Optimizations:`);
plan.optimizations.forEach(opt => console.log(` ⢠${opt}`));
}
// Execute build
const results = await builder.executeBuildPlan(plan);
// Output results
if (options.format === 'json') {
const output = {
plan,
results,
summary: {
total: results.length,
successful: results.filter(r => r.success).length,
failed: results.filter(r => !r.success).length,
totalTime: results.reduce((sum, r) => sum + r.duration, 0),
cacheHits: results.filter(r => r.cacheHit).length
}
};
if (options.output) {
await fs.writeJson(options.output, output, { spaces: 2 });
console.log(chalk_1.default.green(`ā Build results saved to ${options.output}`));
}
else {
console.log(JSON.stringify(output, null, 2));
}
}
else {
await outputBuildResults(results, options.verbose || false);
}
}
// Handle showing build plan without execution
async function handleShowPlan(builder, options) {
console.log(chalk_1.default.cyan('\nš Build Plan Analysis'));
console.log(chalk_1.default.gray('='.repeat(30)));
const plan = await builder.createBuildPlan(options.changedFiles);
if (plan.targets.length === 0) {
console.log(chalk_1.default.green('ā
No targets need rebuilding - all builds are up to date!'));
return;
}
// Show detailed plan
console.log(`\nš Summary:`);
console.log(` ⢠Targets to build: ${chalk_1.default.yellow(plan.targets.length)}`);
console.log(` ⢠Build order: ${plan.buildOrder.join(' ā ')}`);
console.log(` ⢠Parallel groups: ${chalk_1.default.yellow(plan.parallelGroups.length)}`);
console.log(` ⢠Estimated time: ${chalk_1.default.yellow(Math.round(plan.totalEstimatedTime / 1000))}s`);
console.log(`\nšļø Targets:`);
plan.targets.forEach((target, index) => {
const typeColor = getTargetTypeColor(target.type);
console.log(` ${chalk_1.default.yellow(index + 1)}. ${typeColor(target.name)} (${target.type})`);
if (options.verbose) {
console.log(` Path: ${chalk_1.default.gray(target.path)}`);
console.log(` Build: ${chalk_1.default.gray(target.buildScript)}`);
if (target.dependencies.length > 0) {
console.log(` Dependencies: ${chalk_1.default.gray(target.dependencies.join(', '))}`);
}
}
});
console.log(`\nš Parallel Execution Groups:`);
plan.parallelGroups.forEach((group, index) => {
console.log(` Group ${chalk_1.default.yellow(index + 1)}: ${group.join(', ')}`);
});
if (plan.optimizations.length > 0) {
console.log(`\nš” Optimizations:`);
plan.optimizations.forEach(opt => console.log(` ⢠${opt}`));
}
// Output to file if requested
if (options.output) {
if (options.format === 'json') {
await fs.writeJson(options.output, plan, { spaces: 2 });
}
else {
const planText = `Build Plan\n${JSON.stringify(plan, null, 2)}`;
await fs.writeFile(options.output, planText);
}
console.log(chalk_1.default.green(`\nā Build plan saved to ${options.output}`));
}
}
// Handle showing build statistics
async function handleShowStats(builder, options) {
console.log(chalk_1.default.cyan('\nš Build Statistics'));
console.log(chalk_1.default.gray('='.repeat(25)));
const stats = builder.getBuildStats();
console.log(`\nš Cache Performance:`);
console.log(` ⢠Total builds: ${chalk_1.default.yellow(stats.totalBuilds)}`);
console.log(` ⢠Cache hit rate: ${chalk_1.default.yellow(Math.round(stats.cacheHitRate))}%`);
console.log(` ⢠Average build time: ${chalk_1.default.yellow(Math.round(stats.averageBuildTime / 1000))}s`);
console.log(` ⢠Total cache size: ${chalk_1.default.yellow(formatBytes(stats.totalCacheSize))}`);
// Performance recommendations
console.log(`\nš” Recommendations:`);
if (stats.cacheHitRate < 50) {
console.log(` ⢠Consider enabling build caching for better performance`);
}
if (stats.averageBuildTime > 60000) {
console.log(` ⢠Consider optimizing build scripts or increasing parallel builds`);
}
if (stats.totalCacheSize > 1000000000) { // 1GB
console.log(` ⢠Consider clearing old cache entries to save disk space`);
}
// Output to file if requested
if (options.output) {
if (options.format === 'json') {
await fs.writeJson(options.output, stats, { spaces: 2 });
}
else {
const statsText = `Build Statistics\n${JSON.stringify(stats, null, 2)}`;
await fs.writeFile(options.output, statsText);
}
console.log(chalk_1.default.green(`\nā Statistics saved to ${options.output}`));
}
}
// Handle clearing build cache
async function handleClearCache(builder) {
console.log(chalk_1.default.cyan('\nš§¹ Clearing Build Cache'));
console.log(chalk_1.default.gray('='.repeat(30)));
await builder.clearCache();
console.log(chalk_1.default.green('ā
Build cache cleared successfully!'));
}
// Output build results in text format
async function outputBuildResults(results, verbose) {
const successful = results.filter(r => r.success);
const failed = results.filter(r => !r.success);
const cacheHits = results.filter(r => r.cacheHit);
console.log(`\nš Build Results:`);
console.log(` ⢠Total: ${chalk_1.default.yellow(results.length)}`);
console.log(` ⢠Successful: ${chalk_1.default.green(successful.length)}`);
console.log(` ⢠Failed: ${failed.length > 0 ? chalk_1.default.red(failed.length) : chalk_1.default.gray('0')}`);
console.log(` ⢠Cache hits: ${chalk_1.default.cyan(cacheHits.length)}`);
if (successful.length > 0) {
console.log(`\nā
Successful Builds:`);
successful.forEach(result => {
const durationText = result.cacheHit ? 'cached' : `${Math.round(result.duration / 1000)}s`;
const sizeText = result.outputSize ? ` (${formatBytes(result.outputSize)})` : '';
console.log(` ⢠${result.target}: ${chalk_1.default.green(durationText)}${sizeText}`);
});
}
if (failed.length > 0) {
console.log(`\nā Failed Builds:`);
failed.forEach(result => {
console.log(` ⢠${result.target}: ${chalk_1.default.red('failed')}`);
if (verbose && result.error) {
console.log(` Error: ${chalk_1.default.gray(result.error)}`);
}
});
}
// Performance summary
const totalTime = results.reduce((sum, r) => sum + r.duration, 0);
const averageTime = results.length > 0 ? totalTime / results.length : 0;
console.log(`\nā±ļø Performance:`);
console.log(` ⢠Total time: ${chalk_1.default.yellow(Math.round(totalTime / 1000))}s`);
console.log(` ⢠Average per target: ${chalk_1.default.yellow(Math.round(averageTime / 1000))}s`);
if (cacheHits.length > 0) {
const timeSaved = cacheHits.length * averageTime;
console.log(` ⢠Time saved by cache: ${chalk_1.default.green(Math.round(timeSaved / 1000))}s`);
}
}
// Get color for target type
function getTargetTypeColor(type) {
switch (type) {
case 'app': return chalk_1.default.blue;
case 'package': return chalk_1.default.green;
case 'lib': return chalk_1.default.magenta;
case 'tool': return chalk_1.default.cyan;
default: return chalk_1.default.white;
}
}
// Format bytes for display
function formatBytes(bytes) {
if (bytes === 0)
return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
}
// Register incremental build commands
function registerIncrementalBuildCommands(program) {
const incrementalBuild = program
.command('incremental-build')
.alias('ibuild')
.description('Intelligent incremental building with change detection');
incrementalBuild
.command('build')
.description('Run incremental build')
.option('--targets <targets...>', 'Specific targets to build')
.option('--changed-files <files...>', 'Specific changed files to analyze')
.option('--max-parallel <num>', 'Maximum parallel builds', '4')
.option('--no-cache', 'Disable build caching')
.option('--cache-location <path>', 'Build cache location')
.option('--clean', 'Clean build (ignore cache)')
.option('--dry-run', 'Show what would be built without building')
.option('--verbose', 'Show detailed information')
.option('--skip-tests', 'Skip test execution')
.option('--no-fail-fast', 'Continue building after failures')
.option('--build-timeout <ms>', 'Build timeout in milliseconds', '300000')
.option('--output <file>', 'Output file path')
.option('--format <format>', 'Output format (text|json)', 'text')
.action(async (options) => {
await manageIncrementalBuild({
...options,
maxParallelBuilds: parseInt(options.maxParallel),
buildTimeout: parseInt(options.buildTimeout),
enableCache: options.cache !== false,
cleanBuild: options.clean,
dryRun: options.dryRun,
failFast: options.failFast !== false
});
});
incrementalBuild
.command('plan')
.description('Show build plan without executing')
.option('--changed-files <files...>', 'Specific changed files to analyze')
.option('--verbose', 'Show detailed information')
.option('--output <file>', 'Output file path')
.option('--format <format>', 'Output format (text|json)', 'text')
.action(async (options) => {
await manageIncrementalBuild({
...options,
plan: true
});
});
incrementalBuild
.command('stats')
.description('Show build statistics and performance metrics')
.option('--output <file>', 'Output file path')
.option('--format <format>', 'Output format (text|json)', 'text')
.action(async (options) => {
await manageIncrementalBuild({
...options,
stats: true
});
});
incrementalBuild
.command('clear-cache')
.description('Clear build cache')
.action(async () => {
await manageIncrementalBuild({
clearCache: true
});
});
}