Files
bower/lib/commands/cache/clean.js
2013-07-06 11:28:08 +01:00

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;