mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'release-0.6.5' into devel
Conflicts: packages/less/plugin/compile-less.js
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
|
||||
## vNEXT
|
||||
|
||||
## v0.6.5
|
||||
|
||||
* linker! namespacing, exports, unipackages, weak and unordered dependencies,
|
||||
etc. sourcemaps (including for coffee). standard-app-packages. don't
|
||||
implicitly use all app packages. lots of stuff moved from server.js (now
|
||||
|
||||
3
packages/json/json_native.js
Normal file
3
packages/json/json_native.js
Normal file
@@ -0,0 +1,3 @@
|
||||
// Do we already have a global JSON object? Export it as our JSON object.
|
||||
if (window.JSON)
|
||||
JSON = window.JSON;
|
||||
@@ -3,10 +3,12 @@ Package.describe({
|
||||
internal: true
|
||||
});
|
||||
|
||||
// We need to figure out how to serve this file only to browsers that
|
||||
// don't have JSON.stringify (eg, IE7 and earlier -- or is that IE8?)
|
||||
// We need to figure out how to serve this file only to browsers that don't have
|
||||
// JSON.stringify (eg, IE7 and earlier, and IE8 outside of "standards mode")
|
||||
|
||||
Package.on_use(function (api) {
|
||||
// Node always has JSON; we only need this in some browsers.
|
||||
api.export('JSON', 'client');
|
||||
api.add_files('json_native.js', 'client');
|
||||
api.add_files('json2.js', 'client');
|
||||
});
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
var fs = Npm.require('fs');
|
||||
var path = Npm.require('path');
|
||||
var less = Npm.require('less');
|
||||
var Future = Npm.require('fibers/future');
|
||||
|
||||
Plugin.registerSourceHandler("less", function (compileStep) {
|
||||
// XXX annoying that this is replicated in .css, .less, and .styl
|
||||
if (! compileStep.archMatches('browser')) {
|
||||
// XXX in the future, might be better to emit some kind of a
|
||||
// warning if a stylesheet is included on the server, rather than
|
||||
// silently ignoring it. but that would mean you can't stick .css
|
||||
// at the top level of your app, which is kind of silly.
|
||||
return;
|
||||
}
|
||||
|
||||
var source = compileStep.read().toString('utf8');
|
||||
var options = {
|
||||
// Use fs.readFileSync to process @imports. This is the bundler, so
|
||||
@@ -13,24 +23,28 @@ Plugin.registerSourceHandler("less", function (compileStep) {
|
||||
paths: [path.dirname(compileStep._fullInputPath)] // for @import
|
||||
};
|
||||
|
||||
var f = new Future;
|
||||
var css;
|
||||
try {
|
||||
less.render(source, options, function (err, css) {
|
||||
if (err) {
|
||||
// XXX better error handling, once the Plugin interface support it
|
||||
throw new Error(err.message);
|
||||
}
|
||||
|
||||
compileStep.addStylesheet({
|
||||
path: compileStep.inputPath + ".css",
|
||||
data: css
|
||||
});
|
||||
});
|
||||
less.render(source, options, f.resolver());
|
||||
css = f.wait();
|
||||
} catch (e) {
|
||||
// less.render() is supposed to report any errors via its
|
||||
// callback. But sometimes, it throws them instead. This is
|
||||
// probably a bug in less. Be prepared for either behavior.
|
||||
throw new Error(compileStep.inputPath + ": Less compiler error: " + e.message);
|
||||
compileStep.error({
|
||||
message: "Less compiler error: " + e.message,
|
||||
sourcePath: e.filename || compileStep.inputPath,
|
||||
line: e.line - 1, // dunno why, but it matches
|
||||
column: e.column + 1
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
compileStep.addStylesheet({
|
||||
path: compileStep.inputPath + ".css",
|
||||
data: css
|
||||
});
|
||||
});;
|
||||
|
||||
// Register lessimport files with the dependency watcher, without actually
|
||||
|
||||
@@ -1287,18 +1287,17 @@ Tinytest.add("livedata connection - onReconnect prepends messages correctly with
|
||||
|
||||
var getSelfConnectionUrl = function () {
|
||||
if (Meteor.isClient) {
|
||||
return "/";
|
||||
return Meteor._relativeToSiteRootUrl("/");
|
||||
} else {
|
||||
return Meteor.absoluteUrl();
|
||||
}
|
||||
};
|
||||
|
||||
if (Meteor.isServer) {
|
||||
var reversed = {};
|
||||
Meteor.methods({
|
||||
reverse: function (arg) {
|
||||
reversed[arg] = true;
|
||||
return arg.split("").reverse().join("");
|
||||
// Return something notably different from reverse.meteor.com.
|
||||
return arg.split("").reverse().join("") + " LOCAL";
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1325,22 +1324,10 @@ testAsyncMulti("livedata connection - reconnect to a different server", [
|
||||
if (self.doTest) {
|
||||
self.conn.reconnect({url: getSelfConnectionUrl()});
|
||||
self.conn.call("reverse", "bar", expect(function (err, res) {
|
||||
test.equal(res, "rab");
|
||||
}));
|
||||
}
|
||||
},
|
||||
function (test, expect) {
|
||||
var self = this;
|
||||
var id = Random.id();
|
||||
if (self.doTest) {
|
||||
self.conn.call("reverse", id, expect(function (err, res) {
|
||||
if (Meteor.isServer) {
|
||||
test.isTrue(reversed[id]);
|
||||
}
|
||||
test.equal(res, "rab LOCAL");
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
]);
|
||||
|
||||
Tinytest.addAsync("livedata connection - version negotiation requires renegotiating",
|
||||
|
||||
@@ -600,6 +600,8 @@ if (Meteor.isClient) {
|
||||
]);
|
||||
}
|
||||
|
||||
var selfUrl = Meteor.isServer
|
||||
? Meteor.absoluteUrl() : Meteor._relativeToSiteRootUrl('/');
|
||||
|
||||
if (Meteor.isServer) {
|
||||
Meteor.methods({
|
||||
@@ -613,7 +615,7 @@ if (Meteor.isServer) {
|
||||
testAsyncMulti("livedata - connect works from both client and server", [
|
||||
function (test, expect) {
|
||||
var self = this;
|
||||
self.conn = DDP.connect(Meteor.absoluteUrl());
|
||||
self.conn = DDP.connect(selfUrl);
|
||||
pollUntil(expect, function () {
|
||||
return self.conn.status().connected;
|
||||
}, 10000);
|
||||
@@ -637,7 +639,7 @@ if (Meteor.isServer) {
|
||||
testAsyncMulti("livedata - method call on server blocks in a fiber way", [
|
||||
function (test, expect) {
|
||||
var self = this;
|
||||
self.conn = DDP.connect(Meteor.absoluteUrl());
|
||||
self.conn = DDP.connect(selfUrl);
|
||||
pollUntil(expect, function () {
|
||||
return self.conn.status().connected;
|
||||
}, 10000);
|
||||
|
||||
@@ -23,9 +23,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// <METEOR> Commented out JSO implementation (use json package instead).
|
||||
// JSON2 by Douglas Crockford (minified).
|
||||
var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)typeof rep[c]=="string"&&(d=rep[c],e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function f(a){return a<10?"0"+a:a}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(!b||typeof b=="function"||typeof b=="object"&&typeof b.length=="number")return str("",{"":a});throw new Error("JSON.stringify")}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")})}()
|
||||
|
||||
// var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)typeof rep[c]=="string"&&(d=rep[c],e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function f(a){return a<10?"0"+a:a}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(!b||typeof b=="function"||typeof b=="object"&&typeof b.length=="number")return str("",{"":a});throw new Error("JSON.stringify")}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")})}()
|
||||
// </METEOR>
|
||||
|
||||
// [*] Including lib/index.js
|
||||
// Public object
|
||||
|
||||
@@ -101,7 +101,7 @@ _.extend(LivedataTest.ClientStream.prototype, {
|
||||
self._clearConnectionAndHeartbeatTimers();
|
||||
if (self.socket) {
|
||||
self.socket.onmessage = self.socket.onclose
|
||||
= self.socket.onerror = function () {};
|
||||
= self.socket.onerror = self.socket.onheartbeat = function () {};
|
||||
self.socket.close();
|
||||
self.socket = null;
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ Log.format = function (obj, options) {
|
||||
'-',
|
||||
timeStamp,
|
||||
utcOffsetStr,
|
||||
timeInexact ? '?' : ' ',
|
||||
timeInexact ? '? ' : ' ',
|
||||
appInfo,
|
||||
sourceInfo,
|
||||
stderrIndicator].join('');
|
||||
|
||||
@@ -51,7 +51,7 @@ Tinytest.add("logging - log", function (test) {
|
||||
[0, "0", "falsy - 0"],
|
||||
[null, "null", "falsy - null"],
|
||||
[undefined, "undefined", "falsy - undefined"],
|
||||
["2013-06-13T01:15:16.000Z", new Date("2013-06-13T01:15:16.000Z"), "date"],
|
||||
[new Date("2013-06-13T01:15:16.000Z"), new Date("2013-06-13T01:15:16.000Z"), "date"],
|
||||
[/[^regexp]{0,1}/g, "/[^regexp]{0,1}/g", "regexp"],
|
||||
[true, "true", "boolean - true"],
|
||||
[false, "false", "boolean - false"],
|
||||
@@ -72,7 +72,11 @@ Tinytest.add("logging - log", function (test) {
|
||||
var recieved = intercepted[index];
|
||||
var obj = EJSON.parse(recieved);
|
||||
|
||||
if (_.isDate(expected))
|
||||
// IE8 doesn't support this date format. Skip it.
|
||||
if (expected && expected.toString && expected.toString() === "NaN")
|
||||
return;
|
||||
|
||||
if (_.isDate(testcase[0]))
|
||||
obj.message = new Date(obj.message);
|
||||
test.equal(obj.message, expected, 'Logging ' + testName);
|
||||
});
|
||||
@@ -137,7 +141,7 @@ Tinytest.add("logging - format", function (test) {
|
||||
|
||||
test.equal(
|
||||
Log.format({message: "message", time: time, timeInexact: true, level: level}),
|
||||
level.charAt(0).toUpperCase() + "20120908-07:06:05.004" + utcOffsetStr + "?message");
|
||||
level.charAt(0).toUpperCase() + "20120908-07:06:05.004" + utcOffsetStr + "? message");
|
||||
|
||||
test.equal(
|
||||
Log.format({foo1: "bar1", foo2: "bar2", time: time, level: level}),
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
source file. */
|
||||
|
||||
Plugin.registerSourceHandler("css", function (compileStep) {
|
||||
// XXX use archinfo rather than rolling our own
|
||||
if (! compileStep.arch.match(/^browser(\.|$)/)) {
|
||||
// XXX annoying that this is replicated in .css, .less, and .styl
|
||||
if (! compileStep.archMatches('browser')) {
|
||||
// XXX in the future, might be better to emit some kind of a
|
||||
// warning if a stylesheet is included on the server, rather than
|
||||
// silently ignoring it
|
||||
// silently ignoring it. but that would mean you can't stick .css
|
||||
// at the top level of your app, which is kind of silly.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Package._transitional_registerBuildPlugin({
|
||||
});
|
||||
|
||||
Package.on_test(function (api) {
|
||||
api.use(['tinytest', 'stylus', 'test-helpers'])
|
||||
api.use(['tinytest', 'stylus', 'test-helpers']);
|
||||
api.use('spark');
|
||||
api.add_files(['stylus_tests.styl', 'stylus_tests.js'], 'client');
|
||||
});
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
var fs = Npm.require('fs');
|
||||
var stylus = Npm.require('stylus');
|
||||
var nib = Npm.require('nib');
|
||||
var Future = Npm.require('fibers/future');
|
||||
|
||||
Plugin.registerSourceHandler("styl", function (compileStep) {
|
||||
// XXX annoying that this is replicated in .css, .less, and .styl
|
||||
if (! compileStep.archMatches('browser')) {
|
||||
// XXX in the future, might be better to emit some kind of a
|
||||
// warning if a stylesheet is included on the server, rather than
|
||||
// silently ignoring it. but that would mean you can't stick .css
|
||||
// at the top level of your app, which is kind of silly.
|
||||
return;
|
||||
}
|
||||
|
||||
var f = new Future;
|
||||
stylus(compileStep.read().toString('utf8'))
|
||||
.use(nib())
|
||||
.set('filename', compileStep.inputPath)
|
||||
.render(function(err, output) {
|
||||
if (err) {
|
||||
// XXX better error handling, once the Plugin interface support it
|
||||
throw new Error('Stylus compiler error: ' + err.message);
|
||||
}
|
||||
.render(f.resolver());
|
||||
|
||||
compileStep.addStylesheet({
|
||||
path: compileStep.inputPath + ".css",
|
||||
data: output
|
||||
});
|
||||
try {
|
||||
var css = f.wait();
|
||||
} catch (e) {
|
||||
compileStep.error({
|
||||
message: "Stylus compiler error: " + e.message
|
||||
});
|
||||
return;
|
||||
}
|
||||
);
|
||||
compileStep.addStylesheet({
|
||||
path: compileStep.inputPath + ".css",
|
||||
data: css
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,9 +110,25 @@ _.extend(Library.prototype, {
|
||||
|
||||
for (var i = 0; i < self.localPackageDirs.length; ++i) {
|
||||
var packageDir = path.join(self.localPackageDirs[i], name);
|
||||
// XXX or unipackage.json? see also watchLocalPackageDirs
|
||||
if (fs.existsSync(path.join(packageDir, 'package.js')))
|
||||
// A directory is a package if it either contains 'package.js' (a package
|
||||
// source tree) or 'unipackage.json' (a compiled unipackage). (Actually,
|
||||
// for now, unipackages contain a dummy package.js too.)
|
||||
//
|
||||
// XXX support for putting unipackages in a local package dir is
|
||||
// incomplete! They will be properly loaded, but other packages that
|
||||
// depend on them have no way of knowing when they change! unipackages
|
||||
// that are the .build of a source tree work fine (they have a
|
||||
// buildinfo.json and can be rebuilt), and warehouse unipackages work fine
|
||||
// too (users are not supposed to edit them (they are read-only on disk),
|
||||
// and their pathname specifies a version). But if you, eg, have a
|
||||
// unipackage of coffeescript in a local package directory, build another
|
||||
// package dependending on it, and substitute another version of the
|
||||
// unipackage in the same location, nothing will ever rebuild your
|
||||
// package!
|
||||
if (fs.existsSync(path.join(packageDir, 'package.js')) ||
|
||||
fs.existsSync(path.join(packageDir, 'unipackage.json'))) {
|
||||
return packageDir;
|
||||
}
|
||||
}
|
||||
|
||||
// Try the Meteor distribution, if we have one.
|
||||
@@ -120,6 +136,8 @@ _.extend(Library.prototype, {
|
||||
if (version) {
|
||||
packageDir = path.join(warehouse.getWarehouseDir(),
|
||||
'packages', name, version);
|
||||
// The warehouse is theoretically constructed carefully enough that the
|
||||
// directory really should not exist unless it is complete.
|
||||
if (! fs.existsSync(packageDir))
|
||||
throw new Error("Package missing from warehouse: " + name +
|
||||
" version " + version);
|
||||
@@ -224,8 +242,15 @@ _.extend(Library.prototype, {
|
||||
if (! buildmessage.jobHasMessages() && // ensure no errors!
|
||||
pkg.canBeSavedAsUnipackage()) {
|
||||
// Save it, for a fast load next time
|
||||
files.add_to_gitignore(packageDir, '.build*');
|
||||
pkg.saveAsUnipackage(buildDir, { buildOfPath: packageDir });
|
||||
try {
|
||||
files.add_to_gitignore(packageDir, '.build*');
|
||||
pkg.saveAsUnipackage(buildDir, { buildOfPath: packageDir });
|
||||
} catch (e) {
|
||||
// If we can't write to this directory, we don't get to cache our
|
||||
// output, but otherwise life is good.
|
||||
if (!(e && (e.code === 'EACCES' || e.code === 'EPERM')))
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -272,7 +297,7 @@ _.extend(Library.prototype, {
|
||||
|
||||
// Register local package directories with a watchSet. We want to know if a
|
||||
// package is created or deleted, which includes both its top-level source
|
||||
// directory or its package.js file.
|
||||
// directory and its main package metadata file.
|
||||
watchLocalPackageDirs: function (watchSet) {
|
||||
var self = this;
|
||||
_.each(self.localPackageDirs, function (packageDir) {
|
||||
@@ -283,7 +308,8 @@ _.extend(Library.prototype, {
|
||||
_.each(packages, function (p) {
|
||||
watch.readAndWatchFile(watchSet,
|
||||
path.join(packageDir, p, 'package.js'));
|
||||
// XXX unipackage.json too?
|
||||
watch.readAndWatchFile(watchSet,
|
||||
path.join(packageDir, p, 'unipackage.json'));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@@ -231,6 +231,12 @@ _.extend(Slice.prototype, {
|
||||
var handler = !fileOptions.isAsset && self._getSourceHandler(ext);
|
||||
var contents = watch.readAndWatchFile(self.watchSet, absPath);
|
||||
|
||||
if (contents === null) {
|
||||
buildmessage.error("File not found: " + source.relPath);
|
||||
// recover by ignoring
|
||||
return;
|
||||
}
|
||||
|
||||
if (! handler) {
|
||||
// If we don't have an extension handler, serve this file as a
|
||||
// static resource on the client, or ignore it on the server.
|
||||
@@ -359,6 +365,9 @@ _.extend(Slice.prototype, {
|
||||
packageName: self.pkg.name,
|
||||
rootOutputPath: self.pkg.serveRoot,
|
||||
arch: self.arch,
|
||||
archMatches: function (pattern) {
|
||||
return archinfo.matches(self.arch, pattern);
|
||||
},
|
||||
fileOptions: fileOptions,
|
||||
declaredExports: _.pluck(self.declaredExports, 'name'),
|
||||
read: function (n) {
|
||||
@@ -1792,6 +1801,28 @@ _.extend(Package.prototype, {
|
||||
var otherSliceRegExp =
|
||||
(sliceName === "server" ? /^client\/$/ : /^server\/$/);
|
||||
|
||||
// The paths that we've called checkForInfiniteRecursion on.
|
||||
var seenPaths = {};
|
||||
// Used internally by fs.realpathSync as an optimization.
|
||||
var realpathCache = {};
|
||||
var checkForInfiniteRecursion = function (relDir) {
|
||||
var absPath = path.join(self.sourceRoot, relDir);
|
||||
try {
|
||||
var realpath = fs.realpathSync(absPath, realpathCache);
|
||||
} catch (e) {
|
||||
if (!e || e.code !== 'ELOOP')
|
||||
throw e;
|
||||
// else leave realpath undefined
|
||||
}
|
||||
if (realpath === undefined || _.has(seenPaths, realpath)) {
|
||||
buildmessage.error("Symlink cycle detected at " + relDir);
|
||||
// recover by returning no files
|
||||
return true;
|
||||
}
|
||||
seenPaths[realpath] = true;
|
||||
return false;
|
||||
};
|
||||
|
||||
// Read top-level subdirectories. Ignore subdirectories that have
|
||||
// special handling.
|
||||
var sourceDirectories = readAndWatchDirectory('', {
|
||||
@@ -1800,13 +1831,17 @@ _.extend(Package.prototype, {
|
||||
/^public\/$/, /^private\/$/,
|
||||
otherSliceRegExp].concat(sourceExclude)
|
||||
});
|
||||
checkForInfiniteRecursion('');
|
||||
|
||||
// XXX avoid infinite recursion with bad symlinks
|
||||
while (!_.isEmpty(sourceDirectories)) {
|
||||
var dir = sourceDirectories.shift();
|
||||
|
||||
// remove trailing slash
|
||||
dir = dir.substr(0, dir.length - 1);
|
||||
|
||||
if (checkForInfiniteRecursion(dir))
|
||||
return []; // pretend we found no files
|
||||
|
||||
// Find source files in this directory.
|
||||
Array.prototype.push.apply(sources, readAndWatchDirectory(dir, {
|
||||
include: sourceInclude,
|
||||
@@ -1845,7 +1880,6 @@ _.extend(Package.prototype, {
|
||||
include: [new RegExp('^' + assetDir + '/$')]
|
||||
});
|
||||
|
||||
// XXX avoid infinite recursion with bad symlinks
|
||||
if (!_.isEmpty(assetDirs)) {
|
||||
if (!_.isEqual(assetDirs, [assetDir + '/']))
|
||||
throw new Error("Surprising assetDirs: " + JSON.stringify(assetDirs));
|
||||
@@ -1855,6 +1889,9 @@ _.extend(Package.prototype, {
|
||||
// remove trailing slash
|
||||
dir = dir.substr(0, dir.length - 1);
|
||||
|
||||
if (checkForInfiniteRecursion(dir))
|
||||
return []; // pretend we found no files
|
||||
|
||||
// Find asset files in this directory.
|
||||
var assetsAndSubdirs = readAndWatchDirectory(dir, {
|
||||
include: [/.?/],
|
||||
|
||||
@@ -561,9 +561,10 @@ exports.run = function (context, options) {
|
||||
Status.running = true;
|
||||
|
||||
|
||||
var rootUrl = process.env.ROOT_URL || ('http://localhost:' + outerPort);
|
||||
var rootUrl = process.env.ROOT_URL ||
|
||||
('http://localhost:' + outerPort + '/');
|
||||
if (firstRun) {
|
||||
process.stdout.write("=> Meteor server running on: " + rootUrl + "/\n");
|
||||
process.stdout.write("=> Meteor server running on: " + rootUrl + "\n");
|
||||
firstRun = false;
|
||||
lastThingThatPrintedWasRestartMessage = false;
|
||||
} else {
|
||||
|
||||
@@ -228,9 +228,12 @@ var readDirectory = function (options) {
|
||||
// XXX Does the treatment of symlinks make sense?
|
||||
var stats = fs.statSync(path.join(options.absPath, entry));
|
||||
} catch (e) {
|
||||
// Disappeared after the readdirSync (or a dangling symlink)? Eh, pretend
|
||||
// it was never there in the first place.
|
||||
return;
|
||||
if (e && (e.code === 'ENOENT')) {
|
||||
// Disappeared after the readdirSync (or a dangling symlink)? Eh,
|
||||
// pretend it was never there in the first place.
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
// XXX if we're on windows, I guess it's possible for files to end with '/'.
|
||||
if (stats.isDirectory())
|
||||
|
||||
Reference in New Issue
Block a user