22
src/cache/cache-manager.js
vendido
22
src/cache/cache-manager.js
vendido
@@ -66,6 +66,28 @@ class CacheManager {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async has(packageName, version) {
|
||||||
|
const key = this.generateKey(packageName, version);
|
||||||
|
const metadata = await this.loadMetadata();
|
||||||
|
|
||||||
|
if (!metadata.entries[key]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = metadata.entries[key];
|
||||||
|
const filePath = path.join(this.cacheDir, entry.file);
|
||||||
|
|
||||||
|
// Check if file exists
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
// Remove stale entry
|
||||||
|
delete metadata.entries[key];
|
||||||
|
await this.saveMetadata(metadata);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async store(packageName, version, data) {
|
async store(packageName, version, data) {
|
||||||
const key = this.generateKey(packageName, version);
|
const key = this.generateKey(packageName, version);
|
||||||
const metadata = await this.loadMetadata();
|
const metadata = await this.loadMetadata();
|
||||||
|
|||||||
@@ -69,80 +69,23 @@ class PackageManager {
|
|||||||
// Ensure initialization
|
// Ensure initialization
|
||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
|
|
||||||
const spinner = ora('Analyzing dependencies...').start();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// If no packages specified, install from package.json
|
// If no packages specified, install from package.json
|
||||||
if (packages.length === 0) {
|
if (packages.length === 0) {
|
||||||
|
const packageJsonPath = path.join(this.projectRoot, 'package.json');
|
||||||
|
|
||||||
|
if (!fs.existsSync(packageJsonPath)) {
|
||||||
|
throw new Error('No package.json found and no packages specified to install');
|
||||||
|
}
|
||||||
|
|
||||||
return await this.installFromPackageJson(options);
|
return await this.installFromPackageJson(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse package specifications
|
// Install specified packages
|
||||||
const packageSpecs = packages.map(pkg => this.parsePackageSpec(pkg));
|
return await this.installPackages(packages, options);
|
||||||
|
|
||||||
spinner.text = 'Resolving dependencies...';
|
|
||||||
|
|
||||||
// Resolve dependencies
|
|
||||||
const resolved = await this.resolver.resolve(packageSpecs, {
|
|
||||||
projectRoot: options.global ? this.globalRoot : this.projectRoot,
|
|
||||||
includeDevDependencies: !options.saveExact
|
|
||||||
});
|
|
||||||
|
|
||||||
spinner.text = 'Checking security vulnerabilities...';
|
|
||||||
|
|
||||||
// Security audit
|
|
||||||
await this.security.auditPackages(resolved);
|
|
||||||
|
|
||||||
spinner.text = 'Downloading packages...';
|
|
||||||
|
|
||||||
// Download and install packages
|
|
||||||
const tasks = new Listr([
|
|
||||||
{
|
|
||||||
title: 'Downloading packages',
|
|
||||||
task: async (ctx, task) => {
|
|
||||||
const downloads = resolved.map(pkg => ({
|
|
||||||
title: `${pkg.name}@${pkg.version}`,
|
|
||||||
task: async () => {
|
|
||||||
const cached = await this.cache.get(pkg.name, pkg.version);
|
|
||||||
if (!cached) {
|
|
||||||
const downloaded = await this.registry.download(pkg);
|
|
||||||
await this.cache.store(pkg.name, pkg.version, downloaded);
|
|
||||||
await this.security.verifyIntegrity(downloaded, pkg.integrity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return task.newListr(downloads, { concurrent: 5 });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Installing packages',
|
|
||||||
task: async () => {
|
|
||||||
for (const pkg of resolved) {
|
|
||||||
await this.installPackage(pkg, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Updating lock file',
|
|
||||||
task: async () => {
|
|
||||||
await this.lock.update(resolved, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
spinner.stop();
|
|
||||||
await tasks.run();
|
|
||||||
|
|
||||||
// Update package.json if needed
|
|
||||||
if (!options.global) {
|
|
||||||
await this.updatePackageJson(packageSpecs, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(chalk.green(`\n✓ Installed ${resolved.length} packages`));
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
spinner.stop();
|
console.error(chalk.red(`Installation failed: ${error.message}`));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,9 +103,71 @@ class PackageManager {
|
|||||||
...(options.includeDev ? packageJson.devDependencies : {})
|
...(options.includeDev ? packageJson.devDependencies : {})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Object.keys(dependencies).length === 0) {
|
||||||
|
console.log(chalk.yellow('No dependencies found in package.json'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const packages = Object.entries(dependencies).map(([name, version]) => `${name}@${version}`);
|
const packages = Object.entries(dependencies).map(([name, version]) => `${name}@${version}`);
|
||||||
|
|
||||||
return await this.install(packages, { ...options, fromPackageJson: true });
|
// Call the main installation logic directly, bypassing the package.json check
|
||||||
|
return await this.installPackages(packages, { ...options, fromPackageJson: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
async installPackages(packages, options = {}) {
|
||||||
|
if (!packages || packages.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.blue(`Installing ${packages.length} package(s)...`));
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
for (const packageSpec of packages) {
|
||||||
|
try {
|
||||||
|
const { name, version } = this.parsePackageSpec(packageSpec);
|
||||||
|
console.log(chalk.blue(`Installing ${name}@${version || 'latest'}`));
|
||||||
|
|
||||||
|
// Check cache first
|
||||||
|
if (this.cache.has(name, version)) {
|
||||||
|
console.log(chalk.green(`Using cached version of ${name}`));
|
||||||
|
results.push({ name, version, source: 'cache' });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve and download
|
||||||
|
const resolvedPackage = await this.resolver.resolvePackage(name, version || 'latest');
|
||||||
|
|
||||||
|
// Security check
|
||||||
|
if (options.secure !== false) {
|
||||||
|
await this.security.scanPackage(resolvedPackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download and store
|
||||||
|
const packageData = await this.registry.download(resolvedPackage.name, resolvedPackage.version);
|
||||||
|
|
||||||
|
// Store in cache
|
||||||
|
await this.cache.store(resolvedPackage.name, resolvedPackage.version, packageData);
|
||||||
|
|
||||||
|
results.push({
|
||||||
|
name: resolvedPackage.name,
|
||||||
|
version: resolvedPackage.version,
|
||||||
|
source: 'registry'
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(chalk.green(`✓ Installed ${resolvedPackage.name}@${resolvedPackage.version}`));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(chalk.red(`✗ Failed to install ${packageSpec}: ${error.message}`));
|
||||||
|
results.push({ packageSpec, error: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update lock file
|
||||||
|
await this.lock.update(results.filter(r => !r.error));
|
||||||
|
|
||||||
|
console.log(chalk.green(`Installation completed. ${results.filter(r => !r.error).length} packages installed.`));
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
async installPackage(pkg, options = {}) {
|
async installPackage(pkg, options = {}) {
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user