topical media & game development
mobile-graphic-easel-build-build.js / js
#!/usr/bin/env node
// TODO: add support for recursively checking to see if we are ommiting any files
var FILE = require("fs");
var PATH = require("path");
var CHILD_PROCESS = require("child_process");
var OS = require("os");
//file system utils
var WRENCH = require("wrench");
//for parsing command line args
var OPTIMIST = require("optimist");
**********************************************************
CONFIGURATION
var json = FILE.readFileSync(PATH.resolve("./config.json"), "UTF-8");
json = JSON.parse(json);
var config =json.config_easeljs;
var SOURCE_FILES = [];
// listing of all source files, with dependencies listed in order:
SOURCE_FILES = config.SOURCE_FILES;
// default name for lib output:
var JS_FILE_NAME = config.JS_FILE_NAME;
// project name:
var PROJECT_NAME = config.PROJECT_NAME;
// url for website or github repo for project:
var PROJECT_URL = config.PROJECT_URL;
// name of directory for docs:
var DOCS_DIR_NAME = PROJECT_NAME + config.DOCS_DIR_NAME;
// name of file for zipped docs:
var DOCS_FILE_NAME = DOCS_DIR_NAME + config.DOCS_FILE_NAME
// name of directory where generated files are placed
var OUTPUT_DIR_NAME = __dirname + config.OUTPUT_DIR_NAME;
// path to directory that includes YUI Doc templates
var TEMPLATE_DIR_PATH = __dirname + config.TEMPLATE_DIR_PATH;
// tmp directory used when running scripts:
var TMP_DIR_NAME = __dirname + config.TMP_DIR_NAME;
// paths to tools:
var GOOGLE_CLOSURE_PATH = PATH.resolve("../"+PATH.normalize(config.GOOGLE_CLOSURE_PATH))
/*
END CONFIGURATION
************************************************************/
OPTIMIST
.describe("l", "List all available tasks")
.alias("l", "list")
.boolean("l")
.describe("h", "Display usage")
.alias("h", "help")
.boolean("h")
.describe("version", "Build version number (x.x.x) defaults 'NEXT'")
.string("version")
.default("version", "NEXT")
.describe("tasks", "Task to run options: [ALL, BUILDDOCS, BUILDSOURCE, CLEAN]")
.default("tasks", "ALL")
.describe("format", "Formatting minified JS :[STANDARD, PRETTY_PRINT]")
.string("format")
.default("format", "STANDARD")
.usage("Build Task Manager for "+PROJECT_NAME+"\nUsage\n$0 [-h] [-l] --tasks=TASK [--version=DOC_VERSION] [--format=STANDARD]");
//name of minified js file.
var js_file_name = JS_FILE_NAME;
var version;
var verbose;
var format;
var TASK = {
ALL:"ALL",
BUILDDOCS:"BUILDDOCS",
BUILDSOURCE:"BUILDSOURCE",
CLEAN:"CLEAN"
};
var extraSourceFiles;
//main entry point for script. Takes optimist argv object which
//contains command line arguments.
//This function is called at the bottom of the script
function main(argv)
{
if(argv.h || argv.help)
{
displayUsage();
process.exit(0);
}
if(argv.l || argv.list)
{
displayTasks();
process.exit(0);
}
//default doesn't seem to be working for OPTIMIST right now
//if task is not specified, we default to ALL
var task = (!argv.tasks)?"ALL":argv.tasks.toUpperCase();
format = (!argv.format)? "STANDARD" : argv.format.toUpperCase() ;
if(!taskIsRecognized(task))
{
print(setColorText("Unrecognized task : " + task, "red"));
displayUsage();
process.exit(1);
}
version = argv.version || "NEXT";
var type = OS.type().toLowerCase();
if (type.indexOf("windows") != -1) {
os = type;
} else if (type.indexOf("darwin") != -1) {
os = type;
}
if(argv.o)
{
js_file_name = argv.o;
}
var shouldBuildSource = (task == TASK.BUILDSOURCE);
var shouldBuildDocs = (task == TASK.BUILDDOCS);
if(task==TASK.CLEAN)
{
cleanTask(
function(success)
{
print(setColorText("Clean Task Completed", "green"));
}
);
}
if(task == TASK.ALL)
{
shouldBuildSource = true;
shouldBuildDocs = true;
}
if(shouldBuildDocs && (version == undefined))
{
displayUsage();
process.exit(0);
}
if(shouldBuildSource)
{
buildSourceTask(function(success)
{
print(setColorText("\nBuild Source Task Complete", "green"));
if(shouldBuildDocs)
{
buildDocsTask(version,
function(success)
{
print(setColorText("Build Docs Task Complete", "green"));
}
);
}
});
}
if(shouldBuildDocs && task != "ALL")
{
buildDocsTask(version,
function(success)
{
print(setColorText("Build Docs Task Complete","green"));
}
);
}
}
******** TASKS ************
function cleanTask(completeHandler)
{
if(FILE.existsSync(TMP_DIR_NAME))
{
WRENCH.rmdirSyncRecursive(TMP_DIR_NAME);
}
if(FILE.existsSync(OUTPUT_DIR_NAME))
{
WRENCH.rmdirSyncRecursive(OUTPUT_DIR_NAME);
}
}
function buildSourceTask(completeHandler)
{
if(!FILE.existsSync(OUTPUT_DIR_NAME))
{
FILE.mkdirSync(OUTPUT_DIR_NAME);
}
js_file_name = js_file_name.split("\%VERSION%").join(version);
var file_args = [];
var len = SOURCE_FILES.length;
for(var i = 0; i < len; i++)
{
file_args.push("--js");
var dirName = '"'+PATH.resolve(__dirname + SOURCE_FILES[i])+'"';
var pattern = /[\w.\/% ]+version.js/g;
var result = pattern.test(dirName);
if (result) {
var versionData = FILE.readFileSync(PATH.resolve(__dirname + SOURCE_FILES[i]), "UTF-8");
pattern = /\/\*version\*\/"([\w.]+)"/g;
var hasVersionFile = pattern.test(versionData);
if (hasVersionFile) {
var updateValues = {date:new Date().toUTCString(), version:version};
updatedVersionData = replaceMetaData(versionData, updateValues);
if (updatedVersionData.length != 0 || updatedVersionData != null || updatedVersionData != "") {
FILE.writeFileSync(PATH.resolve(__dirname + SOURCE_FILES[i]), updatedVersionData, "UTF-8");
} else {
console.log(setColorText("Error -- updating version.js","red"));
}
}
}
file_args.push(dirName);
}
var tmp_file = '"'+PATH.join(OUTPUT_DIR_NAME,"tmp.js")+'"';
var final_file = PATH.join(OUTPUT_DIR_NAME, js_file_name);
GOOGLE_CLOSURE_PATH = '"'+GOOGLE_CLOSURE_PATH+'"';
var cmd;
if (format == "STANDARD") {
cmd = [
"java", "-jar", GOOGLE_CLOSURE_PATH
].concat(
file_args
).concat(
["--js_output_file", tmp_file]
);
} else if (format == "PRETTY_PRINT") {
cmd = [ "java", "-jar", GOOGLE_CLOSURE_PATH ].concat(file_args).concat(["--js_output_file", tmp_file]).concat(["--formatting", "PRETTY_PRINT"]).concat(["--compilation_level", "WHITESPACE_ONLY"]);
}
CHILD_PROCESS.exec(
cmd.join(" "),
function(error, stdout, stderr)
{
if (error !== null)
{
print(setColorText("Error Running Google Closure : " + error, "red"));
exitWithFailure();
}
var license_data = FILE.readFileSync(__dirname + "/license.txt", "UTF-8");
var path = tmp_file.substring(1, tmp_file.length-1);
var final_data = FILE.readFileSync(path, "UTF-8");
FILE.writeFileSync(final_file, license_data + final_data, "UTF-8");
FILE.unlinkSync(path);
completeHandler(true);
}
);
}
function buildDocsTask(version, completeHandler)
{
if(!FILE.existsSync(OUTPUT_DIR_NAME))
{
FILE.mkdirSync(OUTPUT_DIR_NAME);
}
var parser_in="../src";
var parser_out= PATH.join(TMP_DIR_NAME , "parser");
var doc_dir=DOCS_DIR_NAME.split("\%VERSION%").join(version);
var doc_file=DOCS_FILE_NAME.split("\%VERSION%").join(version);
var generator_out=PATH.join(OUTPUT_DIR_NAME, doc_dir);
var zipCommand = "";
var yuidocCommand = ["yuidoc -q --themedir ./createjsTheme --outdir "+"./output/"+doc_dir+" --project-version", version];
var type = OS.type().toLowerCase();
if(type.indexOf("windows") != -1){
//If 7zip.exe is currently with the /build directory.
zipCommand = "..\\tools\\7-Zip\\7z a "+"output\\"+doc_file+" "+"output\\"+ doc_dir +" > \%temp%\\7z-log.txt";
} else {
zipCommand = "cd ./output;zip -rq " + doc_file + " " + ""+doc_dir+" " + "*.DS_Store";
}
CHILD_PROCESS.exec(
yuidocCommand.join(" "),
function(error, stdout, stderr)
{
if (error !== null)
{
print(setColorText("Error Running YUI DOC : " + error, "red"));
exitWithFailure();
}
CHILD_PROCESS.exec(
zipCommand,
function(error, stdout, stderr)
{
if (error !== null)
{
print(setColorText("Error ZIPPING Docs :" + error, "red"));
exitWithFailure();
}
completeHandler(true);
});
});
}
************* some util methods *****************
function setColorText(str, color) {
var type = color.toLowerCase();
var colorStr = ""
switch(type) {
case "red":
colorStr = "\033[31m"+str+"\033[0m";
break;
case "green":
colorStr = "\033[32m"+str+"\033[0m";
break;
case "blue":
colorStr = "\033[34m"+str+"\033[0m"
break;
case "magenta":
colorStr = "\033[35m"+str+"\033[0m"
break;
case "white":
colorStr = "\033[37m"+str+"\033[0m"
break;
case "cyan":
colorStr = "\033[36m"+str+"\033[0m";
break;
case "yellow":
colorStr = "\033[33m"+str+"\033[0m";
break;
default:
colorStr = str;
}
return colorStr;
}
function replaceMetaData(data, values) {
var finalResult = "";
var newData = data;
for(var n in values) {
var pattern = new RegExp("(\/\\*"+n+"\\*\/\")(.*)(\";)", "i");
var result = pattern.test(data);
if (result) {
finalResult = newData.replace(pattern, "$1"+values[n]+"$3");
newData = finalResult;
} else {
console.log(setColorText("Error -- Unable to resolve value:"+ pattern, "red"));
}
}
return finalResult;
}
function exitWithFailure()
{
process.exit(1);
}
function displayUsage()
{
print(setColorText(OPTIMIST.help(), "yellow"));
}
function displayTasks()
{
var out = "Available tasks: ";
for(var _t in TASK)
{
out += TASK[_t] +", "
}
print(setColorText(out.slice(0, -2), "Cyan"));
}
function taskIsRecognized(task)
{
return TASK.hasOwnProperty(task);
}
function print(msg)
{
console.log(msg);
}
//call the main script entry point
main(OPTIMIST.argv);
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.