Files
meteor/tools/package-loader.js
David Glasser 64d939acb2 Add a lot more buildmessage captures
Many of these (mostly in top level commands in commands-packages.js) are
not super well thought out: they use a new "doOrDie" helper to run some
function in a capture and exit if there are any messages.  We really
need to get a little more thoughtful about the big picture of error
handling (combining "build" errors, network errors, catalog errors,
etc). But this at least allows the addition of more buildmessage
assertions.

At the very least, this ensures that if you edit a package.js in a local
package while "meteor run" is running, that instead of crashing the tool
it properly shows the buildmessage and lets you fix the issue.
2014-08-11 17:06:28 -04:00

118 lines
4.0 KiB
JavaScript

var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var packageCache = require('./package-cache.js');
var catalog = require('./catalog.js');
var utils = require('./utils.js');
var buildmessage = require('./buildmessage.js');
var unipackage = require('./unipackage.js');
var tropohouse = require('./tropohouse.js');
// options:
// - versions: a map from package name to the version to use. or null to only
// use local packages and ignore the package versions.
// - uniloadDir: if specified, versions should be null, and this loader will
// *only* load packages that are already unipackages and are in this
// directory
exports.PackageLoader = function (options) {
var self = this;
self.versions = options.versions || null;
self.uniloadDir = options.uniloadDir;
self.constraintSolverOpts = options.constraintSolverOpts;
};
_.extend(exports.PackageLoader.prototype, {
// Given the name of a package, return a Unipackage object, or throw an
// error if the package wasn't included in the 'versions' passed on
// initalization or isn't available (for example, hasn't been
// downloaded yet).
//
// Options are:
// - throwOnError: if true (the default), throw an error if the
// package can't be found. (If false is passed for throwOnError,
// then return null if the package can't be found.) When called
// inside buildmessage.enterJob, however, instead of throwing an
// error it will record a build error and return a dummy (empty)
// package.
// XXX rename to throwOnNotFound
getPackage: function (name, options) {
var self = this;
buildmessage.assertInCapture();
options = options || {};
if (options.throwOnError === undefined) {
options.throwOnError = true;
}
var loadPath = self.getLoadPathForPackage(name);
if (! loadPath) {
if (options.throwOnError === false)
return null;
buildmessage.error("package not available: " + name);
// recover by returning a dummy (empty) package
var pkg = new unipackage.Unipackage;
pkg.initEmpty(name);
return pkg;
}
return packageCache.packageCache.loadPackageAtPath(
name, loadPath, self.constraintSolverOpts);
},
// As getPackage, but returns the path of the package that would be
// loaded rather than loading the package, and does not take any
// options. Returns null if the package is not available.
//
// XXX it's a little unfortunate that we have two functions called
// getLoadPathForPackage, one on this object (which does not take a
// version) and one on Catalog (which does). Maybe rename them to
// getPackageLoadPath / getPackageVersionLoadPath?
getLoadPathForPackage: function (name) {
var self = this;
buildmessage.assertInCapture();
if (self.uniloadDir) {
var packagePath = path.join(self.uniloadDir, name);
if (!fs.existsSync(path.join(packagePath, 'unipackage.json'))) {
return null;
}
return packagePath;
}
if (self.versions && ! _.has(self.versions, name)) {
throw new Error("no version chosen for package " + name + "?");
}
var version;
if (self.versions) {
version = self.versions[name];
} else {
version = null;
}
return catalog.complete.getLoadPathForPackage(name,
version,
self.constraintSolverOpts);
},
// Given a package name like "ddp" and an architecture, get the unibuild of
// that package at the right architecture.
getUnibuild: function (packageName, arch) {
var self = this;
buildmessage.assertInCapture();
var pkg = self.getPackage(packageName, { throwOnError: true });
return pkg.getUnibuildAtArch(arch);
},
downloadMissingPackages: function (options) {
var self = this;
options = options || {};
// We can only download packages if we know what versions they are.
if (!self.versions)
return;
tropohouse.default.downloadMissingPackages(self.versions, {
serverArch: options.serverArch
});
}
});