mirror of
https://github.com/bower/bower.git
synced 2026-02-11 22:44:58 -05:00
274 lines
7.5 KiB
JavaScript
274 lines
7.5 KiB
JavaScript
var util = require('util');
|
|
var fs = require('fs');
|
|
var path = require('path');
|
|
var events = require('events');
|
|
var mout = require('mout');
|
|
var Q = require('q');
|
|
var tmp = require('tmp');
|
|
var UnitOfWork = require('./UnitOfWork');
|
|
var config = require('./config');
|
|
var createPackage;
|
|
var createError = require('../util/createError');
|
|
|
|
var Package = function (endpoint, options) {
|
|
options = options || {};
|
|
|
|
this._endpoint = endpoint;
|
|
this._name = options.name;
|
|
this._explicitName = !!this.name;
|
|
this._range = options.range || '*';
|
|
this._unitOfWork = options.unitOfWork || new UnitOfWork();
|
|
};
|
|
|
|
util.inherits(Package, events.EventEmitter);
|
|
|
|
// -----------------
|
|
|
|
Package.prototype.getName = function () {
|
|
return this._name;
|
|
};
|
|
|
|
Package.prototype.getEndpoint = function () {
|
|
return this._endpoint;
|
|
};
|
|
|
|
Package.prototype.getRange = function () {
|
|
return this._range;
|
|
};
|
|
|
|
Package.prototype.getTempDir = function () {
|
|
return this._tempDir;
|
|
};
|
|
|
|
Package.prototype.resolve = function () {
|
|
// Throw if already resolved
|
|
if (this._resolved) {
|
|
throw createError('Package is already resolved', 'EALREADYRES');
|
|
}
|
|
|
|
// 1st - Enqueue the package in the unit of work
|
|
return this._unitOfWork.enqueue(this)
|
|
.then(function (done) {
|
|
// 2nd - Create temporary dir
|
|
return this._createTempDir()
|
|
// 3nd - Resolve self
|
|
.then(this._resolveSelf.bind(this))
|
|
// 4th - Read local rc
|
|
.then(this._readRc.bind(this))
|
|
// 5th - Read json
|
|
.then(this._readJson.bind(this))
|
|
// 6th - Parse json
|
|
.then(this._parseJson.bind(this))
|
|
// 7th - Mark as resolved & call done
|
|
// to inform the unit of work
|
|
.then(function (dependencies) {
|
|
this._resolved = true;
|
|
done();
|
|
return dependencies;
|
|
}.bind(this), function (err) {
|
|
this._resolveError = err;
|
|
done();
|
|
throw err;
|
|
}.bind(this))
|
|
// 8th - Resolve dependencies
|
|
.then(this._resolveDependencies.bind(this));
|
|
}.bind(this), function (err) {
|
|
// If error is of a duplicate package,
|
|
// copy everything from the resolved package (duplicate) to itself
|
|
if (err.code === 'EDUPL') {
|
|
mout.object.mixIn(this, err.pkg);
|
|
} else {
|
|
this._resolveError = err;
|
|
throw err;
|
|
}
|
|
});
|
|
};
|
|
|
|
Package.prototype.getResolveError = function () {
|
|
return this._resolveError;
|
|
};
|
|
|
|
Package.prototype.getJson = function () {
|
|
this._assertResolved();
|
|
return this._json;
|
|
};
|
|
|
|
Package.prototype.getDependencies = function () {
|
|
this._assertResolved();
|
|
return this._dependencies;
|
|
};
|
|
|
|
Package.prototype.install = function () {
|
|
this._assertResolved();
|
|
|
|
// TODO
|
|
};
|
|
|
|
// -----------------
|
|
|
|
Package.prototype._resolveSelf = function () {};
|
|
|
|
// -----------------
|
|
|
|
|
|
Package.prototype._createTempDir = function () {
|
|
console.log('_createTempDir');
|
|
|
|
// Resolved if cached
|
|
if (this._tempDir) {
|
|
return Q.fcall(this._tempDir);
|
|
}
|
|
|
|
return Q.nfcall(tmp.dir, {
|
|
prefix: 'bower-' + this.name + '-',
|
|
mode: parseInt('0777', 8) & (~process.umask())
|
|
})
|
|
.then(function (dir) {
|
|
this._tempDir = dir;
|
|
return dir;
|
|
}.bind(this));
|
|
};
|
|
|
|
Package.prototype._readRc = function () {
|
|
console.log('_readRc');
|
|
|
|
// Resolved if cached
|
|
if (this._rc) {
|
|
return Q.fcall(this._rc);
|
|
}
|
|
|
|
var rcFile = path.join(this.getTempDir(), '.bowerrc');
|
|
|
|
// 1nd - Read rc as string
|
|
return Q.nfcall(fs.readFile, rcFile)
|
|
// 2nd - If successfull, parse it as json
|
|
// - If the file does not exist, make it the global config
|
|
.then(function (contents) {
|
|
try {
|
|
this._rc = JSON.parse(contents);
|
|
return this._rc;
|
|
} catch (e) {
|
|
throw createError('Unable to parse local ".bowerrc" file', 'EINVJSON', {
|
|
details: 'Unable to parse JSON file "' + rcFile + '": ' + e.message
|
|
});
|
|
}
|
|
}.bind(this), function (err) {
|
|
// If the file does not exist, return the global config
|
|
if (err.code === 'ENOENT') {
|
|
return config;
|
|
}
|
|
|
|
throw err;
|
|
});
|
|
};
|
|
|
|
Package.prototype._readJson = function (rc) {
|
|
console.log('_readJson');
|
|
|
|
// Resolve if cached
|
|
if (this._json) {
|
|
return Q.fcall(this._json);
|
|
}
|
|
|
|
var jsonFile;
|
|
|
|
function read(file) {
|
|
jsonFile = file;
|
|
return Q.nfcall(fs.readFile, path.join(this.getTempDir(), file));
|
|
}
|
|
|
|
// Try package rc.json
|
|
return read.call(this, rc.json)
|
|
// Try bower.json
|
|
.then(null, read.bind(this, 'bower.json'))
|
|
// Try component.json (deprecated, remove later)
|
|
.then(null, function () {
|
|
return read.call(this, 'component.json')
|
|
.then(function (contents) {
|
|
this.emit('warn', 'Package "' + this.name + '" is using the deprecated component.json file');
|
|
return contents;
|
|
}.bind(this));
|
|
}.bind(this))
|
|
// If we got the file contents, validate them
|
|
.then(function (contents) {
|
|
// TODO: change the validation to a separate module in the bower organization
|
|
try {
|
|
this._json = JSON.parse(contents);
|
|
return this._json;
|
|
} catch (e) {
|
|
throw createError('Unable to parse local "' + path.basename(jsonFile) + '" file', 'EINVJSON', {
|
|
details: 'Unable to parse JSON file "' + jsonFile + '": ' + e.message
|
|
});
|
|
}
|
|
// Otherwise there was an error
|
|
}.bind(this), function (err) {
|
|
// If no json file was found, return an empty one
|
|
if (err.code === 'ENOENT') {
|
|
this._json = {};
|
|
return {};
|
|
}
|
|
|
|
// If we got here, the error code is something else so we throw it
|
|
throw err;
|
|
}.bind(this));
|
|
};
|
|
|
|
Package.prototype._parseJson = function (json) {
|
|
console.log('_parseJson');
|
|
|
|
// Resolve if cached
|
|
if (this._dependencies) {
|
|
return Q.fcall(this._dependencies);
|
|
}
|
|
|
|
// 1st - Check if name defined in the json is different
|
|
// Only handle it if the package name was not explicitly set
|
|
if (!this._explicitName && json.name !== this.name) {
|
|
this.name = json.name;
|
|
this.emit('name_change', this.name);
|
|
}
|
|
|
|
// 2nd - Handle ignore property
|
|
return Q.fcall(function () {
|
|
// Delete all the files specified in the ignore from the temporary directory
|
|
// TODO:
|
|
}.bind(this))
|
|
// 3rd - Handle the dependencies property
|
|
.then(function () {
|
|
var key,
|
|
promises = [];
|
|
|
|
// Read the dependencies, creating a package for each one
|
|
createPackage = createPackage || require('./createPackage');
|
|
if (json.dependencies) {
|
|
for (key in json.dependencies) {
|
|
promises.push(createPackage(json.dependencies[key], { name: key, unitOfWork: this._unitOfWork }));
|
|
}
|
|
}
|
|
|
|
// Since the create package actually returns a promise, we must resolve them all
|
|
return Q.all(promises).then(function (packages) {
|
|
this._dependencies = packages;
|
|
return packages;
|
|
}.bind(this));
|
|
});
|
|
};
|
|
|
|
|
|
Package.prototype._resolveDependencies = function (dependencies) {
|
|
console.log('_resolveDependencies');
|
|
|
|
var promises = dependencies.map(function (dep) {
|
|
return dep.resolve();
|
|
});
|
|
|
|
return Q.all(promises);
|
|
};
|
|
|
|
Package.prototype._assertResolved = function () {
|
|
if (!this._resolved) {
|
|
throw createError('Package is not yet resolved', 'ENOTRES');
|
|
}
|
|
};
|
|
|
|
module.exports = Package; |