Files
coffeescript/src/cake.coffee
Michael Smith ace4837365 Migrate from path.exists to fs.exists
Compatibility is kept for path.exists. Versions of node that have
made the change will use fs.exists, while older versions will fall
back to path.exists. The same goes for path.existsSync.
2012-07-02 00:20:13 -07:00

88 lines
3.4 KiB
CoffeeScript

# `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
# ([Rake](http://rake.rubyforge.org/), [Jake](http://github.com/280north/jake))
# for CoffeeScript. You define tasks with names and descriptions in a Cakefile,
# and can call them from the command line, or invoke them from other tasks.
#
# Running `cake` with no arguments will print out a list of all the tasks in the
# current directory's Cakefile.
# External dependencies.
fs = require 'fs'
path = require 'path'
helpers = require './helpers'
optparse = require './optparse'
CoffeeScript = require './coffee-script'
existsSync = fs.existsSync or path.existsSync
# Keep track of the list of defined tasks, the accepted options, and so on.
tasks = {}
options = {}
switches = []
oparse = null
# Mixin the top-level Cake functions for Cakefiles to use directly.
helpers.extend global,
# Define a Cake task with a short name, an optional sentence description,
# and the function to run as the action itself.
task: (name, description, action) ->
[action, description] = [description, action] unless action
tasks[name] = {name, description, action}
# Define an option that the Cakefile accepts. The parsed options hash,
# containing all of the command-line options passed, will be made available
# as the first argument to the action.
option: (letter, flag, description) ->
switches.push [letter, flag, description]
# Invoke another task in the current Cakefile.
invoke: (name) ->
missingTask name unless tasks[name]
tasks[name].action options
# Run `cake`. Executes all of the tasks you pass, in order. Note that Node's
# asynchrony may cause tasks to execute in a different order than you'd expect.
# If no tasks are passed, print the help screen. Keep a reference to the
# original directory name, when running Cake tasks from subdirectories.
exports.run = ->
global.__originalDirname = fs.realpathSync '.'
process.chdir cakefileDirectory __originalDirname
args = process.argv[2..]
CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile'
oparse = new optparse.OptionParser switches
return printTasks() unless args.length
try
options = oparse.parse(args)
catch e
return fatalError "#{e}"
invoke arg for arg in options.arguments
# Display the list of Cake tasks in a format similar to `rake -T`
printTasks = ->
relative = path.relative or path.resolve
cakefilePath = path.join relative(__originalDirname, process.cwd()), 'Cakefile'
console.log "#{cakefilePath} defines the following tasks:\n"
for name, task of tasks
spaces = 20 - name.length
spaces = if spaces > 0 then Array(spaces + 1).join(' ') else ''
desc = if task.description then "# #{task.description}" else ''
console.log "cake #{name}#{spaces} #{desc}"
console.log oparse.help() if switches.length
# Print an error and exit when attempting to use an invalid task/option.
fatalError = (message) ->
console.error message + '\n'
console.log 'To see a list of all tasks/options, run "cake"'
process.exit 1
missingTask = (task) -> fatalError "No such task: #{task}"
# When `cake` is invoked, search in the current and all parent directories
# to find the relevant Cakefile.
cakefileDirectory = (dir) ->
return dir if existsSync path.join dir, 'Cakefile'
parent = path.normalize path.join dir, '..'
return cakefileDirectory parent unless parent is dir
throw new Error "Cakefile not found in #{process.cwd()}"