indicator when external modules are being downloaded during install so installer does not appear to be frozen / unresponsive.

This commit is contained in:
Brian Madison 2026-01-18 02:16:04 -06:00
parent e0318d9da8
commit 966ca5db0b
1 changed files with 54 additions and 16 deletions

View File

@ -2,6 +2,7 @@ const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('yaml'); const yaml = require('yaml');
const chalk = require('chalk'); const chalk = require('chalk');
const ora = require('ora');
const { XmlHandler } = require('../../../lib/xml-handler'); const { XmlHandler } = require('../../../lib/xml-handler');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root'); const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
const { filterCustomizationData } = require('../../../lib/agent/compiler'); const { filterCustomizationData } = require('../../../lib/agent/compiler');
@ -414,27 +415,48 @@ class ModuleManager {
// Create cache directory if it doesn't exist // Create cache directory if it doesn't exist
await fs.ensureDir(cacheDir); await fs.ensureDir(cacheDir);
// Track if we need to install dependencies
let needsDependencyInstall = false;
let wasNewClone = false;
// Check if already cloned // Check if already cloned
if (await fs.pathExists(moduleCacheDir)) { if (await fs.pathExists(moduleCacheDir)) {
// Try to update if it's a git repo // Try to update if it's a git repo
const updateSpinner = ora(`Updating ${moduleInfo.name} from remote repository...`).start();
try { try {
const currentRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
execSync('git fetch --depth 1', { cwd: moduleCacheDir, stdio: 'pipe' }); execSync('git fetch --depth 1', { cwd: moduleCacheDir, stdio: 'pipe' });
execSync('git checkout -f', { cwd: moduleCacheDir, stdio: 'pipe' }); execSync('git checkout -f', { cwd: moduleCacheDir, stdio: 'pipe' });
execSync('git pull --ff-only', { cwd: moduleCacheDir, stdio: 'pipe' }); execSync('git pull --ff-only', { cwd: moduleCacheDir, stdio: 'pipe' });
const newRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
if (currentRef === newRef) {
updateSpinner.succeed(`${moduleInfo.name} is already up to date`);
} else {
updateSpinner.succeed(`Updated ${moduleInfo.name} to latest version`);
// Force dependency install since we got new code
needsDependencyInstall = true;
}
} catch { } catch {
updateSpinner.warn(`Update failed, re-downloading ${moduleInfo.name}`);
// If update fails, remove and re-clone // If update fails, remove and re-clone
await fs.remove(moduleCacheDir); await fs.remove(moduleCacheDir);
wasNewClone = true;
} }
} else {
wasNewClone = true;
} }
// Clone if not exists or was removed // Clone if not exists or was removed
if (!(await fs.pathExists(moduleCacheDir))) { if (wasNewClone) {
console.log(chalk.dim(` Cloning external module: ${moduleInfo.name}`)); const cloneSpinner = ora(`Downloading ${moduleInfo.name} from remote repository...`).start();
try { try {
execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, { execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, {
stdio: 'pipe', stdio: 'pipe',
}); });
cloneSpinner.succeed(`Downloaded ${moduleInfo.name}`);
} catch (error) { } catch (error) {
cloneSpinner.fail(`Failed to download ${moduleInfo.name}`);
throw new Error(`Failed to clone external module '${moduleCode}': ${error.message}`); throw new Error(`Failed to clone external module '${moduleCode}': ${error.message}`);
} }
} }
@ -444,11 +466,25 @@ class ModuleManager {
const nodeModulesPath = path.join(moduleCacheDir, 'node_modules'); const nodeModulesPath = path.join(moduleCacheDir, 'node_modules');
if (await fs.pathExists(packageJsonPath)) { if (await fs.pathExists(packageJsonPath)) {
// Install if node_modules doesn't exist, or if package.json is newer (dependencies changed) // Install if node_modules doesn't exist, or if package.json is newer (dependencies changed)
const needsInstall = !(await fs.pathExists(nodeModulesPath)); const nodeModulesMissing = !(await fs.pathExists(nodeModulesPath));
let packageJsonNewer = false;
if (!needsInstall) { // Force install if we updated or cloned new
if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
try {
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
cwd: moduleCacheDir,
stdio: 'pipe',
timeout: 120_000, // 2 minute timeout
});
installSpinner.succeed(`Installed dependencies for ${moduleInfo.name}`);
} catch (error) {
installSpinner.warn(`Failed to install dependencies for ${moduleInfo.name}`);
console.warn(chalk.yellow(` Warning: ${error.message}`));
}
} else {
// Check if package.json is newer than node_modules // Check if package.json is newer than node_modules
let packageJsonNewer = false;
try { try {
const packageStats = await fs.stat(packageJsonPath); const packageStats = await fs.stat(packageJsonPath);
const nodeModulesStats = await fs.stat(nodeModulesPath); const nodeModulesStats = await fs.stat(nodeModulesPath);
@ -457,18 +493,20 @@ class ModuleManager {
// If stat fails, assume we need to install // If stat fails, assume we need to install
packageJsonNewer = true; packageJsonNewer = true;
} }
}
if (needsInstall || packageJsonNewer) { if (packageJsonNewer) {
console.log(chalk.dim(` Installing dependencies for ${moduleInfo.name}...`)); const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
try { try {
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', { execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
cwd: moduleCacheDir, cwd: moduleCacheDir,
stdio: 'inherit', stdio: 'pipe',
timeout: 120_000, // 2 minute timeout timeout: 120_000, // 2 minute timeout
}); });
} catch (error) { installSpinner.succeed(`Installed dependencies for ${moduleInfo.name}`);
console.warn(chalk.yellow(` Warning: Failed to install dependencies for ${moduleInfo.name}: ${error.message}`)); } catch (error) {
installSpinner.warn(`Failed to install dependencies for ${moduleInfo.name}`);
console.warn(chalk.yellow(` Warning: ${error.message}`));
}
} }
} }
} }