mirror of
https://github.com/bower/bower.git
synced 2026-02-11 22:44:58 -05:00
Walk towards finishing FsResolver.
This commit is contained in:
@@ -152,18 +152,9 @@ Resolver.prototype._applyPkgMeta = function (meta) {
|
||||
if (meta.ignore && meta.ignore.length) {
|
||||
return Q.nfcall(glob, '**/*', { cwd: this._tempDir, dot: true, mark: true })
|
||||
.then(function (files) {
|
||||
var filter = this._createIgnoreFilter(meta.ignore),
|
||||
promises = [];
|
||||
var promises = [];
|
||||
|
||||
// For each file that passes the ignore filter,
|
||||
// rimraf it
|
||||
files.forEach(function (file) {
|
||||
if (filter(file)) {
|
||||
promises.push(Q.nfcall(rimraf, file));
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for all the rimraf's to finish
|
||||
// TODO
|
||||
return Q.all(promises);
|
||||
}.bind(this))
|
||||
.then(function () {
|
||||
@@ -183,12 +174,4 @@ Resolver.prototype._savePkgMeta = function (meta) {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Resolver.prototype._createIgnoreFilter = function (ignore) {
|
||||
var list = pathspec.RelPathList.parse(ignore);
|
||||
|
||||
return function (filename) {
|
||||
return list.matches(filename);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Resolver;
|
||||
@@ -1,33 +1,80 @@
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Resolver = require('../Resolver');
|
||||
var copy = require('../../util/copy');
|
||||
var extract = require('../../util/extract');
|
||||
var createError = require('../../util/createError');
|
||||
|
||||
var FsResolver = function (source, options) {
|
||||
// Ensure absolute path
|
||||
source = path.resolve(source);
|
||||
|
||||
Resolver.call(this, source, options);
|
||||
};
|
||||
|
||||
util.inherits(FsResolver, Resolver);
|
||||
mout.object.mixIn(FsResolver, Resolver);
|
||||
|
||||
// -----------------
|
||||
|
||||
FsResolver.prototype.hasNew = function (canonicalPkg) {
|
||||
// If target was specified, simply reject the promise
|
||||
if (this._target !== '*') {
|
||||
return Q.reject(createError('File system sources can\'t resolve targets ("' + this._target + '")', 'ENORESTARGET'));
|
||||
}
|
||||
|
||||
// TODO: should we store latest modified files in the resolution and compare?
|
||||
return Q.resolve(true);
|
||||
};
|
||||
|
||||
FsResolver.prototype._resolveSelf = function () {
|
||||
return this._copy()
|
||||
// If target was specified, simply reject the promise
|
||||
if (this._target !== '*') {
|
||||
return Q.reject(createError('File system sources can\'t resolve targets ("' + this._target + '")', 'ENORESTARGET'));
|
||||
}
|
||||
|
||||
return this._readJson(this._source)
|
||||
.then(this._copy.bind(this))
|
||||
.then(this._extract.bind(this));
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
FsResolver.prototype._copy = function () {
|
||||
FsResolver.prototype._copy = function (meta) {
|
||||
return Q.nfcall(fs.stat, this._source)
|
||||
.then(function (stat) {
|
||||
var dstFile,
|
||||
copyOpts;
|
||||
|
||||
// Pass in the ignore to the copy options to avoid copying ignore files
|
||||
// Also, pass in the mode to avoid additional stat calls when copying
|
||||
copyOpts = {
|
||||
mode: stat.mode,
|
||||
ignore: meta.ignore
|
||||
};
|
||||
|
||||
// If it's a folder
|
||||
if (stat.isDirectory()) {
|
||||
return copy.copyDir(this._source, this._tempDir, copyOpts);
|
||||
}
|
||||
|
||||
// If it's a file
|
||||
// We pass the mode to avoid additional stat calls
|
||||
dstFile = path.join(this._tempDir, path.basename(this._source));
|
||||
return copy.copyFile(this._source, dstFile, copyOpts);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
FsResolver.prototype._extract = function () {
|
||||
|
||||
return extract.canExtract(this._source)
|
||||
.then(function (canExtract) {
|
||||
if (canExtract) {
|
||||
return extract(this._tempDir);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = FsResolver;
|
||||
@@ -2,8 +2,8 @@ var util = require('util');
|
||||
var fs = require('fs');
|
||||
var Q = require('q');
|
||||
var mout = require('mout');
|
||||
var ncp = require('ncp');
|
||||
var GitResolver = require('./GitResolver');
|
||||
var copy = require('../../util/copy');
|
||||
var cmd = require('../../util/cmd');
|
||||
var path = require('path');
|
||||
|
||||
@@ -20,15 +20,7 @@ mout.object.mixIn(GitFsResolver, GitResolver);
|
||||
// -----------------
|
||||
|
||||
GitFsResolver.prototype._copy = function () {
|
||||
// Copy folder permissions
|
||||
return Q.nfcall(fs.stat, this._source)
|
||||
.then(function (stat) {
|
||||
return Q.nfcall(fs.chmod, this._tempDir, stat.mode);
|
||||
}.bind(this))
|
||||
// Copy folder contents
|
||||
.then(function () {
|
||||
return Q.nfcall(ncp, this._source, this._tempDir);
|
||||
}.bind(this));
|
||||
return copy.copyDir(this._source, this._tempDir);
|
||||
};
|
||||
|
||||
// Override the checkout function to work with the local copy
|
||||
|
||||
117
lib/util/copy.js
Normal file
117
lib/util/copy.js
Normal file
@@ -0,0 +1,117 @@
|
||||
var fstream = require('fstream');
|
||||
var fstreamIgnore = require('fstream-ignore');
|
||||
var fs = require('fs');
|
||||
var Q = require('q');
|
||||
|
||||
function copy(reader, writer) {
|
||||
var deferred = Q.defer(),
|
||||
ignore,
|
||||
finish;
|
||||
|
||||
finish = function (err) {
|
||||
writer.removeAllListeners();
|
||||
reader.removeAllListeners();
|
||||
|
||||
// If we got an error, simply reject the deferred
|
||||
if (err) {
|
||||
return deferred.reject(err);
|
||||
}
|
||||
|
||||
return deferred.resolve();
|
||||
};
|
||||
|
||||
// Reader
|
||||
if (reader.type === 'Directory' && reader.ignore) {
|
||||
ignore = reader.ignore;
|
||||
reader = fstreamIgnore(reader);
|
||||
reader.addIgnoreRules(ignore);
|
||||
} else {
|
||||
reader = fstream.Reader(reader);
|
||||
}
|
||||
|
||||
reader.on('error', finish);
|
||||
|
||||
// Writer
|
||||
writer = fstream.Writer(writer)
|
||||
.on('error', finish)
|
||||
.on('close', finish);
|
||||
|
||||
// Finally pipe reader to writer
|
||||
reader.pipe(writer);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function copyMode(src, dst) {
|
||||
return Q.nfcall(fs.stat, src)
|
||||
.then(function (stat) {
|
||||
return Q.nfcall(fs.chmod, dst, stat.mode);
|
||||
});
|
||||
}
|
||||
|
||||
function parseOptions(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
if (opts.mode != null) {
|
||||
opts.copyMode = false;
|
||||
} else if (opts.copyMode == null) {
|
||||
opts.copyMode = true;
|
||||
}
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
|
||||
// Available options:
|
||||
// - mode: force final mode of dest
|
||||
// - copyMode: copy mode of src to dest (only if mode is not specified)
|
||||
function copyFile(src, dst, opts) {
|
||||
var promise;
|
||||
|
||||
opts = parseOptions(opts);
|
||||
|
||||
promise = copy({
|
||||
path: src,
|
||||
type: 'File'
|
||||
}, {
|
||||
path: dst,
|
||||
mode: opts.mode,
|
||||
type: 'File'
|
||||
});
|
||||
|
||||
if (opts.copyMode) {
|
||||
promise = promise.then(copyMode.bind(copyMode, src, dst));
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Available options:
|
||||
// - ignore: array of patterns to be ignored
|
||||
// - mode: force final mode of dest
|
||||
// - copyMode: copy mode of src to dest (only if mode is not specified)
|
||||
function copyDir(src, dst, opts) {
|
||||
var promise;
|
||||
|
||||
opts = parseOptions(opts);
|
||||
|
||||
promise = copy({
|
||||
path: src,
|
||||
type: 'Directory',
|
||||
ignore: opts.ignore
|
||||
}, {
|
||||
path: dst,
|
||||
mode: opts.mode,
|
||||
type: 'Directory'
|
||||
});
|
||||
|
||||
if (opts.copyMode) {
|
||||
promise = promise.then(copyMode.bind(copyMode, src, dst));
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
module.exports.copyDir = copyDir;
|
||||
module.exports.copyFile = copyFile;
|
||||
151
lib/util/extract.js
Normal file
151
lib/util/extract.js
Normal file
@@ -0,0 +1,151 @@
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var zlib = require('zlib');
|
||||
var unzip = require('unzip');
|
||||
var tar = require('tar');
|
||||
var Q = require('Q');
|
||||
var mout = require('mout');
|
||||
|
||||
var extractors = {
|
||||
'.zip': extractZip,
|
||||
'.tar': extractTar,
|
||||
'.tar.gz': extractTarGz
|
||||
};
|
||||
var extractorTypes = Object.keys(extractors);
|
||||
|
||||
function extractZip(archive, dest) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
fs.createReadStream(archive)
|
||||
.pipe(unzip.Extract({ path: this.path }))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dest));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function extractTar(archive, dest) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
fs.createReadStream(archive)
|
||||
.pipe(tar.Extract({ path: this.path }))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dest));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function extractTarGz(archive, dest) {
|
||||
var deferred = Q.defer();
|
||||
|
||||
fs.createReadStream(archive)
|
||||
.pipe(zlib.createGunzip())
|
||||
.pipe(tar.Extract({ path: this.path }))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', deferred.resolve.bind(deferred, dest));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getExtractor(archive) {
|
||||
var type = mout.array.find(extractorTypes, function (type) {
|
||||
return mout.string.endsWith(archive, type);
|
||||
});
|
||||
|
||||
return type ? extractors[type] : null;
|
||||
}
|
||||
|
||||
function isSingleDir(dir) {
|
||||
return Q.nfcall(fs.readdir, dir)
|
||||
.then(function (files) {
|
||||
var dir;
|
||||
|
||||
if (files.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dir = files[0];
|
||||
|
||||
return Q.nfcall(fs.stat, dir)
|
||||
.then(function (stat) {
|
||||
return !stat.isDirectory() ? files[0] : false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function moveSingleDirContents(dir) {
|
||||
var destDir = path.dirname(dir);
|
||||
|
||||
return Q.nfcall(fs.readdir, dir)
|
||||
.then(function (files) {
|
||||
var promises;
|
||||
|
||||
promises = files.map(function (file) {
|
||||
var src = path.join(dir, file),
|
||||
dest = path.join(destDir, file);
|
||||
|
||||
return Q.nfcall(fs.rename, src, dest);
|
||||
});
|
||||
|
||||
return Q.all(promises);
|
||||
})
|
||||
.then(function () {
|
||||
return Q.rmdir(dir);
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
|
||||
function extract(archive, dest, options) {
|
||||
var extractor,
|
||||
promise;
|
||||
|
||||
options = options || {};
|
||||
extractor = getExtractor(options.extension || archive);
|
||||
|
||||
// If extractor is null, then the archive type is unknown
|
||||
if (!extractor) {
|
||||
return Q.reject(new Error('File "' + archive + '" is not a known archive'));
|
||||
}
|
||||
|
||||
// Extract archive
|
||||
promise = extractor(archive, dest);
|
||||
|
||||
// Remove archive
|
||||
if (!options.keepArchive) {
|
||||
promise = promise
|
||||
.then(function () {
|
||||
return Q.nfcall(fs.unlink, archive);
|
||||
});
|
||||
}
|
||||
|
||||
// Move contents if a single directory was extracted
|
||||
if (!options.keepStructure) {
|
||||
promise = promise
|
||||
.then(function () {
|
||||
return isSingleDir(dest);
|
||||
})
|
||||
.then(function (singleDir) {
|
||||
return singleDir ? moveSingleDirContents(singleDir) : null;
|
||||
});
|
||||
}
|
||||
|
||||
// Resolve promise to the dest dir
|
||||
return promise.then(function () {
|
||||
return dest;
|
||||
});
|
||||
}
|
||||
|
||||
function canExtract(archive) {
|
||||
if (!getExtractor(archive)) {
|
||||
return Q.resolve(false);
|
||||
}
|
||||
|
||||
return Q.nfcall(fs.stat, archive)
|
||||
.then(function (stat) {
|
||||
return stat.isFile();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = extract;
|
||||
module.exports.canExtract = canExtract;
|
||||
Reference in New Issue
Block a user