--- a/src/bespin-build/lib/bespin/builder.js
+++ b/src/bespin-build/lib/bespin/builder.js
@@ -22,59 +22,125 @@
*
* ***** END LICENSE BLOCK ***** */
// Bespin build system
var file = require("file");
var os = require("os");
-DEFAULT_PROFILE = "bespinProfile.json";
+var DEFAULT_PROFILE = "bespinProfile.json";
-PROFILE_FORMAT = '\nA profile is a JSON file containing an array of objects.\n' +
+var PROFILE_FORMAT = '\nA profile is a JSON file containing an array of objects.\n' +
'Each object must minimally have an "output" defined on it. For example:\n\n' +
'[{"output": "BespinEmbed.js"}]\n\n' +
'is a minimally acceptable profile.\n';
+
+var STANDARD_INCLUDES = [
+ {file: "src/html/loader.js"},
+ {file: "src/bespin-build/preloads.js"},
+ "narwhal/client"
+];
var BuilderError = exports.BuilderError = function(message) {
this.message = message;
-}
+};
+/*
+* Loads a JSON-format profile from disk.
+* @param {String} filename The profile file to load.
+* @type Object
+*/
exports.loadProfile = function(filename) {
if (!file.exists(filename)) {
throw new BuilderError("Profile file " + filename + " does not exist.");
}
var data = file.read(filename);
return JSON.parse(data);
-}
+};
+/*
+* Validates the information in a loaded profile object.
+* @param {Object} profile The profile object.
+*/
exports.validateProfile = function(profile) {
if (!Array.isArray(profile)) {
throw new BuilderError(PROFILE_FORMAT);
}
for (var i = 0; i < profile.length; i++) {
- if (!profile.output) {
+ var desc = profile[i];
+ if (!desc.output) {
throw new BuilderError(PROFILE_FORMAT);
}
+ if (!desc.includes) {
+ desc.includes = STANDARD_INCLUDES;
+ }
}
-}
+};
+/*
+* Retrieves/augments the file contents for the filespec provided.
+* The filespec can be a string, in which case it's assumed to be
+* a module. Modules are looked up on the module path, and the
+* contents are wrapped to be properly registered with the client-side
+* module sandbox.
+*
+* If filespec is an object with a "file" property, then that
+* file's contents will be returned directly.
+* @param {String|Object} filespec File to return contents of.
+* @type String
+*/
+exports.getFileContents = function(filespec) {
+ if (filespec instanceof String) {
+ // handle modules
+ return "";
+ } else if (filespec.file) {
+ // handle files
+ var path = new file.Path(filespec.file);
+ if (!path.exists()) {
+ throw new BuilderError("Could not find included file: "
+ + filespec.file);
+ }
+ return path.read();
+ }
+};
+
+/*
+* Generates an output script based on one item
+* description from the profile.
+* @param {Object} description One item from the list of items in a profile.
+*/
+exports.generateScript = function(description) {
+ var outputPath = new file.Path(description.output);
+ if (!outputPath.dirname().exists()) {
+ outputPath.dirname().mkdirs();
+ }
+};
+
+/*
+* Entry point for the command line interface.
+* @param (Array) args The command line arguments.
+*/
exports.main = function(args) {
print("Bespin Build System\n");
var profileFilename = args[1] ? args[1] : DEFAULT_PROFILE;
try {
var profile = exports.loadProfile(profileFilename);
exports.validateProfile(profile);
print("Using build profile: ", profileFilename);
+ for (var i = 0; i < profile.length; i++) {
+ exports.generateScript(profile[i]);
+ }
+
} catch (e) {
if (e instanceof exports.BuilderError) {
print("Build failed!");
print (e.message);
os.exit(1);
}
}
-}
\ No newline at end of file
+};
--- a/src/bespin-build/lib/bespin/builder/tests/commandTest.js
+++ b/src/bespin-build/lib/bespin/builder/tests/commandTest.js
@@ -36,27 +36,58 @@ var FAKEPROFILE = new file.Path(module.p
var throwsBuilderError = function(func, args, message) {
try {
func.apply(this, args);
qunit.ok(false, message);
} catch (e) {
if (e instanceof builder.BuilderError) {
qunit.ok(true, "Got a BuilderError");
} else {
- throw e;
+ qunit.ok(false, "Got an unexpected exception: " + e);
}
}
-}
+};
qunit.test("Profile loading", function() {
- qunit.ok(FAKEPROFILE.exists(), "Expected the testing profile file to exist (fakeprofile.json)");
- qunit.ok(FAKEPROFILE.isFile(), "Expected to find a file at " + FAKEPROFILE);
+ qunit.ok(FAKEPROFILE.exists(),
+ "Expected the testing profile file to exist (fakeprofile.json)");
+ qunit.ok(FAKEPROFILE.isFile(),
+ "Expected to find a file at " + FAKEPROFILE);
throwsBuilderError(builder.loadProfile, ["BADFILENAME!!!"],
"Expected an exception for a bad filename");
var profile = builder.loadProfile(FAKEPROFILE);
- qunit.equals(1, profile.length);
- qunit.equals("foo", profile[0].output);
+ qunit.equals(profile.length, 1);
+ qunit.equals(profile[0].output, "foo");
});
qunit.test("Profile validation", function() {
- throwsBuilderError(builder.validateProfile, [{}], "validate profile expects a list");
- throwsBuilderError(builder.validateProfile, [[{}]], "profiles must have an output defined");
+ throwsBuilderError(builder.validateProfile, [{}],
+ "validate profile expects a list");
+ throwsBuilderError(builder.validateProfile, [[{}]],
+ "profiles must have an output defined");
+
+ var myProfile = [{output: "foo.js"}];
+ builder.validateProfile(myProfile);
+ qunit.ok(true, "Should not have encountered an error in the previous validation.");
+ qunit.ok(Array.isArray(myProfile[0].includes),
+ "Expected profile to be augmented with includes");
});
+
+qunit.test("Setting up for build", function() {
+ var temppath = new file.Path("testtmp");
+ if (temppath.exists()) {
+ temppath.rmtree();
+ }
+ builder.generateScript({output: temppath + "/foo.js"});
+ qunit.ok(temppath.exists(), "expected output directory to be created");
+ if (temppath.exists()) {
+ temppath.rmtree();
+ }
+});
+
+qunit.test("Get file contents", function() {
+ throwsBuilderError(builder.getFileContents, [{file: "BADFILENAME"}],
+ "file contents can only be retrieved for good files");
+ file.write("GOODFILENAME", "Just some test data.\n");
+ var contents = builder.getFileContents({file: "GOODFILENAME"});
+ qunit.equals(contents, "Just some test data.\n", "File contents not retrieved properly");
+ file.remove("GOODFILENAME");
+});
\ No newline at end of file
--- a/src/html/index.html
+++ b/src/html/index.html
@@ -1,15 +1,16 @@
<!DOCTYPE html>
<html><head>
<link rel="stylesheet" href="sproutcore.css" type="text/css" />
<link rel="stylesheet" href="bespin.css" type="text/css" />
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
+ require.preload(["ref-send", "sandbox", "narwhal/client", "array", "object", "string", "function", "regexp", "reactor", "date", "global", "system", "binary"]);
require.async("bespin/boot");
</script>
<script type="text/javascript" src="dojo/dojo.js.uncompressed.js"></script>
<script type='text/javascript' src='dojo/regexp.js'></script>
<script type='text/javascript' src='dojo/cookie.js'></script>
<script type='text/javascript' src='dojo/AdapterRegistry.js'></script>
<script type='text/javascript' src='dojo/fx/easing.js'></script>
--- a/src/html/loader.js
+++ b/src/html/loader.js
@@ -2,16 +2,17 @@
// client/browser module server defined in the narwhal/server module, or some
// similar mechanism. this file is simply an anonymous function declaration.
// the server constructs an inline script to inject anywhere in an HTML page,
// along with its "path" argument (the base URL from which to download
// modules). The function returns a module loader API function/object called
// "require" that can then be chained with .preload(ids), .when(id),
// .async(id), or other calls, depending on what services are needed to load
// this particular page.
+
(function (path) {
// ultimately, we're exporting a "require" API to global scope, and
// returning that same object.
var require = this.require = function (id) {
if (!require.require)
throw new Error("require is not yet available");
return require.require(id);
@@ -98,9 +99,9 @@
// maintaining the require object along the call chain.
require.bridge = function (block) {
block(require);
return require;
};
// return the require object for chaining
return require;
-}).call(this,"/.js/").preload(["ref-send", "sandbox", "narwhal/client", "array", "object", "string", "function", "regexp", "reactor", "date", "global", "system", "binary"])
\ No newline at end of file
+}).call(this,"/.js/");
--- a/src/html/test.html
+++ b/src/html/test.html
@@ -1,13 +1,14 @@
<!DOCTYPE html>
<html><head>
<link rel="stylesheet" type="text/css" href="qunit.css">
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
+ require.preload(["ref-send", "sandbox", "narwhal/client", "array", "object", "string", "function", "regexp", "reactor", "date", "global", "system", "binary"]);
require.async("bespin/tests/bootTests");
</script>
</head>
<body>
<h1 id="qunit-header">Bespin Tests</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>