Dynamically-generated Cakefile Tasks
Published
Cake is a task-runner for CoffeeScript.
It can be useful to invoke external scripts from cake
, if they are written in another language or simply don't fit in the Cakefile
. Suppose we have a scripts
directory populated with various text-based executables, and we want to automatically define a cake
task for each of those scripts, with an appropriate description, like so:
$ ls scripts
build.py
clean.sh
$ cake
cake build # build the project
cake clean # remove built files
$ cake build --help
build.py: usage info...
We can do this in the Cakefile
by reading each script and extracting its first comment, then defining a task with that comment as its description:
# Define tasks for any scripts in the `scripts` directory
for basename in fs.readdirSync('./scripts') then do (basename)->
return if basename[0] is '.'
filename = "./scripts/#{basename}"
contents = fs.readFileSync(filename, 'utf8')
title = basename.replace(/\..*?$/, '')
# use the first block comment in the file as its description
description = ''
for line, i in contents.split(/[\r\n]+/)
if line.match(/^#!/) then continue
if line.match(/-\*- mode/) then continue
if line.match(/^\s*(#|\/\/|$)/)
description += line.replace(/^\s*(#|\/\/)\s*/, ' ').trim()
continue
# stop reading when we encounter non-comment text
break
task(title, description, ->
# pass command-line arguments directly in to the script
index = process.argv.indexOf(title)
args = process.argv.slice(index+1)
child_process.spawn(filename, args, {
stdio: 'inherit'
env: env
}).on('exit', (code, signal)->
process.exit(code)
)
# prevent `cake` from invoking further tasks based on those arguments
global.invoke = (->)
)