Comparing version 0.1.12 to 0.1.13
743
lib/jake.js
@@ -1,4 +0,3 @@ | ||
#!/usr/bin/env node | ||
/* | ||
* Node-Jake JavaScript build tool | ||
* Jake JavaScript build tool | ||
* Copyright 2112 Matthew Eernisse (mde@fleegix.org) | ||
@@ -20,138 +19,41 @@ * | ||
var JAKE_VERSION = '0.1.12' | ||
, jake | ||
, args = process.argv.slice(2) | ||
var jake | ||
, fs = require('fs') | ||
, path = require('path') | ||
, sys = require('sys') | ||
, usage | ||
, parseopts = {} | ||
, optsReg | ||
, Parser | ||
, parsed | ||
, opts | ||
, cmds | ||
, taskName | ||
, jakefile | ||
, dirname | ||
, isCoffee | ||
, exists | ||
, tasks; | ||
, path = require('path'); | ||
var Namespace = function (name, parentNamespace) { | ||
this.name = name; | ||
this.parentNamespace = parentNamespace; | ||
this.childNamespaces = {}; | ||
this.tasks = {}; | ||
}; | ||
exists = function () { | ||
var cwd = process.cwd(); | ||
if (path.existsSync(jakefile) || path.existsSync(jakefile + '.js') || | ||
path.existsSync(jakefile + '.coffee')) { | ||
return true; | ||
} | ||
process.chdir(".."); | ||
if (cwd === process.cwd()) { | ||
return false; | ||
} | ||
return exists(); | ||
}; | ||
usage = '' | ||
+ 'Node-Jake JavaScript build tool\n' | ||
+ '********************************************************************************\n' | ||
+ 'If no flags are given, Node-Jake looks for a Jakefile or Jakefile.js in the current directory.\n' | ||
+ '********************************************************************************\n' | ||
+ '{Usage}: jake [options] target (commands/options ...)\n' | ||
+ '\n' | ||
+ '{Options}:\n' | ||
+ ' -f, --jakefile FILE Use FILE as the Jakefile\n' | ||
+ ' -C, --directory DIRECTORY Change to DIRECTORY before running tasks.\n' | ||
+ ' -T, --tasks Display the tasks, with descriptions, then exit.\n' | ||
+ ' -h, --help Outputs help information\n' | ||
+ ' -V, --version Outputs Node-Jake version\n' | ||
+ ''; | ||
/** | ||
* @constructor | ||
* Parses a list of command-line args into a key/value object of | ||
* options and an array of positional commands. | ||
* @ param {Array} opts A list of options in the following format: | ||
* [{full: 'foo', abbr: 'f'}, {full: 'bar', abbr: 'b'}]] | ||
* A Jake task | ||
*/ | ||
parseopts.Parser = function (opts) { | ||
// Positional commands parse out of the args | ||
this.cmds = []; | ||
// A key/value object of matching options parsed out of the args | ||
this.opts = {}; | ||
// Data structures used for parsing | ||
this.reg = []; | ||
this.shortOpts = {}; | ||
this.longOpts = {}; | ||
var item; | ||
for (var i = 0, ii = opts.length; i < ii; i++) { | ||
item = opts[i]; | ||
this.shortOpts[item.abbr] = item.full; | ||
this.longOpts[item.full] = item.full; | ||
} | ||
this.reg = opts; | ||
var Task = function (name, prereqs, action, async, type) { | ||
this.name = name; | ||
this.fullName = null; | ||
this.prereqs = prereqs; | ||
this.action = action; | ||
this.desription = null; | ||
this.async = async === true; | ||
this.type = type; | ||
this.done = false; | ||
}; | ||
parseopts.Parser.prototype = new function () { | ||
Task.prototype = new (function () { | ||
this.invoke = function () { | ||
jake.runTask(this.fullName, arguments, true); | ||
}; | ||
/** | ||
* Parses an array of arguments into options and positional commands | ||
* Any matcthing opts end up in a key/value object keyed by the 'full' | ||
* name of the option. Any args that aren't passed as options end up in | ||
* an array of positional commands. | ||
* Any options passed without a value end up with a value of null | ||
* in the key/value object of options | ||
* If the user passes options that are not defined in the list passed | ||
* to the constructor, the parser throws an error 'Unknown option.' | ||
* @param {Array} args The command-line args to parse | ||
*/ | ||
this.parse = function (args) { | ||
var cmds = [] | ||
, opts = {} | ||
, arg | ||
, argName | ||
, argItems; | ||
this.execute = function () { | ||
jake.reenableTask(this.fullName, false); | ||
jake.runTask(this.fullName, arguments, false); | ||
}; | ||
while (args.length) { | ||
arg = args.shift(); | ||
if (arg.indexOf('--') == 0) { | ||
argItems = arg.split('='); | ||
argName = this.longOpts[argItems[0].substr(2)]; | ||
if (argName) { | ||
// If there's no attached value, value is null | ||
opts[argName] = argItems[1] || true; | ||
} | ||
else { | ||
throw new Error('Unknown option "' + argItems[0] + '"'); | ||
} | ||
} | ||
else if (arg.indexOf('-') == 0) { | ||
argName = this.shortOpts[arg.substr(1)]; | ||
if (argName) { | ||
// If there is no following item, or the next item is | ||
// another opt, value is null | ||
opts[argName] = (!args[0] || (args[0].indexOf('-') == 0)) ? | ||
true : args.shift(); | ||
} | ||
else { | ||
throw new Error('Unknown option "' + arg + '"'); | ||
} | ||
} | ||
else { | ||
cmds.push(arg); | ||
} | ||
} | ||
this.cmds = cmds; | ||
this.opts = opts; | ||
this.reenable = function (deep) { | ||
jake.reenableTask(this.fullName, deep); | ||
}; | ||
})(); | ||
var Namespace = function (name, parentNamespace) { | ||
this.name = name; | ||
this.parentNamespace = parentNamespace; | ||
this.childNamespaces = {}; | ||
this.tasks = {}; | ||
}; | ||
@@ -169,4 +71,8 @@ | ||
var _this = this | ||
// The list of tasks/dependencies to run, parsed recursively | ||
// and run bottom-up, so dependencies run first | ||
, _taskIndex = 0 | ||
, _modTimes = {} | ||
, _workingTaskList = [] | ||
// The list of tasks/prerequisites to run, parsed recursively | ||
// and run bottom-up, so prerequisites run first | ||
, _taskList = [] | ||
@@ -201,140 +107,34 @@ // A dictionary of loaded tasks, to ensure that all tasks | ||
/** | ||
* Tells us if the task has any dependencies | ||
* @param {Array.<String>} deps An array of dependencies | ||
* @return {Boolean} true if deps is a non-empty Array | ||
* Tells us if the task has any prerequisites | ||
* @param {Array.<String>} prereqs An array of prerequisites | ||
* @return {Boolean} true if prereqs is a non-empty Array | ||
*/ | ||
, _taskHasDeps = function (deps) { | ||
return !!(deps && _isArray(deps) && deps.length); | ||
, _taskHasPrereqs = function (prereqs) { | ||
return !!(prereqs && _isArray(prereqs) && prereqs.length); | ||
} | ||
/** | ||
* Handles a file task | ||
* @param {Error} err Error, if any, returned from fs.lstat | ||
* @param {fs.Stats} stats Stats obj, if any, returned from fs.lstat | ||
* @param {String} name The task name | ||
* @param {Array} deps The array of dependencies, if any | ||
* @callback {Function} Callback for running the task | ||
*/ | ||
, _handleFileTask = function (name, opts, callback) { | ||
var err = opts.err | ||
, stats = opts.stats | ||
, deps = opts.deps | ||
, includeDeps = opts.includeDeps | ||
, subOpts = {}; | ||
// If the task has dependencies these are invoked in order. | ||
// If any of them were changed after the current file, or | ||
// if the current file does not exist, then push the current | ||
// task to the list of tasks and update the time of last change. | ||
if (includeDeps && _taskHasDeps(deps)) { | ||
stats = stats || {ctime: 0}; | ||
// Clone original opts, set root to false | ||
_mixin(subOpts, opts); | ||
subOpts.root = false; | ||
for (var i = 0, ii = deps.length, depsLeft = deps.length, maxTime = stats.ctime; | ||
i < ii; i++) { | ||
_parseDeps(deps[i], subOpts, function (ctime) { | ||
depsLeft -= 1; | ||
maxTime = (maxTime == null || maxTime < ctime) ? ctime : maxTime; | ||
if (depsLeft == 0) { | ||
if (maxTime > stats.ctime) { | ||
_taskList.push(name); | ||
} | ||
callback(maxTime); | ||
} | ||
}); | ||
} | ||
} | ||
// If it does not have dependencies and could not | ||
// be found, simply execute the task and use the | ||
// current time as the last time it changed. | ||
else if (err) { | ||
// File not found | ||
if (err.errno == 2) { | ||
_taskList.push(name); | ||
callback(new Date()); | ||
} | ||
// Errors are rethrown. | ||
else { | ||
throw new Error(err.message); | ||
} | ||
} | ||
// No dependencies and the file already existed, then don't | ||
// do anything and just return the time of last changed. | ||
else { | ||
callback(stats.ctime); | ||
} | ||
} | ||
/** | ||
* Parses all dependencies of a task (and their dependencies, etc.) | ||
* recursively -- depth-first, so deps run first | ||
* Parses all prerequisites of a task (and their prerequisites, etc.) | ||
* recursively -- depth-first, so prereqs run first | ||
* @param {String} name The name of the current task whose | ||
* dependencies are being parsed. | ||
* @param {Object} opts -- has following options: | ||
* root {Boolean}: Is this the root task of a dependency tree or not | ||
* @param {Function} [callback] Callbacks for async tasks | ||
* prerequisites are being parsed. | ||
* @param {Boolean} [isRoot] Is this the root task of a prerequisite tree or not | ||
* @param {Boolean} [includePrereqs] Whether or not to descend into prerequs | ||
*/ | ||
, _parseDeps = function (name, opts, callback) { | ||
, _parsePrereqs = function (name, isRoot, includePrereqs) { | ||
var task = _this.getTask(name) | ||
, deps = task ? task.deps : [] | ||
, root = opts.root | ||
, includeDeps = opts.includeDeps | ||
, subOpts = {}; | ||
, prereqs = task ? task.prereqs : []; | ||
// No task found | ||
if (!task) { | ||
// If this is the root task, it's a failure if the task cannot be found. | ||
if (root) { | ||
throw new Error('Task "' + name + '" is not defined in the Jakefile.'); | ||
} | ||
// If this is not the root task, we'll just assume the name is a file. | ||
// Search for a file instead and provide the callback with the | ||
// last time it changed | ||
fs.lstat(name, function(err, stats) { | ||
if (err) { | ||
throw new Error(err.message); | ||
} | ||
callback(stats.ctime); | ||
}); | ||
// No task found -- if it's the root, throw, because we know that | ||
// *should* be an existing task. Otherwise it could be a file prereq | ||
if (isRoot && !task) { | ||
throw new Error('task not found'); | ||
} | ||
// The task was found | ||
else { | ||
// File task | ||
if (task.isFile) { | ||
fs.lstat(name, function(err, stats) { | ||
var taskOpts = { | ||
err: err | ||
, stats: stats | ||
, deps: deps | ||
, includeDeps: includeDeps | ||
}; | ||
_handleFileTask(name, taskOpts, callback); | ||
}); | ||
} | ||
// Normal task | ||
else { | ||
// If the task has dependencies, execute those first and then | ||
// push the task to the task list. In case it will be used as a | ||
// dependancy for a file task, the last time of change is set to | ||
// the current time in order to force files to update as well. | ||
if (includeDeps && _taskHasDeps(deps)) { | ||
// Clone original opts, set root to false | ||
_mixin(subOpts, opts); | ||
subOpts.root = false; | ||
for (var i = 0, ii = deps.length, ctr = deps.length; i < ii; i++) { | ||
_parseDeps(deps[i], subOpts, function () { | ||
ctr -= 1; | ||
if (ctr == 0) { | ||
_taskList.push(name); | ||
callback(new Date()); | ||
} | ||
}); | ||
} | ||
if (includePrereqs && _taskHasPrereqs(prereqs)) { | ||
for (var i = 0, ii = prereqs.length; i < ii; i++) { | ||
_parsePrereqs(prereqs[i], false, includePrereqs); | ||
} | ||
// If the task does not have dependencies, just push it. | ||
else { | ||
_taskList.push(name); | ||
callback(new Date()); | ||
} | ||
} | ||
_workingTaskList.push(name); | ||
} | ||
@@ -345,2 +145,3 @@ }; | ||
// ================= | ||
this.errorCode = undefined; | ||
// Name/value map of all the various tasks defined in a Jakefile. | ||
@@ -357,16 +158,20 @@ // Non-namespaced tasks are placed into 'default.' | ||
this.populateAndProcessTaskList = function (name, includeDeps, callback) { | ||
this.populateAndProcessTaskList = function (name, includePrereqs, callback) { | ||
var opts = { | ||
root: true | ||
, includeDeps: includeDeps | ||
, includePrereqs: includePrereqs | ||
}; | ||
// Parse all the dependencies up front. This allows use of a simple | ||
// Parse all the prerequisites up front. This allows use of a simple | ||
// queue to run all the tasks in order, and treat sync/async essentially | ||
// the same. | ||
_parseDeps(name, opts, callback); | ||
_parsePrereqs(name, opts, callback); | ||
}; | ||
this.createTree = function (name, isRoot, includePrereqs) { | ||
_parsePrereqs(name, isRoot, includePrereqs); | ||
}; | ||
/** | ||
* Initial function called to run the specified task. Parses all the | ||
* dependencies and then kick off the queue-processing | ||
* prerequisites and then kicks off the queue-processing | ||
* @param {String} name The name of the task to run | ||
@@ -378,27 +183,22 @@ * @param {Array} args The list of command-line args passed after | ||
*/ | ||
this.runTask = function (name, includeDeps) { | ||
this.populateAndProcessTaskList(name, includeDeps, function () { | ||
if (!_taskList.length) { | ||
_this.die('No tasks to run.'); | ||
} | ||
// Kick off running the list of tasks | ||
_this.runNextTask(); | ||
}); | ||
this.runTask = function (name, args, includePrereqs) { | ||
this.createTree(name, true, includePrereqs); | ||
_taskList.splice.apply(_taskList, [_taskIndex, 0].concat(_workingTaskList)); | ||
_workingTaskList = []; | ||
this.runNextTask(args); | ||
}; | ||
this.reenableTask = function (name, includeDeps) { | ||
var self = this; | ||
this.populateAndProcessTaskList(name, includeDeps, function () { | ||
var name | ||
, task; | ||
if (!_taskList.length) { | ||
_this.die('No tasks to reenable.'); | ||
this.reenableTask = function (name, includePrereqs) { | ||
_parsePrereqs(name, true, includePrereqs); | ||
if (!_workingTaskList.length) { | ||
fail('No tasks to reenable.'); | ||
} | ||
else { | ||
for (var i = 0, ii = _workingTaskList.length; i < ii; i++) { | ||
name = _workingTaskList[i]; | ||
task = this.getTask(name); | ||
task.done = false; | ||
} | ||
else { | ||
while (name = (_taskList.shift())) { | ||
task = self.getTask(name); | ||
task.done = false; | ||
} | ||
} | ||
}); | ||
} | ||
_workingTaskList = []; | ||
}; | ||
@@ -446,76 +246,105 @@ | ||
*/ | ||
this.runNextTask = function () { | ||
var name = _taskList.shift() | ||
this.runNextTask = function (args) { | ||
var name = _taskList[_taskIndex] | ||
, task | ||
, parsed | ||
, passArgs; | ||
, prereqs | ||
, prereqName | ||
, prereqTask | ||
, stats | ||
, modTime; | ||
// If there are still tasks to run, do it | ||
if (name) { | ||
_taskIndex++; | ||
task = this.getTask(name); | ||
// Run tasks only once, even if it ends up in the task queue | ||
// multiple times | ||
if (task.done) { | ||
complete(); | ||
} | ||
// Okie, we haven't done this one | ||
else { | ||
// Flag this one as done, no repeatsies | ||
task.done = true; | ||
// TODO Do this once instead of on each iteration | ||
parsed = this.parseArgs(this.args); | ||
passArgs = parsed.cmds; | ||
if (parsed.opts) { | ||
passArgs = parsed.cmds.concat(parsed.opts); | ||
} | ||
// Task or file-task | ||
if (task) { | ||
prereqs = task.prereqs; | ||
// Run this mofo | ||
task.handler.apply(task, passArgs); | ||
// Async tasks call this themselves | ||
if (!task.async) { | ||
// Run tasks only once, even if it ends up in the task queue multiple times | ||
if (task.done) { | ||
complete(); | ||
} | ||
} | ||
} | ||
}; | ||
// Okie, we haven't done this one | ||
else { | ||
// Flag this one as done, no repeatsies | ||
task.done = true; | ||
/** | ||
* Parse the list of args into positional args and a final keyword/value | ||
* object to pass to the task invocations. | ||
* @param {Array} args A list of arguments to parse. | ||
*/ | ||
this.parseArgs = function (args) { | ||
var cmds = [] | ||
, opts = {} | ||
, pat = /:|=/ | ||
, argItems | ||
, hasOpts = false; | ||
if (task.type == 'file') { | ||
try { | ||
stats = fs.statSync(name); | ||
modTime = stats.ctime; | ||
} | ||
catch (e) { | ||
// Assume there's a task to fall back to to generate the file | ||
} | ||
for (var i = 0; i < args.length; i++) { | ||
argItems = args[i].split(pat); | ||
if (argItems.length > 1) { | ||
hasOpts = true; | ||
opts[argItems[0]] = argItems[1]; | ||
if (prereqs.length) { | ||
for (var i = 0, ii = prereqs.length; i < ii; i++) { | ||
prereqName = prereqs[i]; | ||
prereqTask = this.getTask(prereqName); | ||
// Run the action if the prereq is a normal task, or a file/directory | ||
// task with a mod-date more recent than the one for this file | ||
if ((prereqTask && prereqTask.type == 'task') || !modTime || | ||
_modTimes[prereqName] > modTime) { | ||
if (typeof task.action == 'function') { | ||
task.action.apply(task, args || []); | ||
// The action may have created/modified the file | ||
// --------- | ||
// If there's a valid file at the end of running the task, | ||
// use its mod-time as last modified | ||
try { | ||
stats = fs.statSync(name); | ||
modTime = stats.ctime; | ||
} | ||
// If there's still no actual file after running the file-task, | ||
// treat this simply as a plain task -- the current time will be | ||
// the mod-time for anything that depends on this file-task | ||
catch (e) { | ||
modTime = new Date(); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
else { | ||
if (typeof task.action == 'function') { | ||
task.action.apply(task, args || []); | ||
modTime = new Date(); | ||
} | ||
} | ||
_modTimes[name] = modTime; | ||
// Async tasks call this themselves | ||
if (!task.async) { | ||
complete(); | ||
} | ||
} | ||
else { | ||
// Run this mofo | ||
if (typeof task.action == 'function') { | ||
task.action.apply(task, args || []); | ||
} | ||
// Async tasks call this themselves | ||
if (!task.async) { | ||
complete(); | ||
} | ||
} | ||
} | ||
} | ||
// Task doesn't exist; assume file. Just get the mod-time if the file | ||
// actually exists | ||
else { | ||
cmds.push(args[i]); | ||
stats = fs.statSync(name); | ||
_modTimes[name] = stats.ctime; | ||
complete(); | ||
} | ||
} | ||
if (!hasOpts) { opts = null; } | ||
return {cmds: cmds, opts: opts}; | ||
}; | ||
/** | ||
* Prints out a message and ends the jake program. | ||
* @param {String} str The message to print out before dying. | ||
*/ | ||
this.die = function (str) { | ||
var len = str.length, i; | ||
for (i = 0; i < len; i+=25) { | ||
sys.print(str.slice(i,i+25)); | ||
} | ||
process.exit(); | ||
}; | ||
this.parseAllTasks = function () { | ||
@@ -548,3 +377,3 @@ var _parseNs = function (name, ns) { | ||
*/ | ||
this.showAllTaskDescriptions = function () { | ||
this.showAllTaskDescriptions = function (f) { | ||
var maxTaskNameLength = 0 | ||
@@ -554,3 +383,5 @@ , task | ||
, padding | ||
, descr; | ||
, name | ||
, descr | ||
, filter = typeof f == 'string' ? f : null; | ||
@@ -566,3 +397,9 @@ for (var p in jake.Task) { | ||
for (var p in jake.Task) { | ||
if (filter && p.indexOf(filter) == -1) { | ||
continue; | ||
} | ||
task = jake.Task[p]; | ||
name = '\033[32m' + p + '\033[39m '; | ||
// Create padding-string with calculated length | ||
@@ -572,185 +409,65 @@ padding = (new Array(maxTaskNameLength - p.length + 2)).join(' '); | ||
descr = task.description || '(No description)'; | ||
// Comment-colors FTW | ||
descr = "\033[90m # "+ descr +"\033[39m"; | ||
descr = '\033[90m # ' + descr + '\033[39m \033[37m \033[39m'; | ||
console.log('jake ' + p + padding + descr); | ||
console.log('jake ' + name + padding + descr); | ||
} | ||
process.exit(); | ||
}; | ||
}(); | ||
this.createTask = function () { | ||
var args = Array.prototype.slice.call(arguments) | ||
, task | ||
, type | ||
, name | ||
, action | ||
, async | ||
, prereqs = []; | ||
/** | ||
* @constructor | ||
* A Jake task | ||
*/ | ||
jake.Task = function (name, deps, handler, async, isFile) { | ||
this.name = name; | ||
this.fullName = null; | ||
this.deps = deps; | ||
this.handler = handler; | ||
this.desription = null; | ||
this.async = async === true; | ||
this.isFile = isFile; | ||
this.done = false; | ||
}; | ||
type = args.shift() | ||
jake.Task.prototype = new (function () { | ||
this.invoke = function () { | ||
jake.runTask(this.fullName, true); | ||
}; | ||
// name, [deps], [action] | ||
// Older name (string) + deps (array) format | ||
if (typeof args[0] == 'string') { | ||
name = args.shift(); | ||
if (_isArray(args[0])) { | ||
prereqs = args.shift(); | ||
} | ||
if (typeof args[0] == 'function') { | ||
action = args.shift(); | ||
async = args.shift(); | ||
} | ||
} | ||
// name:deps, [action] | ||
// Newer object-literal syntax, e.g.: {'name': ['depA', 'depB']} | ||
else { | ||
obj = args.shift() | ||
for (var p in obj) { | ||
prereqs = prereqs.concat(obj[p]); | ||
name = p; | ||
} | ||
action = args.shift(); | ||
async = args.shift(); | ||
} | ||
this.execute = function () { | ||
jake.reenableTask(this.fullName, true); | ||
jake.runTask(this.fullName, false); | ||
}; | ||
if (type == 'directory') { | ||
action = function () { | ||
if (!path.existsSync(name)) { | ||
fs.mkdirSync(name, 0755); | ||
} | ||
}; | ||
} | ||
this.reenable = function (deep) { | ||
jake.reenableTask(this.fullName, deep); | ||
}; | ||
})(); | ||
task = new jake.Task(name, prereqs, action, async, type); | ||
jake.taskOrFile = function () { | ||
var args = Array.prototype.slice.call(arguments) | ||
, type = args.shift() | ||
, name = args.shift() | ||
// Dependencies are an optional arg | ||
, deps = typeof args[0] == 'function' ? | ||
[] : args.shift() | ||
, handler = args.shift() | ||
, async = args.shift() | ||
, isFile = (type == 'file'); | ||
var task = new jake.Task(name, deps, handler, async, isFile); | ||
if (jake.currentTaskDescription) { | ||
task.description = jake.currentTaskDescription; | ||
jake.currentTaskDescription = null; | ||
} | ||
jake.currentNamespace.tasks[name] = task; | ||
}; | ||
// Global functions for being called inside the Jakefile | ||
// Yes, globals are ugly, but adding a few globals keeps | ||
// the API nice and simple | ||
global.jake = jake; | ||
global.task = function (name, deps, handler, async) { | ||
var args = Array.prototype.slice.call(arguments) | ||
, type; | ||
args.unshift('task'); | ||
jake.taskOrFile.apply(global, args); | ||
}; | ||
global.file = function (name, deps, handler, async) { | ||
var args = Array.prototype.slice.call(arguments); | ||
args.unshift('file'); | ||
jake.taskOrFile.apply(global, args); | ||
}; | ||
global.desc = function (str) { | ||
jake.currentTaskDescription = str; | ||
}; | ||
global.namespace = function (name, nextLevelDown) { | ||
var curr = jake.currentNamespace | ||
, ns = new Namespace(name, curr); | ||
curr.childNamespaces[name] = ns; | ||
jake.currentNamespace = ns; | ||
nextLevelDown(); | ||
jake.currentNamespace = curr; | ||
}; | ||
global.complete = function () { | ||
jake.runNextTask(); | ||
}; | ||
global.fail = function (msg) { | ||
var message = (msg && msg.toString()) || '(No error message specified.)'; | ||
throw new Error(message); | ||
}; | ||
// ======================== | ||
// Run Jake | ||
// ======================== | ||
optsReg = [ | ||
{ full: 'directory' | ||
, abbr: 'C' | ||
} | ||
, { full: 'jakefile' | ||
, abbr: 'f' | ||
} | ||
, { full: 'tasks' | ||
, abbr: 'T' | ||
} | ||
, { full: 'help' | ||
, abbr: 'h' | ||
} | ||
, { full: 'version' | ||
, abbr: 'V' | ||
} | ||
]; | ||
Parser = new parseopts.Parser(optsReg); | ||
parsed = Parser.parse(args); | ||
opts = Parser.opts; | ||
cmds = Parser.cmds; | ||
taskName = cmds.shift(); | ||
dirname = opts.directory || process.cwd(); | ||
process.chdir(dirname); | ||
taskName = taskName || 'default'; | ||
jakefile = opts.jakefile ? | ||
opts.jakefile.replace(/\.js$/, '').replace(/\.coffee$/, '') : 'Jakefile'; | ||
if (opts.help) { | ||
jake.die(usage); | ||
} | ||
if (opts.version) { | ||
jake.die(JAKE_VERSION); | ||
} | ||
if (!exists()) { | ||
jake.die('Could not load Jakefile.\nIf no Jakefile specified with -f or --jakefile, ' + | ||
'jake looks for Jakefile or Jakefile.js in the current directory ' + | ||
'or one of the parent directories.'); | ||
} | ||
isCoffee = path.existsSync(jakefile + '.coffee'); | ||
try { | ||
if (isCoffee) { | ||
try { | ||
CoffeeScript = require('coffee-script'); | ||
if (jake.currentTaskDescription) { | ||
task.description = jake.currentTaskDescription; | ||
jake.currentTaskDescription = null; | ||
} | ||
catch (e) { | ||
jake.die('CoffeeScript is missing! Try `npm install coffee-script`'); | ||
} | ||
} | ||
tasks = require(path.join(process.cwd(), jakefile)); | ||
} | ||
catch (e) { | ||
if (e.stack) { | ||
console.log(e.stack); | ||
} | ||
jake.die('Could not load Jakefile: ' + e); | ||
} | ||
jake.currentNamespace.tasks[name] = task; | ||
}; | ||
}(); | ||
process.addListener('uncaughtException', function (err) { | ||
console.log('jake aborted.'); | ||
if (err.stack) { | ||
console.log(err.stack); | ||
} | ||
}); | ||
jake.Task = Task; | ||
jake.Namespace = Namespace; | ||
jake.parseAllTasks(); | ||
if (opts.tasks) { | ||
jake.showAllTaskDescriptions(); | ||
} | ||
else { | ||
jake.args = cmds; | ||
jake.runTask(taskName, true); | ||
} | ||
module.exports = jake; |
@@ -1,6 +0,11 @@ | ||
{ "name" : "jake" | ||
, "version" : "0.1.12" | ||
, "author" : "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)" | ||
, "main" : "./lib/jake" | ||
, "bin" : { "jake" : "./lib/jake.js" } | ||
{ "name": "jake" | ||
, "version": "0.1.13" | ||
, "author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)" | ||
, "bin": { "jake": "./bin/cli.js" } | ||
, "main": "./lib" | ||
, "repository": { | ||
"type": "git" | ||
, "url": "https://github.com/mde/jake.git" | ||
} | ||
, "preferGlobal": true | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
59251
14
1367
333
6
2