diff --git a/Cakefile b/Cakefile index 0cdd0d19..ce81a3c4 100644 --- a/Cakefile +++ b/Cakefile @@ -7,12 +7,16 @@ run: (args) -> proc.addListener 'error', (err) -> if err then puts err -task 'install', 'install CoffeeScript into /usr/local', -> +option '-p', '--prefix', 'set the installation prefix for `cake install`' + +task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options) -> + base: options.prefix or '/usr/local' + lib: base + '/lib/coffee-script' exec([ - 'mkdir -p /usr/local/lib/coffee-script' - 'cp -rf bin lib LICENSE README package.json src vendor /usr/local/lib/coffee-script' - 'ln -sf /usr/local/lib/coffee-script/lib/bin/coffee /usr/local/bin/coffee' - 'ln -sf /usr/local/lib/coffee-script/lib/bin/cake /usr/local/bin/cake' + 'mkdir -p ' + lib + 'cp -rf bin lib LICENSE README package.json src vendor ' + lib + 'ln -sf ' + lib + '/lib/bin/coffee ' + base + '/bin/coffee' + 'ln -sf ' + lib + '/lib/bin/cake ' + base + '/bin/cake' ].join(' && ')) diff --git a/lib/cake.js b/lib/cake.js index 79d78fcd..9f67eb56 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -1,5 +1,5 @@ (function(){ - var coffee, fs, no_such_task, path, print_tasks, tasks; + var coffee, fs, no_such_task, oparse, options, optparse, path, print_tasks, switches, tasks; var __hasProp = Object.prototype.hasOwnProperty; // `cake` is a simplified version of Make (Rake, Jake) for CoffeeScript. // You define tasks with names and descriptions in a Cakefile, and can call them @@ -7,7 +7,11 @@ fs = require('fs'); path = require('path'); coffee = require('coffee-script'); + optparse = require('optparse'); tasks = {}; + options = {}; + switches = []; + oparse = null; // Mixin the top-level Cake functions for Cakefiles to use. process.mixin({ // Define a task with a name, a description, and the action itself. @@ -18,12 +22,16 @@ action: action }; }, + // Define an option that the Cakefile accepts. + option: function option(letter, flag, description) { + return switches.push([letter, flag, description]); + }, // Invoke another task in the Cakefile. invoke: function invoke(name) { if (!(tasks[name])) { no_such_task(name); } - return tasks[name].action(); + return tasks[name].action(options); } }); // Running `cake` runs the tasks you pass asynchronously (node-style), or @@ -38,10 +46,12 @@ return fs.readFile('Cakefile', function(err, source) { var _a, _b, _c, arg; eval(coffee.compile(source)); + oparse = new optparse.OptionParser(switches); if (!(args.length)) { return print_tasks(); } - _a = []; _b = args; + options = oparse.parse(args); + _a = []; _b = options.arguments; for (_c = 0; _c < _b.length; _c++) { arg = _b[_c]; _a.push(invoke(arg)); @@ -52,23 +62,24 @@ }; // Display the list of Cake tasks. print_tasks = function print_tasks() { - var _a, _b, _c, _d, _e, _f, _g, i, name, spaces, task; - _a = []; _b = tasks; - for (name in _b) { if (__hasProp.call(_b, name)) { - task = _b[name]; - _a.push((function() { - spaces = 20 - name.length; - spaces = spaces > 0 ? (function() { - _c = []; _f = 0; _g = spaces; - for (_e = 0, i=_f; (_f <= _g ? i <= _g : i >= _g); (_f <= _g ? i += 1 : i -= 1), _e++) { - _c.push(' '); - } - return _c; - }).call(this).join('') : ''; - return puts("cake " + name + spaces + ' # ' + task.description); - }).call(this)); + var _a, _b, _c, _d, _e, _f, i, name, spaces, task; + puts(''); + _a = tasks; + for (name in _a) { if (__hasProp.call(_a, name)) { + task = _a[name]; + spaces = 20 - name.length; + spaces = spaces > 0 ? (function() { + _b = []; _e = 0; _f = spaces; + for (_d = 0, i=_e; (_e <= _f ? i <= _f : i >= _f); (_e <= _f ? i += 1 : i -= 1), _d++) { + _b.push(' '); + } + return _b; + }).call(this).join('') : ''; + puts("cake " + name + spaces + ' # ' + task.description); }} - return _a; + if (switches.length) { + return puts('\n' + oparse.help() + '\n'); + } }; // Print an error and exit when attempting to all an undefined task. no_such_task = function no_such_task(task) { diff --git a/lib/optparse.js b/lib/optparse.js index 95b8a0bf..afdb665e 100755 --- a/lib/optparse.js +++ b/lib/optparse.js @@ -4,7 +4,7 @@ // [short-flag (optional), long-flag, description] // And an optional banner for the usage help. op = (exports.OptionParser = function OptionParser(rules, banner) { - this.banner = banner || 'Usage: [Options]'; + this.banner = banner; this.rules = build_rules(rules); return this; }); @@ -42,7 +42,10 @@ // Return the help text for this OptionParser, for --help and such. op.prototype.help = function help() { var _a, _b, _c, _d, _e, _f, _g, i, let_part, lines, rule, spaces; - lines = [this.banner, '', 'Available options:']; + lines = ['Available options:']; + if (this.banner) { + lines.unshift(this.banner + '\n'); + } _a = this.rules; for (_b = 0; _b < _a.length; _b++) { rule = _a[_b]; diff --git a/src/cake.coffee b/src/cake.coffee index 8dd8beb0..f65a6782 100644 --- a/src/cake.coffee +++ b/src/cake.coffee @@ -5,8 +5,12 @@ fs: require 'fs' path: require 'path' coffee: require 'coffee-script' +optparse: require 'optparse' tasks: {} +options: {} +switches: [] +oparse: null # Mixin the top-level Cake functions for Cakefiles to use. process.mixin { @@ -15,10 +19,15 @@ process.mixin { task: (name, description, action) -> tasks[name]: {name: name, description: description, action: action} + # Define an option that the Cakefile accepts. + option: (letter, flag, description) -> + switches.push [letter, flag, description] + # Invoke another task in the Cakefile. invoke: (name) -> no_such_task name unless tasks[name] - tasks[name].action() + tasks[name].action(options) + } # Running `cake` runs the tasks you pass asynchronously (node-style), or @@ -29,15 +38,19 @@ exports.run: -> args: process.ARGV[2...process.ARGV.length] fs.readFile 'Cakefile', (err, source) -> eval coffee.compile source + oparse: new optparse.OptionParser switches return print_tasks() unless args.length - invoke arg for arg in args + options: oparse.parse(args) + invoke arg for arg in options.arguments # Display the list of Cake tasks. print_tasks: -> + puts '' for name, task of tasks spaces: 20 - name.length spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else '' puts "cake " + name + spaces + ' # ' + task.description + puts '\n' + oparse.help() + '\n' if switches.length # Print an error and exit when attempting to all an undefined task. no_such_task: (task) -> diff --git a/src/optparse.coffee b/src/optparse.coffee index 099a3bcf..b38a902e 100644 --- a/src/optparse.coffee +++ b/src/optparse.coffee @@ -2,7 +2,7 @@ # [short-flag (optional), long-flag, description] # And an optional banner for the usage help. op: exports.OptionParser: (rules, banner) -> - @banner: banner or 'Usage: [Options]' + @banner: banner @rules: build_rules(rules) this @@ -26,7 +26,8 @@ op::parse: (args) -> # Return the help text for this OptionParser, for --help and such. op::help: -> - lines: [@banner, '', 'Available options:'] + lines: ['Available options:'] + lines.unshift @banner + '\n' if @banner for rule in @rules spaces: 15 - rule.flag.length spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''