Jump To …

cake.coffee

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 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'

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 path.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()}"