Files
meteor/tools/package-loader.js
ekatek e0414f2ed5 allow user to mark packages as debugOnly and not have them bundle in production mode
(still outstanding: changes to package publication workflow)

A package marked debugOnly in the package source is not to be bundled in production.
Moreover, if a package/app depends on a debugOnly package, that entire tree should
not be bundled. (But we should take it into account when figuring out versions!)

Does the following:

- In the catalog, we have a function that takes in a set of versions and a set of original
constraints and traverses it, recursively, to build a subset of versions that we *should*
bundle, and the corresponding subset of versions that we shouldn't (because they are either
debugOnly themselves or pulled in by debugOnly packages). (We do this in the catalog because
it is an addon onto the results of the constraint solver, tied deeply into our representation
of data)

- In the packageLoader, we keep track packages & versions that we should bundle, and also,
packages that we should exclude. We do this in the package-loader because, essentially, that's the
object that we use to keep the results of the constraint-solver, and we already propagate it to all
functions that care about it. (Possibly we should subsequently rename it later).

- In the compiler, when we figure out buildTimeDependencies, we ask if we need to bundle debug
builds. If not, we filter them out (see above). Also, when we actually build together unibuilds,
we don't touch the ones that the packageloader tells us to exclude (which ensures that they don't make
it into the final product).

- In the project, we keep track of whether this project is building in debug mode. That's because the project
is where we keep the state of our curent project that we are building, and if we are ever in the state of
building multiple things, then that's the code that we would need to touch (see also that we make a similar
assumption when solving constraints).

- Adds the option to keepthe project debug-build-free and calls it in commands when approporiate.
2014-10-07 15:55:50 -07:00

130 lines
4.6 KiB
JavaScript

var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var catalog = require('./catalog.js');
var utils = require('./utils.js');
var buildmessage = require('./buildmessage.js');
var isopack = require('./isopack.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.
exports.PackageLoader = function (options) {
var self = this;
if (!options.catalog)
throw Error("Must specify a catalog");
self.versions = null;
// Ignore specified versions if we're doing this as part of uniload.
// The PackageLoader created in uniload.js will not specify a versions option,
// but other PackageLoaders (eg, created to build plugins in compiler.compile)
// might, but we should ignore that since uniload never loads versioned
// packages; it only loads precompiled packages (for built releases) or local
//packages (from checkout).
if (options.versions && options.catalog !== catalog.uniload)
self.versions = options.versions;
self.uniloadDir = options.uniloadDir;
self.constraintSolverOpts = options.constraintSolverOpts;
self.catalog = options.catalog;
self.excluded = options.excluded;
};
_.extend(exports.PackageLoader.prototype, {
// Given the name of a package, return a Isopack 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 isopack.Isopack;
pkg.initEmpty(name);
return pkg;
}
return self.catalog.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.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 self.catalog.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;
// We shouldn't ever download packages for uniload.
if (self.catalog === catalog.uniload)
return;
tropohouse.default.downloadMissingPackages(self.versions, {
serverArch: options.serverArch
});
},
// Sometimes, we have figured out the versions for packages, but we have no
// intention of loading them. In this case, they are considered 'excluded
// packages'. This function lets us know if we have hit one of those.
excludedPackage: function (packageName) {
var self = this;
return self.excluded && self.excluded[packageName];
}
});