mirror of
https://github.com/bower/bower.git
synced 2026-01-13 16:28:05 -05:00
Sometimes it return ENOENT instead of ENODIR for normal files. This broke code paths in few places. Also, see: https://github.com/isaacs/chmodr/pull/8
186 lines
5.6 KiB
JavaScript
186 lines
5.6 KiB
JavaScript
var fs = require('../../util/fs');
|
|
var path = require('path');
|
|
var mout = require('mout');
|
|
var Q = require('q');
|
|
var rimraf = require('../../util/rimraf');
|
|
var endpointParser = require('bower-endpoint-parser');
|
|
var PackageRepository = require('../../core/PackageRepository');
|
|
var semver = require('../../util/semver');
|
|
var defaultConfig = require('../../config');
|
|
|
|
function clean(logger, endpoints, options, config) {
|
|
var decEndpoints;
|
|
var names;
|
|
|
|
options = options || {};
|
|
config = defaultConfig(config);
|
|
|
|
// If endpoints is an empty array, null them
|
|
if (endpoints && !endpoints.length) {
|
|
endpoints = null;
|
|
}
|
|
|
|
// Generate decomposed endpoints and names based on the endpoints
|
|
if (endpoints) {
|
|
decEndpoints = endpoints.map(function (endpoint) {
|
|
return endpointParser.decompose(endpoint);
|
|
});
|
|
names = decEndpoints.map(function (decEndpoint) {
|
|
return decEndpoint.name || decEndpoint.source;
|
|
});
|
|
}
|
|
|
|
return Q.all([
|
|
clearPackages(decEndpoints, config, logger),
|
|
clearLinks(names, config, logger)
|
|
])
|
|
.spread(function (entries) {
|
|
return entries;
|
|
});
|
|
}
|
|
|
|
function clearPackages(decEndpoints, config, logger) {
|
|
var repository = new PackageRepository(config, logger);
|
|
|
|
return repository.list()
|
|
.then(function (entries) {
|
|
var promises;
|
|
|
|
// Filter entries according to the specified packages
|
|
if (decEndpoints) {
|
|
entries = entries.filter(function (entry) {
|
|
return !!mout.array.find(decEndpoints, function (decEndpoint) {
|
|
var entryPkgMeta = entry.pkgMeta;
|
|
|
|
// Check if name or source match the entry
|
|
if (decEndpoint.name !== entryPkgMeta.name &&
|
|
decEndpoint.source !== entryPkgMeta.name &&
|
|
decEndpoint.source !== entryPkgMeta._source
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// If target is a wildcard, simply return true
|
|
if (decEndpoint.target === '*') {
|
|
return true;
|
|
}
|
|
|
|
// If it's a semver target, compare using semver spec
|
|
if (semver.validRange(decEndpoint.target)) {
|
|
return semver.satisfies(entryPkgMeta.version, decEndpoint.target);
|
|
}
|
|
|
|
// Otherwise, compare against target/release
|
|
return decEndpoint.target === entryPkgMeta._target ||
|
|
decEndpoint.target === entryPkgMeta._release;
|
|
});
|
|
});
|
|
}
|
|
|
|
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 (!decEndpoints) {
|
|
// Ensure that everything is cleaned,
|
|
// even invalid packages in the cache
|
|
return repository.clear();
|
|
}
|
|
})
|
|
.then(function () {
|
|
return entries;
|
|
});
|
|
});
|
|
}
|
|
|
|
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);
|
|
});
|
|
});
|
|
}
|
|
|
|
// -------------------
|
|
|
|
clean.readOptions = function (argv) {
|
|
var cli = require('../../util/cli');
|
|
var options = cli.readOptions(argv);
|
|
var endpoints = options.argv.remain.slice(2);
|
|
|
|
delete options.argv;
|
|
|
|
return [endpoints, options];
|
|
};
|
|
|
|
module.exports = clean;
|