How do I run a rake script automatically every time I save a file in Visual Studio? I can create a batch file that wraps the command. And I'd like to trigger it on CTRL + S
. But, Visual Studio 2012 doesn't have macros.
JP Boodhoo has done it in many of his screen casts, but hasn't shared the implementation.
FYI, my rakefile
looks like this
require 'albacore'
desc 'Build Solution'
msbuild :Build do |msb|
msb.properties :configuration => :Release
msb.targets :Clean, :Build
msb.solution = 'ProjoBot.sln'
end
desc 'Run Unit Tests'
mspec :Test do |mspec|
mspec.command = 'Lib/Tools/MSpec/mspec-clr4.exe'
mspec.assemblies 'Src/Tests/ProjoBot.UnitSpecifications/bin/Release/ProjoBot.UnitSpecifications.dll'
end
task :default => [:Build, :Test]
I used the External Tools to run a batch file that executes the default Rake task.
@ECHO OFF
rake
I assigned the shortcut key CTRL + S
to the tool, so that, when I save, the rake task is triggered! I hope this helps someone looking to do the same thing.
There may be some options that integrate with the command line that are ignorant of Visual Studio.
The Ruby/Guard Way
I was playing with the Guard gem last night. You basically install guard and the Guard rake plugin.
gem install guard
gem install guard-rake
You can create a Guard "template", a Guardfile
with a plain Rake task in it
guard init rake
You can edit it to watch .cs
files in the source
directory, for example. (and
guard 'rake', :task => 'default', :run_on_start => false do
watch(%r{^source/.+\.cs$})
end
Then start Guard
guard
You may need to use -i
to turn off this "interactive" mode, which may generate errors on Windows!
guard -i
Guard runs like a little local server, showing logs
12:07:08 - INFO - Guard uses TerminalTitle to send notifications.
12:07:08 - INFO - Starting guard-rake default
12:07:08 - INFO - Guard is now watching at 'D:/temp'
[1] guard(main)>
And if you force a file change (I'm going to touch
a fake file I set up in my test directory), you'll get the output of your rake task!
12:07:08 - INFO - Guard uses TerminalTitle to send notifications.
12:07:08 - INFO - Starting guard-rake default
12:07:08 - INFO - Guard is now watching at 'D:/temp'
12:07:54 - INFO - running default
building!...
[1] guard(main)>
The PowerShell Way
There's nothing fancy out there that wraps up filesystem polling triggered actions, but that doesn't mean you can't build your own! I wrote a .\guard.ps1
file that sits in my solution root. It has a FileSystemWatcher
and waits for changes in a loop.
$here = Split-Path $MyInvocation.MyCommand.Definition
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "$here\source"
$watcher.IncludeSubdirectories = $true
while($true) {
# timeout here lets the console process kill commands and such
$result = $watcher.WaitForChanged('All', 3000)
if($result.TimedOut) {
continue
}
# this is where you'd put your rake command
Write-Host "$($result.ChangeType):: $($result.Name)"
# and a delay here is good for the CPU :)
Start-Sleep -Seconds 3
}
You can see it working and printing when you touch
or create (New-Item <name> -Type File
) files. But, we can also execute rake very simply
rake
PowerShell will just go ahead and execute that as a native command. You could get fancy and make this script look and feel more like Guard (ok, not a lot more, but a little!)
param(
[string] $path = (Split-Path $MyInvocation.MyCommand.Definition),
[string] $task = 'default'
)
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $path
$watcher.IncludeSubdirectories = $true
while($true) {
$result = $watcher.WaitForChanged('All', 3000)
if($result.TimedOut) {
continue
}
rake $task
Start-Sleep -Seconds 3
}
And you'd execute it like this
.\guard.ps1 -Path "$pwd\source" -Task 'build'