mirror of
https://github.com/bower/bower.git
synced 2026-02-12 06:55:04 -05:00
238 lines
6.6 KiB
JavaScript
238 lines
6.6 KiB
JavaScript
var EventEmitter = require('events').EventEmitter;
|
|
var fs = require('graceful-fs');
|
|
var path = require('path');
|
|
var mout = require('mout');
|
|
var Q = require('q');
|
|
var rimraf = require('rimraf');
|
|
var RegistryClient = require('bower-registry-client');
|
|
var PackageRepository = require('../../core/PackageRepository');
|
|
var Logger = require('../../core/Logger');
|
|
var cli = require('../../util/cli');
|
|
var defaultConfig = require('../../config');
|
|
|
|
function clean(packages, options, config) {
|
|
var emitter = new EventEmitter();
|
|
var logger = new Logger();
|
|
var names;
|
|
|
|
options = options || {};
|
|
config = mout.object.deepMixIn(config || {}, defaultConfig);
|
|
|
|
// If packages is an empty array, null them
|
|
if (packages && !packages.length) {
|
|
packages = names = null;
|
|
// Otherwise parse them
|
|
} else {
|
|
packages = packages.map(function (pkg) {
|
|
var split = pkg.split('#');
|
|
return {
|
|
name: split[0],
|
|
version: split[1]
|
|
};
|
|
});
|
|
names = packages.map(function (pkg) {
|
|
return pkg.name;
|
|
});
|
|
}
|
|
|
|
Q.all([
|
|
clearPackages(packages, config, logger),
|
|
clearRegistry(names, config, logger),
|
|
clearLinks(names, config, logger),
|
|
!names ? clearCompletion(config, logger) : null
|
|
])
|
|
.spread(function (entries) {
|
|
emitter.emit('end', entries);
|
|
})
|
|
.fail(function (error) {
|
|
emitter.emit('error', error);
|
|
});
|
|
|
|
return logger.pipe(emitter);
|
|
}
|
|
|
|
function clearPackages(packages, config, logger) {
|
|
var repository = new PackageRepository(config, logger);
|
|
|
|
return repository.list()
|
|
.then(function (entries) {
|
|
var promises;
|
|
|
|
// Filter entries according to the specified packages
|
|
if (packages) {
|
|
entries = entries.filter(function (entry) {
|
|
return !!mout.array.find(packages, function (pkg) {
|
|
var entryPkgMeta = entry.pkgMeta;
|
|
|
|
// Check if names are different
|
|
if (pkg.name !== entryPkgMeta.name) {
|
|
return false;
|
|
}
|
|
|
|
// If version was specified, check if they are different
|
|
if (pkg.version) {
|
|
return pkg.version === entryPkgMeta.version ||
|
|
pkg.version === entryPkgMeta.target;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
});
|
|
}
|
|
|
|
promises = entries.map(function (entry) {
|
|
return repository.eliminate(entry.pkgMeta)
|
|
.then(function () {
|
|
logger.info('deleted', 'Cached package ' + entry.pkgMeta.name + ': ' + entry.canonicalDir, {
|
|
file: entry.canonicalDir
|
|
});
|
|
});
|
|
});
|
|
|
|
return Q.all(promises)
|
|
.then(function () {
|
|
if (!packages) {
|
|
// Ensure that everything is cleaned,
|
|
// even invalid packages in the cache
|
|
return repository.clear();
|
|
}
|
|
})
|
|
.then(function () {
|
|
return entries;
|
|
});
|
|
});
|
|
}
|
|
|
|
function clearRegistry(names, config, logger) {
|
|
var registryClient;
|
|
var promises;
|
|
var registryOptions;
|
|
|
|
registryOptions = mout.object.deepMixIn({}, config);
|
|
registryOptions.cache = config.storage.registry;
|
|
registryClient = new RegistryClient(registryOptions);
|
|
|
|
if (names) {
|
|
promises = names.map(function (name) {
|
|
return Q.nfcall(registryClient.clearCache.bind(registryClient), name)
|
|
.then(function () {
|
|
logger.info('info', 'Cleaned registry cache for ' + name);
|
|
});
|
|
});
|
|
|
|
return Q.all(promises);
|
|
}
|
|
|
|
return Q.nfcall(registryClient.clearCache.bind(registryClient))
|
|
.then(function () {
|
|
logger.info('deleted', 'Entire registry cache', {
|
|
file: config.storage.registry
|
|
});
|
|
});
|
|
}
|
|
|
|
function clearLinks(names, config, logger) {
|
|
var promise;
|
|
var dir = config.storage.links;
|
|
|
|
// If no names are passed, grab all links
|
|
if (!names) {
|
|
promise = Q.nfcall(fs.readdir, dir)
|
|
.fail(function (err) {
|
|
if (err.code === 'ENOENT') {
|
|
return [];
|
|
}
|
|
|
|
throw err;
|
|
});
|
|
// Otherwise use passed ones
|
|
} else {
|
|
promise = Q.resolve(names);
|
|
}
|
|
|
|
return promise
|
|
.then(function (names) {
|
|
var promises;
|
|
var linksToRemove = [];
|
|
|
|
// Decide which links to delete
|
|
promises = names.map(function (name) {
|
|
var link = path.join(config.storage.links, name);
|
|
|
|
return Q.nfcall(fs.readlink, link)
|
|
.then(function (linkTarget) {
|
|
// Link exists, check if it points to a folder
|
|
// that still exists
|
|
return Q.nfcall(fs.stat, linkTarget)
|
|
.then(function (stat) {
|
|
// Target is not a folder..
|
|
if (!stat.isDirectory()) {
|
|
linksToRemove.push(link);
|
|
}
|
|
})
|
|
// Error occurred reading the link
|
|
.fail(function () {
|
|
linksToRemove.push(link);
|
|
});
|
|
// Ignore if link does not exist
|
|
}, function (err) {
|
|
if (err.code !== 'ENOENT') {
|
|
linksToRemove.push(link);
|
|
}
|
|
});
|
|
});
|
|
|
|
return Q.all(promises)
|
|
.then(function () {
|
|
var promises;
|
|
|
|
// Remove each link that was declared as invalid
|
|
promises = linksToRemove.map(function (link) {
|
|
return Q.nfcall(rimraf, link)
|
|
.then(function () {
|
|
logger.info('deleted', 'Invalid link: ' + link, {
|
|
file: link
|
|
});
|
|
});
|
|
});
|
|
|
|
return Q.all(promises);
|
|
});
|
|
});
|
|
}
|
|
|
|
function clearCompletion(config, logger) {
|
|
var dir = config.storage.completion;
|
|
|
|
return Q.nfcall(fs.stat, dir)
|
|
.then(function () {
|
|
return Q.nfcall(rimraf, dir)
|
|
.then(function () {
|
|
logger.info('deleted', 'Completion cache', {
|
|
file: dir
|
|
});
|
|
});
|
|
}, function (error) {
|
|
if (error.code !== 'ENOENT') {
|
|
throw error;
|
|
}
|
|
});
|
|
}
|
|
|
|
// -------------------
|
|
|
|
clean.line = function (argv) {
|
|
var options = clean.options(argv);
|
|
return clean(options.argv.remain.slice(2), options);
|
|
};
|
|
|
|
clean.options = function (argv) {
|
|
return cli.readOptions(argv);
|
|
};
|
|
|
|
clean.completion = function () {
|
|
// TODO:
|
|
};
|
|
|
|
module.exports = clean;
|