Rake -- Watch for Changes - rake

Is there a way using Rake to watch depedencies for changes and execute tasks automatically?
For example, given the following Rakefile:
file 'main.o' => ["main.c", "greet.h"] do
sh "cc -c -o main.o main.c"
end
file 'greet.o' => ['greet.c'] do
sh "cc -c -o greet.o greet.c"
end
file "hello" => ["main.o", "greet.o"] do
sh "cc -o hello main.o greet.o"
end
It would be great if when I changed greet.c or main.c then hello would automatically execute.

AFAIK rake doesn't support watching files and directories with a continuous compilation approach.
The buildr project implements a continuous compilation task for java which you can get inspired by to do the job for your project.
Also, it looks like guard might help there. See the guard github profile for implementations using guard. There's even a Rake extension to do what you want!

There is also rerun https://github.com/alexch/rerun. You can do rerun rake to watch and run the default task.

Related

rake executes file task when file already exists

I have a rakefile that executes some (but not all) of it's file tasks even if the files of interest have already been built. The frustrating thing, is that paring down my rake file to a MWE resolves the problem---even though I haven't altered anything wrt the filetask definition, how the files are being selected, the dependencies, or anything else. It seems that simply removing other (file)tasks from the rakefile remedies the problem.
I realize this is a really awful question, but does anyone have ideas about what might be going on here? I'd post sample code, but my MWE works as expected and I don't have any sense for what is causing the problem in the full rake file. All I can think to do is demonstrate that my MWE is literally an excerpt from the full Rakefile, unaltered...
➜ solutionmaps cat mwe/Rakefile|sed '/^$/d'|tee a
require 'rake'
require 'rake/clean'
require 'pathname'
HOME = ENV['HOME']
SHARED_ATLAS = "#{HOME}/MRI/Manchester/data/CommonBrains/MNI_EPI_funcRes.nii"
TXT = Rake::FileList["txt/nodestrength/??.mni"]
AFNI_RAW = TXT.pathmap("afni/nodestrength/%n_raw+tlrc.HEAD")
AFNI_RAW.zip(TXT).each do |target,source|
file target => [source] do
sh("3dUndump -master #{SHARED_ATLAS} -xyz -datum float -prefix #{target.sub("+tlrc.HEAD","")} #{source}")
end
CLOBBER.push(target)
CLOBBER.push(target.sub(".HEAD",".BRIK"))
CLOBBER.push(target.sub(".HEAD",".BRIK.gz"))
end
➜ solutionmaps perl -ne 'print if ($seen{$_} .= #ARGV) =~ /10$/' Rakefile mwe/Rakefile|sed '/^$/d'|tee b
require 'rake'
require 'rake/clean'
require 'pathname'
HOME = ENV['HOME']
SHARED_ATLAS = "#{HOME}/MRI/Manchester/data/CommonBrains/MNI_EPI_funcRes.nii"
TXT = Rake::FileList["txt/nodestrength/??.mni"]
AFNI_RAW = TXT.pathmap("afni/nodestrength/%n_raw+tlrc.HEAD")
AFNI_RAW.zip(TXT).each do |target,source|
file target => [source] do
sh("3dUndump -master #{SHARED_ATLAS} -xyz -datum float -prefix #{target.sub("+tlrc.HEAD","")} #{source}")
end
CLOBBER.push(target)
CLOBBER.push(target.sub(".HEAD",".BRIK"))
CLOBBER.push(target.sub(".HEAD",".BRIK.gz"))
end
➜ solutionmaps diff a b
➜ solutionmaps
And that my mwe works as expected (that is, it does not execute the file task).
➜ mwe rake --trace --dry-run afni/nodestrength/02_raw+tlrc.HEAD
** Invoke afni/nodestrength/02_raw+tlrc.HEAD (first_time, not_needed)
** Invoke txt/nodestrength/02.mni (first_time, not_needed)
But the full rakefile does not.
rake --trace --dry-run afni/nodestrength/02_raw+tlrc.HEAD
** Invoke afni/nodestrength/02_raw+tlrc.HEAD (first_time)
** Invoke txt/nodestrength/02.mni (first_time, not_needed)
** Execute (dry run) afni/nodestrength/02_raw+tlrc.HEAD
➜ solutionmaps ls afni/nodestrength/02_raw+tlrc.HEAD
afni/nodestrength/02_raw+tlrc.HEAD
Finally happened across a possible answer:
Rake determines that a file task needs to be run if the file doesn’t exist or if any of the prerequisite file tasks are newer.
Quoted from: http://madewithenvy.com/ecosystem/articles/2013/rake-file-tasks/
Since my Rakefiles are under heavy development, and my Filetasks are all pretty interrelated, this is probably why my Rakefile always wanted to rebuild everything.

GO: {GOOS} and {GOARCH} not recognised in environment

I want to change my diretory to go/pkg/darwin_amd64 but $ cd $GOPATH/pkg/${GOOS}_${GOARCH} doesn't find the folder though directory exists.
$ echo $GOPATH/pkg/${GOOS}_${GOARCH} gives /go/pkg/_ instead of /go/pkg/darwin_amd64.
$ go env prints:
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/sahilkapoor/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"
We can see that GOOS and GOARCH are defined here. I am using terminal on Mac OSX 10.10.3. What am I missing?
$GOOS and $GOARCH will only be defined in your shell if you have exported them (which, unless you are doing cross compilation, is unlikely).
When you run go env, default values are shown when they have not been overwritten by your environment. You should change your command to the following to get the desired results:
cd $(go env GOPATH)/pkg/$(go env GOOS)_$(go env GOARCH)

capistrano v2 not failing / rolling back when custom task fails

i have to compile a custom c coded binary used by our rails app.
this setup is held in a custom rake file (ourapp.rake, below)
running cap v2 i noticed the make was failing but the deploy didn't "fail".
i since just made the task
system "cd #{thedir} && exit 1" # simulate failing of custom task
but the deploy:cold doesn't fail, the debug output (below) clearly shows make failing
am i missing something? i've tried
searching for error codes/failing scenario of capistrano - nothing (lots of mentions of trying to run custom scripts on failing)
system v run v invoke
help appreciated, code below
# ourapp.rake
namespace :ourapp do
desc "Compile and Install Performant Parser"
task :compile_performant_parser do
thedir=File.join(Rails.root, 'parser')
system "cd #{thedir} && make clean && make && make install"
end # compile
desc "Compile and Install Compareplans process"
task :compile_binary do
thedir=File.join(Rails.root, 'compareplans_process/src')
#system "cd #{thedir} && make clean && make && make install"
system "exit 1"
end # compile
task :install => [:compile_performant_parser, :compile_binary ] do
puts "Preparing Ourapp for run"
end
end
additions to deploy.rb
namespace :deploy do
desc "setup ourapp dependencies, dir, binaries and (later data)"
task :setup_ourapp do
run "cd #{current_release} && /usr/bin/env bundle exec rake our app:install RAILS_ENV=#{rails_env}"
end
after 'deploy:update_code', 'deploy:setup_ourapp'
end
so i figured out that capistrano does not exit, so you need to test the error code
Capistrano run local command exit on failure
and to rollback you need to use a transaction type
How do I use transactions within custom capistrano tasks?

Rake does not recognize rules with multiple extensions

I generate PDFs from Markdown files using Rake. If a Markdown file is filename.md, I like the PDF to be filename.md.pdf not filename.pdf, so that autocompletion works the way I like and so that it's clear what the source of the PDF file is.
I have this Rake file, which works fine.
MDFILES = FileList["*.md"]
PDFS = MDFILES.ext("pdf")
desc "Build PDFs of all chapters"
task :pdfs => PDFS
# Build PDFs from Markdown source
rule ".pdf" => ".md" do |t|
sh "pandoc #{t.source} -o #{t.name}"
end
If I run rake pdfs or rake filename.pdf the PDFs are generated as expected, but the PDFs are named filename.pdf.
But I want the Rakefile to be this instead:
MDFILES = FileList["*.md"]
PDFS = MDFILES.ext("md.pdf")
desc "Build PDFs of all chapters"
task :pdfs => PDFS
# Build PDFs from Markdown source
rule "md.pdf" => ".md" do |t|
sh "pandoc #{t.source} -o #{t.name}"
end
Running rake pdfs or rake filename.md.pdf returns the error Don't know how to build task 'filename.md.pdf'.
How can I produce filenames the way I want?
By the way, this type of rule works fine with Make, to wit:
%.md.pdf : %.md
pandoc $< -o $#
I've had a similar problem myself recently when I attempted to specify an extension with multiple dots in a rule. I solved it by using a different rule syntax as described here.
Try something like this for your rule:
rule( /\.md\.pdf$/ => [
proc {|task_name| task_name.sub(/\.md\.pdf$/, '.md') }
]) do |t|
sh "pandoc #{t.source} -o #{t.name}"
end

Output when watching CoffeeScript files from a cakefile task

I would like to make a Cakefile task to watch some CoffeeScript files just like if I had run coffee -c -w js/*.coffee.
Its watching and recompiling them successfully, but it doesn't log the usual output to the terminal when there's a compile error like it would if I just ran the script from the terminal. Any idea how to make this happen?
exec = require('child_process').exec
task 'watch','watch all files and compile them as needed', (options) ->
exec 'coffee -c -w js/*.coffee', (err,stdout, stderr) ->
console.log stdout
Also, if there's a better way to invoke a coffeescript command from a cakefile than running 'exec' please post that too.
spawn instead of exec?
{spawn} = require 'child_process'
task 'watch', -> spawn 'coffee', ['-cw', 'js'], customFds: [0..2]
I've used spawn to solve this, here is an example cake file:
{spawn, exec} = require 'child_process'
option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`'
task 'build', 'continually build with --watch', ->
coffee = spawn 'coffee', ['-cw', '-o', 'lib', 'src']
coffee.stdout.on 'data', (data) -> console.log data.toString().trim()
You can see it in action with the docco project:
https://github.com/jashkenas/docco/blob/master/Cakefile
The problem with your original code was that exec only calls its callback once—after the child process has terminated. (The Node docs aren't so clear on this.) So instead of defining that callback, you should instead try
child = exec 'coffee -c -w js/*.coffee'
child.stdout.on 'data', (data) -> sys.print data
Let me know if that works for you.