Merge branch 'devel' into release-0.9.4

Conflicts:
	docs/client/data.js
This commit is contained in:
Sashko Stubailo
2014-09-29 10:39:05 -07:00
23 changed files with 520 additions and 61 deletions

View File

@@ -3587,6 +3587,9 @@ package is exported to.
{{> autoApiBox "PackageAPI#export" }}
{{> autoApiBox "PackageAPI#addFiles" }}
{{> autoApiBox "Package.registerBuildPlugin"}}
{{> autoApiBox "Plugin.registerSourceHandler"}}
<h3 id="packagetests"><span>Unit Tests</span></h3>
{{#markdown}}

File diff suppressed because one or more lines are too long

View File

@@ -392,7 +392,10 @@ var toc = [
{name: "Package.onTest", id: "packagetests"},
{name: "Npm.depends", id: "Npm-depends"},
{name: "Npm.require", id: "Npm-require"},
{name: "Cordova.depends", id: "Cordova-depends"}
{name: "Cordova.depends", id: "Cordova-depends"},
{name: "Package.registerBuildPlugin", id: "Package-registerBuildPlugin"}, [
{name: "Plugin.registerSourceHandler", id: "Plugin-registerSourceHandler"}
]
]
],

View File

@@ -48,6 +48,22 @@
"Blaze.renderWithData",
"Blaze.toHTML",
"Blaze.toHTMLWithData",
"CompileStep",
"CompileStep#addAsset",
"CompileStep#addHtml",
"CompileStep#addJavaScript",
"CompileStep#addStylesheet",
"CompileStep#arch",
"CompileStep#declaredExports",
"CompileStep#error",
"CompileStep#fileOptions",
"CompileStep#fullInputPath",
"CompileStep#inputPath",
"CompileStep#inputSize",
"CompileStep#packageName",
"CompileStep#pathForSourceMap",
"CompileStep#read",
"CompileStep#rootOutputPath",
"Cordova",
"Cordova.depends",
"DDP.connect",
@@ -135,12 +151,15 @@
"Package.describe",
"Package.onTest",
"Package.onUse",
"Package.registerBuildPlugin",
"PackageAPI",
"PackageAPI#addFiles",
"PackageAPI#export",
"PackageAPI#imply",
"PackageAPI#use",
"PackageAPI#versionsFrom",
"Plugin",
"Plugin.registerSourceHandler",
"ReactiveVar",
"ReactiveVar#get",
"ReactiveVar#set",

2
meteor
View File

@@ -1,6 +1,6 @@
#!/bin/bash
BUNDLE_VERSION=0.3.55
BUNDLE_VERSION=0.3.55 # XXX: 0.3.56 is used on the cordova-0.9.4 branch
# OS Check. Put here because here is where we download the precompiled
# bundles that are arch specific.

View File

@@ -64,7 +64,7 @@ Blaze.View.prototype.lookup = function (name, _options) {
} else if (lookupTemplate && (name in Blaze.Template) &&
(Blaze.Template[name] instanceof Blaze.Template)) {
return Blaze.Template[name];
} else if (Blaze._globalHelpers[name]) {
} else if (Blaze._globalHelpers[name] != null) {
return wrapHelper(bindDataContext(Blaze._globalHelpers[name]));
} else {
return function () {

View File

@@ -147,7 +147,7 @@ _.extend(Meteor, {
var warnedAboutWrapAsync = false;
/**
* @deprecated in 1.0.0
* @deprecated in 0.9.3
*/
Meteor._wrapAsync = function(fn, context) {
if (! warnedAboutWrapAsync) {

View File

@@ -1,9 +1,9 @@
UglifyJSMinify = Npm.require('uglify-js').minify;
var cssParse = Npm.require('css-parse');
var cssStringify = Npm.require('css-stringify');
var path = Npm.require('path');
var url = Npm.require('url');
UglifyJS = Npm.require('uglify-js');
UglifyJSMinify = UglifyJS.minify;
CssTools = {
parseCss: cssParse,

View File

@@ -11,7 +11,7 @@ Npm.depends({
Package.on_use(function (api) {
api.use('underscore', 'server');
api.export(['CssTools', 'UglifyJSMinify']);
api.export(['CssTools', 'UglifyJSMinify', 'UglifyJS']);
api.add_files(['minification.js', 'minifiers.js'], 'server');
});

View File

@@ -1610,28 +1610,28 @@ var runOneTwoTest = function (test, subTemplateName, optionsData) {
};
Tinytest.add('spacebars-tests - old - template_tests - with stops without re-running helper', function (test) {
runOneTwoTest(test, 'spacebars_test_helpers_stop_with');
runOneTwoTest(test, 'old_spacebars_test_helpers_stop_with');
});
Tinytest.add('spacebars-tests - old - template_tests - each stops without re-running helper', function (test) {
runOneTwoTest(test, 'spacebars_test_helpers_stop_each');
runOneTwoTest(test, 'old_spacebars_test_helpers_stop_each');
});
Tinytest.add('spacebars-tests - old - template_tests - each inside with stops without re-running helper', function (test) {
runOneTwoTest(test, 'spacebars_test_helpers_stop_with_each');
runOneTwoTest(test, 'old_spacebars_test_helpers_stop_with_each');
});
Tinytest.add('spacebars-tests - old - template_tests - if stops without re-running helper', function (test) {
runOneTwoTest(test, 'spacebars_test_helpers_stop_if', ['a', 'b', 'a']);
runOneTwoTest(test, 'old_spacebars_test_helpers_stop_if', ['a', 'b', 'a']);
});
Tinytest.add('spacebars-tests - old - template_tests - unless stops without re-running helper', function (test) {
runOneTwoTest(test, 'spacebars_test_helpers_stop_unless', ['a', 'b', 'a']);
runOneTwoTest(test, 'old_spacebars_test_helpers_stop_unless', ['a', 'b', 'a']);
});
Tinytest.add('spacebars-tests - old - template_tests - inclusion stops without re-running function', function (test) {
var t = Template.old_spacebars_test_helpers_stop_inclusion3;
runOneTwoTest(test, 'spacebars_test_helpers_stop_inclusion', [t, t, t]);
runOneTwoTest(test, 'old_spacebars_test_helpers_stop_inclusion', [t, t, t]);
});
Tinytest.add('spacebars-tests - old - template_tests - template with callbacks inside with stops without recalculating data', function (test) {
@@ -1639,7 +1639,7 @@ Tinytest.add('spacebars-tests - old - template_tests - template with callbacks i
tmpl.created = function () {};
tmpl.rendered = function () {};
tmpl.destroyed = function () {};
runOneTwoTest(test, 'spacebars_test_helpers_stop_with_callbacks');
runOneTwoTest(test, 'old_spacebars_test_helpers_stop_with_callbacks');
});
Tinytest.add('spacebars-tests - old - template_tests - no data context is seen as an empty object', function (test) {

View File

@@ -992,3 +992,7 @@ Hi there!
{{/with}}
{{/with}}
</template>
<template name="spacebars_template_test_falsy_helper">
foo:{{foo}} GLOBAL_ZERO:{{GLOBAL_ZERO}}
</template>

View File

@@ -669,7 +669,6 @@ Tinytest.add("spacebars-tests - template_tests - select tags", function (test) {
options.update({}, {$set: {selected: false}}, {multi: true});
Tracker.flush();
options.update({}, {$set: {selected: true}}, {multi: true});
window.avital = true;
Tracker.flush();
test.equal($(selectEl).find('option')[0].selected, true);
test.equal($(selectEl).find('option')[1].selected, true);
@@ -2903,3 +2902,12 @@ Tinytest.add("spacebars-tests - template_tests - content context back-compat", f
Tracker.flush();
test.equal(canonicalizeHtml(div.innerHTML), 'FA');
});
Tinytest.add("spacebars-tests - template_tests - falsy helper", function (test) {
var tmpl = Template.spacebars_template_test_falsy_helper;
tmpl.foo = 0;
Template.registerHelper('GLOBAL_ZERO', 0);
var div = renderToDiv(tmpl);
test.equal(canonicalizeHtml(div.innerHTML), 'foo:0 GLOBAL_ZERO:0');
});

View File

@@ -191,6 +191,9 @@ var getCurrentProgressTracker = function () {
return progress ? progress : rootProgress;
};
var nudge = function () {
getCurrentProgressTracker().nudge();
};
var addChildTracker = function (title) {
var options = {};
@@ -299,10 +302,20 @@ var enterJob = function (options, f) {
return currentProgress.withValue(progress, function () {
if (!currentMessageSet.get()) {
var nestingLevel = currentNestingLevel.get();
var start;
if (debugBuild) {
start = Date.now();
console.log("START", nestingLevel, options.title);
}
try {
return f();
} finally {
progress.reportProgressDone();
if (debugBuild) {
var end = Date.now();
console.log("DONE", nestingLevel, options.title, "took " + (end - start));
}
}
}
@@ -549,5 +562,6 @@ _.extend(exports, {
reportProgress: reportProgress,
reportProgressDone: reportProgressDone,
getCurrentProgressTracker: getCurrentProgressTracker,
addChildTracker: addChildTracker
addChildTracker: addChildTracker,
nudge: nudge
});

View File

@@ -236,6 +236,8 @@ var File = function (options) {
// disk).
self.sourcePath = options.sourcePath;
self.info = options.info || '?';
// If this file was generated, a sourceMap (as a string) with debugging
// information, as well as the "root" that paths in it should be resolved
// against. Set with setSourceMap.
@@ -270,6 +272,11 @@ var File = function (options) {
};
_.extend(File.prototype, {
toString: function() {
var self = this;
return "File: [info=" + self.info + "]";
},
hash: function () {
var self = this;
if (! self._hash)
@@ -430,6 +437,15 @@ var Target = function (options) {
// A mapping from Cordova plugin name to Cordova plugin version number.
self.cordovaDependencies = {};
// For the todos sample app:
// false: 99.6 KB / 316 KB
// vs
// true: 99 KB / 315 KB
// METEOR_MINIFY_LEGACY is an undocumented safety-valve environment variable,
// in case people hit trouble
self._minifyTogether = !!process.env.METEOR_MINIFY_LEGACY;
};
_.extend(Target.prototype, {
@@ -625,6 +641,7 @@ _.extend(Target.prototype, {
return;
var f = new File({
info: 'unbuild ' + resource,
data: resource.data,
cacheable: false,
hash: resource.hash
@@ -659,7 +676,7 @@ _.extend(Target.prototype, {
// meteor.js?
return;
var f = new File({data: resource.data, cacheable: false});
var f = new File({ info: 'resource ' + resource.servePath, data: resource.data, cacheable: false});
var relPath = stripLeadingSlash(resource.servePath);
f.setTargetPathFromRelPath(relPath);
@@ -726,16 +743,32 @@ _.extend(Target.prototype, {
minifyJs: function (minifiers) {
var self = this;
var allJs = _.map(self.js, function (file) {
return file.contents('utf8');
}).join('\n;\n');
var allJs;
allJs = minifiers.UglifyJSMinify(allJs, {
var minifyOptions = {
fromString: true,
compress: {drop_debugger: false}
}).code;
compress: {drop_debugger: false }
};
self.js = [new File({ data: new Buffer(allJs, 'utf8') })];
if (self._minifyTogether) {
var sources = _.map(self.js, function (file) {
return file.contents('utf8');
});
buildmessage.enterJob({title: "Minifying"}, function () {
allJs = _minify(minifiers.UglifyJS, '', sources, minifyOptions).code;
});
} else {
minifyOptions.compress.unused = false;
minifyOptions.compress.dead_code = false;
allJs = buildmessage.forkJoin({title: "Minifying" }, self.js, function (file) {
var source = file.contents('utf8');
return _minify(minifiers.UglifyJS, file.info, source, minifyOptions).code;
}).join("\n\n");
}
self.js = [new File({ info: 'minified js', data: new Buffer(allJs, 'utf8') })];
self.js[0].setUrlToHash(".js");
},
@@ -771,6 +804,127 @@ _.extend(Target.prototype, {
}
});
// This code should mirror the minify function in UglifyJs2,
_minify = function(UglifyJS, key, files, options) {
options = UglifyJS.defaults(options, {
spidermonkey : false,
outSourceMap : null,
sourceRoot : null,
inSourceMap : null,
fromString : false,
warnings : false,
mangle : {},
output : null,
compress : {}
});
UglifyJS.base54.reset();
var totalFileSize = 0;
_.forEach(files, function (file) {
totalFileSize += file.length;
});
var phases = 2;
if (options.compress) phases++;
if (options.mangle) phases++;
if (options.output) phases++;
var progress = {current: 0, end: totalFileSize * phases, done: false};
var progressTracker = buildmessage.getCurrentProgressTracker();
// 1. parse
var toplevel = null,
sourcesContent = {};
if (options.spidermonkey) {
toplevel = UglifyJS.AST_Node.from_mozilla_ast(files);
} else {
if (typeof files == "string")
files = [ files ];
buildmessage.forkJoin({title: 'Minifying: parsing ' + key}, files, function (file) {
var code = options.fromString
? file
: fs.readFileSync(file, "utf8");
sourcesContent[file] = code;
toplevel = UglifyJS.parse(code, {
filename: options.fromString ? "?" : file,
toplevel: toplevel
});
progress.current += code.length;
progressTracker.reportProgress(progress);
});
}
// 2. compress
var compress;
if (options.compress) buildmessage.enterJob({title: "Minify: compress 1 " + key}, function () {
compress = { warnings: options.warnings };
UglifyJS.merge(compress, options.compress);
toplevel.figure_out_scope();
});
if (options.compress) buildmessage.enterJob({title: "Minify: compress 2 " + key}, function () {
var sq = UglifyJS.Compressor(compress);
toplevel = toplevel.transform(sq);
progress.current += totalFileSize;
progressTracker.reportProgress(progress);
});
// 3. mangle
if (options.mangle) buildmessage.enterJob({title: "Minify: mangling " + key}, function () {
toplevel.figure_out_scope();
toplevel.compute_char_frequency();
toplevel.mangle_names(options.mangle);
progress.current += totalFileSize;
progressTracker.reportProgress(progress);
});
// 4. output
var inMap = options.inSourceMap;
var output = {};
if (typeof options.inSourceMap == "string") {
inMap = fs.readFileSync(options.inSourceMap, "utf8");
}
if (options.outSourceMap) {
output.source_map = UglifyJS.SourceMap({
file: options.outSourceMap,
orig: inMap,
root: options.sourceRoot
});
if (options.sourceMapIncludeSources) {
for (var file in sourcesContent) {
if (sourcesContent.hasOwnProperty(file)) {
options.source_map.get().setSourceContent(file, sourcesContent[file]);
}
}
}
}
if (options.output) buildmessage.enterJob({title: "Minify: merging " + key}, function () {
UglifyJS.merge(output, options.output);
progress.current += totalFileSize;
progressTracker.reportProgress(progress);
});
var stream;
buildmessage.enterJob({title: "Minify: printing " + key}, function () {
stream = UglifyJS.OutputStream(output);
toplevel.print(stream);
progress.current += totalFileSize;
progressTracker.reportProgress(progress);
});
return {
code : stream + "",
map : output.source_map + ""
};
};
//////////////////// ClientTarget ////////////////////
@@ -842,7 +996,7 @@ _.extend(ClientTarget.prototype, {
if (! stringifiedCss.code)
return;
self.css = [new File({ data: new Buffer(stringifiedCss.code, 'utf8') })];
self.css = [new File({ info: 'combined css', data: new Buffer(stringifiedCss.code, 'utf8') })];
// Add the contents of the input files to the source map of the new file
stringifiedCss.map.sourcesContent =
@@ -890,7 +1044,7 @@ _.extend(ClientTarget.prototype, {
minifiedCss = minifiers.CssTools.minifyCss(allCss);
}
if (!! minifiedCss) {
self.css = [new File({ data: new Buffer(minifiedCss, 'utf8') })];
self.css = [new File({ info: 'minified css', data: new Buffer(minifiedCss, 'utf8') })];
self.css[0].setUrlToHash(".css", "?meteor_css_resource=true");
}
},

View File

@@ -528,19 +528,13 @@ _.extend(CompleteCatalog.prototype, {
constr.push(utils.parseConstraint(name + "@=" + packageSource.version));
});
var patience = new utils.Patience({
messageAfterMs: 1000,
message: "Figuring out the best package versions to use. This may take a moment."
});
var ret;
try {
var ret = buildmessage.enterJob({ title: "Figuring out the best package versions to use." }, function () {
// Then, call the constraint solver, to get the valid transitive subset of
// those versions to record for our solution. (We don't just return the
// original version lock because we want to record the correct transitive
// dependencies)
try {
ret = self.resolver.resolve(deps, constr, resolverOpts);
return self.resolver.resolve(deps, constr, resolverOpts);
} catch (e) {
// Maybe we only failed because we need to refresh. Try to refresh
// (unless we already are) and retry.
@@ -550,11 +544,10 @@ _.extend(CompleteCatalog.prototype, {
}
catalog.official.refresh();
self.resolver || self._initializeResolver();
ret = self.resolver.resolve(deps, constr, resolverOpts);
return self.resolver.resolve(deps, constr, resolverOpts);
}
} finally {
patience.stop();
}
});
if (ret["usedRCs"]) {
var expPackages = [];
_.each(ret.answer, function(version, package) {
@@ -692,6 +685,7 @@ _.extend(CompleteCatalog.prototype, {
// This may be a singleton, but the resolver is in a package so it
// doesn't have access to it.
utils.Patience.nudge();
buildmessage.nudge();
}
});
},

View File

@@ -152,6 +152,7 @@ main.registerCommand({
main.registerCommand({
name: 'run',
pretty: true,
requiresApp: true,
maxArgs: Infinity,
options: {

View File

@@ -578,25 +578,121 @@ var compileUnibuild = function (unipkg, inputSourceArch, packageLoader,
// way to return errors (that could go in an overall list of
// errors experienced across all files)
var readOffset = 0;
/**
* The comments for this class aren't used to generate docs right now.
* The docs live in the GitHub Wiki at: https://github.com/meteor/meteor/wiki/CompileStep-API-for-Build-Plugin-Source-Handlers
* @class CompileStep
* @summary The object passed into Plugin.registerSourceHandler
* @global
*/
var compileStep = {
/**
* @summary The total number of bytes in the input file.
* @memberOf CompileStep
* @instance
* @type {Integer}
*/
inputSize: contents.length,
/**
* @summary The filename and relative path of the input file.
* Please don't use this filename to read the file from disk, instead
* use [compileStep.read](CompileStep-read).
* @type {String}
* @instance
* @memberOf CompileStep
*/
inputPath: relPath,
/**
* @summary The filename and absolute path of the input file.
* Please don't use this filename to read the file from disk, instead
* use [compileStep.read](CompileStep-read).
* @type {String}
* @instance
* @memberOf CompileStep
*/
fullInputPath: absPath,
// The below is used in the less and stylus packages... so it should be
// public API.
_fullInputPath: absPath, // avoid, see above..
// XXX duplicates _pathForSourceMap() in linker
pathForSourceMap: (
inputSourceArch.pkg.name
? inputSourceArch.pkg.name + "/" + relPath
: path.basename(relPath)),
/**
* @summary If you are generating a sourcemap for the compiled file, use
* this path for the original file in the sourcemap.
* @type {String}
* @memberOf CompileStep
* @instance
*/
pathForSourceMap: (inputSourceArch.pkg.name ?
inputSourceArch.pkg.name + "/" + relPath : path.basename(relPath)),
// null if this is an app. intended to be used for the sources
// dictionary for source maps.
/**
* @summary The name of the package in which the file being built exists.
* @type {String}
* @memberOf CompileStep
* @instance
*/
packageName: inputSourceArch.pkg.name,
/**
* @summary On web targets, this will be the root URL prepended
* to the paths you pick for your output files. For example,
* it could be "/packages/my-package".
* @type {String}
* @memberOf CompileStep
* @instance
*/
rootOutputPath: inputSourceArch.pkg.serveRoot,
arch: inputSourceArch.arch, // XXX: what is the story with arch?
/**
* @summary The architecture for which we are building. Can be "os",
* "web.browser", or "web.cordova".
* @type {String}
* @memberOf CompileStep
* @instance
*/
arch: inputSourceArch.arch,
/**
* @deprecated in 0.9.4
* This is a duplicate API of the above, we don't need it.
*/
archMatches: function (pattern) {
return archinfo.matches(inputSourceArch.arch, pattern);
},
/**
* @summary Any options passed to "api.addFiles".
* @type {Object}
* @memberOf CompileStep
* @instance
*/
fileOptions: fileOptions,
/**
* @summary The list of exports that the current package has defined.
* Can be used to treat those symbols differently during compilation.
* @type {Object}
* @memberOf CompileStep
* @instance
*/
declaredExports: _.pluck(inputSourceArch.declaredExports, 'name'),
/**
* @summary Read from the input file. If `n` is specified, returns the
* next `n` bytes of the file as a Buffer. XXX not sure if this actually
* returns a String sometimes...
* @param {Integer} [n] The number of bytes to return.
* @instance
* @memberOf CompileStep
*/
read: function (n) {
if (n === undefined || readOffset + n > contents.length)
n = contents.length - readOffset;
@@ -604,7 +700,18 @@ var compileUnibuild = function (unipkg, inputSourceArch, packageLoader,
readOffset += n;
return ret;
},
appendDocument: function (options) {
/**
* @summary Works in web targets only. Add markup to the `head` or `body`
* section of the document.
* @param {Object} options
* @param {String} options.section Which section of the document should
* be appended to. Can only be "head" or "body".
* @param {String} options.data The content to append.
* @memberOf CompileStep
* @instance
*/
addHtml: function (options) {
if (! archinfo.matches(inputSourceArch.arch, "web"))
throw new Error("Document sections can only be emitted to " +
"web targets");
@@ -617,6 +724,26 @@ var compileUnibuild = function (unipkg, inputSourceArch, packageLoader,
data: new Buffer(options.data, 'utf8')
});
},
/**
* @deprecated in 0.9.4
*/
appendDocument: function (options) {
this.addHtml(options);
},
/**
* @summary Web targets only. Add a stylesheet to the document.
* @param {Object} options
* @param {String} path The requested path for the added CSS, may not be
* satisfied if there are path conflicts.
* @param {String} data The content of the stylesheet that should be
* added.
* @param {String} sourceMap A stringified JSON sourcemap, in case the
* stylesheet was generated from a different file.
* @memberOf CompileStep
* @instance
*/
addStylesheet: function (options) {
if (! archinfo.matches(inputSourceArch.arch, "web"))
throw new Error("Stylesheets can only be emitted to " +
@@ -631,6 +758,22 @@ var compileUnibuild = function (unipkg, inputSourceArch, packageLoader,
sourceMap: options.sourceMap
});
},
/**
* @summary Add JavaScript code. The code added will only see the
* namespaces imported by this package as runtime dependencies using
* ['api.use'](#PackageAPI-use). If the file being compiled was added
* with the bare flag, the resulting JavaScript won't be wrapped in a
* closure.
* @param {Object} options
* @param {String} options.path The path at which the JavaScript file
* should be inserted, may not be honored in case of path conflicts.
* @param {String} options.data The code to be added.
* @param {String} options.sourcePath The path that will be used in
* any error messages generated by this file, e.g. `foo.js:4:1: error`.
* @memberOf CompileStep
* @instance
*/
addJavaScript: function (options) {
if (typeof options.data !== "string")
throw new Error("'data' option to addJavaScript must be a string");
@@ -642,15 +785,45 @@ var compileUnibuild = function (unipkg, inputSourceArch, packageLoader,
source: options.data,
sourcePath: options.sourcePath,
servePath: path.join(inputSourceArch.pkg.serveRoot, options.path),
bare: !! options.bare,
bare: !! fileOptions.bare,
sourceMap: options.sourceMap
});
},
/**
* @summary Add a file to serve as-is to the browser or to include on
* the browser, depending on the target. On the web, it will be served
* at the exact path requested. For server targets, it can be retrieved
* using `Assets.getText` or `Assets.getBinary`.
* @param {Object} options
* @param {String} path The path at which to serve the asset.
* @param {Buffer|String} data The data that should be placed in
* the file.
* @memberOf CompileStep
* @instance
*/
addAsset: function (options) {
if (! (options.data instanceof Buffer))
throw new Error("'data' option to addAsset must be a Buffer");
if (! (options.data instanceof Buffer)) {
if (_.isString(options.data)) {
options.data = new Buffer(options.data);
} else {
throw new Error("'data' option to addAsset must be a Buffer or String.");
}
}
addAsset(options.data, options.path);
},
/**
* @summary Display a build error.
* @param {Object} options
* @param {String} message The error message to display.
* @param {String} [sourcePath] The path to display in the error message.
* @param {Integer} line The line number to display in the error message.
* @param {String} func The function name to display in the error message.
* @memberOf CompileStep
* @instance
*/
error: function (options) {
buildmessage.error(options.message || ("error building " + relPath), {
file: options.sourcePath,

View File

@@ -45,7 +45,7 @@ var emptyCachedServerDataJson = function () {
};
// Given a connection, makes a call to the package server. (Checks to see if
// the connection is connected, and reconnectes if needed -- a workaround for
// the connection is connected, and reconnects if needed -- a workaround for
// the fact that connections in the tool do not reconnect)
exports.callPackageServer = function (conn) {
if (!conn.connected) {

View File

@@ -587,7 +587,27 @@ _.extend(PackageSource.prototype, {
// - sources: sources for the plugin (array of string)
// - npmDependencies: map from npm package name to required
// version (string)
_transitional_registerBuildPlugin: function (options) {
/**
* @summary Define a build plugin. A build plugin extends the build
* process for apps and packages that use this package. For example,
* the `coffeescript` package uses a build plugin to compile CoffeeScript
* source files into JavaScript.
* @param {Object} [options]
* @param {String} options.name A cosmetic name, must be unique in the
* package.
* @param {String|String[]} options.use Meteor packages that this
* plugin uses, independent of the packages specified in
* [api.onUse](#PackageAPI-onUse).
* @param {String[]} options.sources The source files that make up the
* build plugin, independent from [api.addFiles](#PackageAPI-addFiles).
* @param {Object} options.npmDependencies An object where the keys
* are NPM package names, and the keys are the version numbers of
* required NPM packages, just like in [Npm.depends](#Npm-depends).
* @memberOf Package
* @locus package.js
*/
registerBuildPlugin: function (options) {
// Tests don't have plugins; plugins initialized in the control file
// belong to the package and not to the test. (This will be less
// confusing in the new control file format).
@@ -620,6 +640,13 @@ _.extend(PackageSource.prototype, {
self.pluginInfo[options.name] = options;
},
/**
* @deprecated in 0.9.4
*/
_transitional_registerBuildPlugin: function (options) {
this.registerBuildPlugin(options);
},
includeTool: function () {
if (!files.inCheckout()) {
buildmessage.error("Package.includeTool() can only be used with a " +

View File

@@ -42,6 +42,10 @@ var Progress = function (options) {
self._isDone = false;
self._selfActive = false;
// If we're faking progress using the exponential trick, the counter
// stores the number of actual ticks
self._exponentialCounter = undefined;
};
_.extend(Progress.prototype, {
@@ -64,6 +68,30 @@ _.extend(Progress.prototype, {
self.reportProgress(state);
},
// For when we don't have a clear idea how long something will take,
// (i.e. no end estimate), just call nudge occasionally. We'll build
// an exponential progress bar for the task.
nudge: function () {
var self = this;
var halfLife = 25;
var state = _.clone(self._selfState);
if (!self._exponentialCounter) {
self._exponentialCounter = 1;
// Arbitrary endpoint
state.end = 100;
} else {
self._exponentialCounter++;
}
var fractionLeft = Math.pow(0.5, self._exponentialCounter / halfLife);
state.current = state.end * (1 - fractionLeft);
self.reportProgress(state);
},
// Tries to determine which is the 'current' job in the tree
// This is very heuristical... we use some hints, like:
// don't descend into fork-join jobs; we know these execute concurrently,

View File

@@ -1,9 +1,14 @@
var _ = require('underscore');
var Future = require('fibers/future');
var files = require('./files.js');
var release = require('./release.js');
var buildmessage = require('./buildmessage.js');
var fiberHelpers = require('./fiber-helpers.js');
var runLog = require('./run-log.js');
var Console = require('./console.js').Console;
var Proxy = require('./run-proxy.js').Proxy;
var Selenium = require('./run-selenium.js').Selenium;
var HttpProxy = require('./run-httpproxy.js').HttpProxy;
@@ -106,6 +111,7 @@ _.extend(Runner.prototype, {
// XXX leave a pidfile and check if we are already running
start: function () {
var self = this;
self.proxy.start();
// print the banner only once we've successfully bound the port
@@ -145,16 +151,19 @@ _.extend(Runner.prototype, {
// but all of the ones I tried look terrible in the terminal.
if (! self.quiet) {
var animationFrame = 0;
var printUpdate = function () {
runLog.logTemporary("=> Starting MongoDB... " +
spinner[animationFrame]);
var printUpdate = fiberHelpers.bindEnvironment(function () {
//runLog.logTemporary("=> Starting MongoDB... " +
// spinner[animationFrame]);
buildmessage.nudge();
animationFrame = (animationFrame + 1) % spinner.length;
};
});
printUpdate();
var mongoProgressTimer = setInterval(printUpdate, 200);
}
self.mongoRunner.start();
buildmessage.enterJob({ title: 'Starting MongoDB' }, function () {
self.mongoRunner.start();
});
if (! self.quiet) {
clearInterval(mongoProgressTimer);
@@ -324,6 +333,7 @@ exports.run = function (appDir, options) {
var runner = new Runner(appDir, runOptions);
runner.start();
Console.enableProgressBar(false);
var result = fut.wait();
runner.stop();

View File

@@ -1,6 +1,7 @@
var _ = require('underscore');
var uniload = require('./uniload.js');
var release = require('./release.js');
var Console = require('./console.js').Console;
// runLog is primarily used by the parts of the tool which run apps locally. It
// writes to standard output (and standard error, if rawLogs is set), and allows
@@ -64,12 +65,12 @@ _.extend(RunLog.prototype, {
if (self.consecutiveRestartMessages) {
self.consecutiveRestartMessages = null;
process.stdout.write("\n");
Console.stdout.write("\n");
}
if (self.consecutiveClientRestartMessages) {
self.consecutiveClientRestartMessages = null;
process.stdout.write("\n");
Console.stdout.write("\n");
}
if (self.temporaryMessageLength) {
@@ -95,9 +96,9 @@ _.extend(RunLog.prototype, {
self._clearSpecial();
if (self.rawLogs)
process[isStderr ? "stderr" : "stdout"].write(line + "\n");
Console[isStderr ? "stderr" : "stdout"].write(line + "\n");
else
process.stdout.write(Log.format(obj, { color: true }) + "\n");
Console.stdout.write(Log.format(obj, { color: true }) + "\n");
// XXX deal with test server logging differently?!
},
@@ -115,7 +116,7 @@ _.extend(RunLog.prototype, {
self._record(obj);
self._clearSpecial();
process.stdout.write(msg + "\n");
Console.stdout.write(msg + "\n");
},
// Write a message to the terminal that will get overwritten by the

View File

@@ -391,6 +391,11 @@ _.extend(Unipackage.prototype, {
if (self._pluginsInitialized)
return;
/**
* @global
* @namespace Plugin
* @summary The namespace that is exposed inside build plugin files.
*/
var Plugin = {
// 'extension' is a file extension without the separation dot
// (eg 'js', 'coffee', 'coffee.md')
@@ -401,6 +406,21 @@ _.extend(Unipackage.prototype, {
//
// 'handler' is a function that takes a single argument, a
// CompileStep (#CompileStep)
/**
* @summary Inside a build plugin source file specified in
* [Package.registerBuildPlugin](#Package-registerBuildPlugin),
* add a handler to compile files with a certain file extension.
* @param {String} fileExtension The file extension that this plugin
* should handle, without the first dot.
* Examples: `"coffee"`, `"coffee.md"`.
* @param {Function} handler A function that takes one argument,
* a CompileStep object.
*
* Documentation for CompileStep is available [on the GitHub Wiki](https://github.com/meteor/meteor/wiki/CompileStep-API-for-Build-Plugin-Source-Handlers).
* @memberOf Plugin
* @locus Build Plugin
*/
registerSourceHandler: function (extension, options, handler) {
if (!handler) {
handler = options;