mirror of
https://github.com/bower/bower.git
synced 2026-01-14 08:47:54 -05:00
253 lines
6.3 KiB
JavaScript
253 lines
6.3 KiB
JavaScript
var fs = require('../../util/fs');
|
|
var path = require('path');
|
|
var Q = require('q');
|
|
var tmp = require('tmp');
|
|
var mkdirp = require('mkdirp');
|
|
var rimraf = require('../../util/rimraf');
|
|
var readJson = require('../../util/readJson');
|
|
var createError = require('../../util/createError');
|
|
var removeIgnores = require('../../util/removeIgnores');
|
|
var md5 = require('md5-hex');
|
|
|
|
tmp.setGracefulCleanup();
|
|
|
|
function Resolver(decEndpoint, config, logger) {
|
|
this._source = decEndpoint.source;
|
|
this._target = decEndpoint.target || '*';
|
|
this._name = decEndpoint.name || path.basename(this._source);
|
|
|
|
this._config = config;
|
|
this._logger = logger;
|
|
|
|
this._guessedName = !decEndpoint.name;
|
|
}
|
|
|
|
// -----------------
|
|
|
|
Resolver.prototype.getSource = function() {
|
|
return this._source;
|
|
};
|
|
|
|
Resolver.prototype.getName = function() {
|
|
return this._name;
|
|
};
|
|
|
|
Resolver.prototype.getTarget = function() {
|
|
return this._target;
|
|
};
|
|
|
|
Resolver.prototype.getTempDir = function() {
|
|
return this._tempDir;
|
|
};
|
|
|
|
Resolver.prototype.getPkgMeta = function() {
|
|
return this._pkgMeta;
|
|
};
|
|
|
|
Resolver.prototype.hasNew = function(pkgMeta) {
|
|
var promise;
|
|
var that = this;
|
|
|
|
// If already working, error out
|
|
if (this._working) {
|
|
return Q.reject(createError('Already working', 'EWORKING'));
|
|
}
|
|
|
|
this._working = true;
|
|
|
|
// Avoid reading the package meta if already given
|
|
promise = this._hasNew(pkgMeta);
|
|
|
|
return promise.fin(function() {
|
|
that._working = false;
|
|
});
|
|
};
|
|
|
|
Resolver.prototype.resolve = function() {
|
|
var that = this;
|
|
|
|
// If already working, error out
|
|
if (this._working) {
|
|
return Q.reject(createError('Already working', 'EWORKING'));
|
|
}
|
|
|
|
this._working = true;
|
|
|
|
// Create temporary dir
|
|
return (
|
|
this._createTempDir()
|
|
// Resolve self
|
|
.then(this._resolve.bind(this))
|
|
// Read json, generating the package meta
|
|
.then(this._readJson.bind(this, null))
|
|
// Apply and save package meta
|
|
.then(function(meta) {
|
|
return that
|
|
._applyPkgMeta(meta)
|
|
.then(that._savePkgMeta.bind(that, meta));
|
|
})
|
|
.then(
|
|
function() {
|
|
// Resolve with the folder
|
|
return that._tempDir;
|
|
},
|
|
function(err) {
|
|
// If something went wrong, unset the temporary dir
|
|
that._tempDir = null;
|
|
throw err;
|
|
}
|
|
)
|
|
.fin(function() {
|
|
that._working = false;
|
|
})
|
|
);
|
|
};
|
|
|
|
Resolver.prototype.isCacheable = function() {
|
|
// Bypass cache for local dependencies
|
|
if (
|
|
this._source &&
|
|
/^(?:file:[\/\\]{2}|[A-Z]:)?\.?\.?[\/\\]/.test(this._source)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// We don't want to cache moving targets like branches
|
|
if (
|
|
this._pkgMeta &&
|
|
this._pkgMeta._resolution &&
|
|
this._pkgMeta._resolution.type === 'branch'
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
// -----------------
|
|
|
|
// Abstract functions that must be implemented by concrete resolvers
|
|
Resolver.prototype._resolve = function() {
|
|
throw new Error('_resolve not implemented');
|
|
};
|
|
|
|
// Abstract functions that can be re-implemented by concrete resolvers
|
|
// as necessary
|
|
Resolver.prototype._hasNew = function(pkgMeta) {
|
|
return Q.resolve(true);
|
|
};
|
|
|
|
Resolver.isTargetable = function() {
|
|
return true;
|
|
};
|
|
|
|
Resolver.versions = function(source) {
|
|
return Q.resolve([]);
|
|
};
|
|
|
|
Resolver.clearRuntimeCache = function() {};
|
|
|
|
// -----------------
|
|
|
|
Resolver.prototype._createTempDir = function() {
|
|
return Q.nfcall(mkdirp, this._config.tmp)
|
|
.then(
|
|
function() {
|
|
return Q.nfcall(tmp.dir, {
|
|
template: path.join(
|
|
this._config.tmp,
|
|
md5(this._name) + '-' + process.pid + '-XXXXXX'
|
|
),
|
|
mode: 0777 & ~process.umask(),
|
|
unsafeCleanup: true
|
|
});
|
|
}.bind(this)
|
|
)
|
|
.then(
|
|
function(dir) {
|
|
// nfcall may return multiple callback arguments as an array
|
|
return (this._tempDir = Array.isArray(dir) ? dir[0] : dir);
|
|
}.bind(this)
|
|
);
|
|
};
|
|
|
|
Resolver.prototype._cleanTempDir = function() {
|
|
var tempDir = this._tempDir;
|
|
|
|
if (!tempDir) {
|
|
return Q.resolve();
|
|
}
|
|
|
|
// Delete and create folder
|
|
return Q.nfcall(rimraf, tempDir)
|
|
.then(function() {
|
|
return Q.nfcall(mkdirp, tempDir, 0777 & ~process.umask());
|
|
})
|
|
.then(function() {
|
|
return tempDir;
|
|
});
|
|
};
|
|
|
|
Resolver.prototype._readJson = function(dir) {
|
|
var that = this;
|
|
|
|
dir = dir || this._tempDir;
|
|
return readJson(dir, {
|
|
assume: { name: this._name },
|
|
logger: that._logger
|
|
}).spread(function(json, deprecated) {
|
|
if (deprecated) {
|
|
that._logger.warn(
|
|
'deprecated',
|
|
'Package ' +
|
|
that._name +
|
|
' is using the deprecated ' +
|
|
deprecated
|
|
);
|
|
}
|
|
|
|
return json;
|
|
});
|
|
};
|
|
|
|
Resolver.prototype._applyPkgMeta = function(meta) {
|
|
// Check if name defined in the json is different
|
|
// If so and if the name was "guessed", assume the json name
|
|
if (meta.name !== this._name && this._guessedName) {
|
|
this._name = meta.name;
|
|
}
|
|
|
|
// Handle ignore property, deleting all files from the temporary directory
|
|
// If no ignores were specified, simply resolve
|
|
if (!meta.ignore || !meta.ignore.length) {
|
|
return Q.resolve(meta);
|
|
}
|
|
|
|
// Otherwise remove them from the temp dir
|
|
return removeIgnores(this._tempDir, meta).then(function() {
|
|
return meta;
|
|
});
|
|
};
|
|
|
|
Resolver.prototype._savePkgMeta = function(meta) {
|
|
var that = this;
|
|
var contents;
|
|
|
|
// Store original source & target
|
|
meta._source = this._source;
|
|
meta._target = this._target;
|
|
|
|
// Stringify contents
|
|
contents = JSON.stringify(meta, null, 2);
|
|
|
|
return Q.nfcall(
|
|
fs.writeFile,
|
|
path.join(this._tempDir, '.bower.json'),
|
|
contents
|
|
).then(function() {
|
|
return (that._pkgMeta = meta);
|
|
});
|
|
};
|
|
|
|
module.exports = Resolver;
|