Current File : //lib/node_modules/bower/lib/core/resolvers/FsResolver.js |
var util = require('util');
var fs = require('../../util/fs');
var path = require('path');
var mout = require('mout');
var Q = require('q');
var junk = require('junk');
var Resolver = require('./Resolver');
var copy = require('../../util/copy');
var extract = require('../../util/extract');
var createError = require('../../util/createError');
function FsResolver(decEndpoint, config, logger) {
Resolver.call(this, decEndpoint, config, logger);
// Ensure absolute path
this._source = path.resolve(this._config.cwd, this._source);
// If target was specified, simply reject the promise
if (this._target !== '*') {
throw createError(
"File system sources can't resolve targets",
'ENORESTARGET'
);
}
// If the name was guessed
if (this._guessedName) {
// Remove extension
this._name = this._name.substr(
0,
this._name.length - path.extname(this._name).length
);
}
}
util.inherits(FsResolver, Resolver);
mout.object.mixIn(FsResolver, Resolver);
// -----------------
FsResolver.isTargetable = function() {
return false;
};
// TODO: Should we store latest mtimes in the resolution and compare?
// This would be beneficial when copying big files/folders
// TODO: There's room for improvement by using streams if the source
// is an archive file, by piping read stream to the zip extractor
// This will likely increase the complexity of code but might worth it
FsResolver.prototype._resolve = function() {
return this._copy()
.then(this._extract.bind(this))
.then(this._rename.bind(this));
};
// -----------------
FsResolver.prototype._copy = function() {
var that = this;
return Q.nfcall(fs.stat, this._source).then(function(stat) {
var dst;
var copyOpts;
var promise;
that._sourceStat = stat;
copyOpts = { mode: stat.mode };
// If it's a folder
if (stat.isDirectory()) {
dst = that._tempDir;
// Read the bower.json inside the folder, so that we
// copy only the necessary files if it has ignore specified
promise = that
._readJson(that._source)
.then(function(json) {
copyOpts.ignore = json.ignore;
return copy.copyDir(that._source, dst, copyOpts);
})
.then(function() {
// Resolve to null because it's a dir
return;
});
// Else it's a file
} else {
dst = path.join(that._tempDir, path.basename(that._source));
promise = copy
.copyFile(that._source, dst, copyOpts)
.then(function() {
return dst;
});
}
that._logger.action('copy', that._source, {
src: that._source,
dst: dst
});
return promise;
});
};
FsResolver.prototype._extract = function(file) {
if (!file || !extract.canExtract(file)) {
return Q.resolve();
}
this._logger.action('extract', path.basename(this._source), {
archive: file,
to: this._tempDir
});
return extract(file, this._tempDir);
};
FsResolver.prototype._rename = function() {
return Q.nfcall(fs.readdir, this._tempDir).then(
function(files) {
var file;
var oldPath;
var newPath;
// Remove any OS specific files from the files array
// before checking its length
files = files.filter(junk.isnt);
// Only rename if there's only one file and it's not the json
if (
files.length === 1 &&
!/^(bower|component)\.json$/.test(files[0])
) {
file = files[0];
this._singleFile = 'index' + path.extname(file);
oldPath = path.join(this._tempDir, file);
newPath = path.join(this._tempDir, this._singleFile);
return Q.nfcall(fs.rename, oldPath, newPath);
}
}.bind(this)
);
};
FsResolver.prototype._savePkgMeta = function(meta) {
// Store main if is a single file
if (this._singleFile) {
meta.main = this._singleFile;
}
return Resolver.prototype._savePkgMeta.call(this, meta);
};
module.exports = FsResolver;