vJot’s a public code base, so I saw it unbecoming of an open-source guy to add my stats html to the repo. No worries, I’ll just add it with a little help via the wonder library, Capistrano:
task :after_symlink, :roles => :app do stats = <<-JS <script src="http://www.google-analytics.com/urchin.js"> </script> <script type="text/javascript"> _uacct = "UA-104904-8"; urchinTracker(); </script> JS layout = "#{current_path}/app/views/layouts/application.html.erb" run "sed -i 's?</body>?#{stats}</body>?' #{layout}" end
The code appends my Analytics’ javascript to the layout file and voilà, instant stats!
The secret sauce is that if you’ve defined an after_symlink task, Capistrano will run it during your regularly scheduled cap deploy. As a matter of fact, it has before_ and after_ hooks for all its tasks, including any tasks that you’ve written. Schweet.
Update: Thanks goes out to the unix gurus in the audience for shortening up my sed code.
Maybe you need to double-escape your sed backslashes?
I’m rocking the ? instead of / to avoid escaping woes, but maybe I’m missing something obvious.
sed’s in-place option (-i) is what you’re after.
run “sed -i’’ ’s??#{stats}?’ #{layout}”
should do the trick.
What might not be immediately obvious is that you can chain these together. That might seem useless, but consider that the RailsMachine gem already has an :after_symlink task. Rather than muck around the gem just define :after_after_symlink. Booya! (Thanks Bradley Taylor for that one).
The reason `cat x| foo > x` doesn’t work is that x is zeroed by the redirect before cat has a chance to read anything from it.
Well its because the sed’s output is writen simultaneusly with sed’s data processing. So bascicly your data gets trunclated first processed then :)
Could be because sed is a line editor and your tag is on it’s own line?
As noob pointed out, you’re most probably truncating the layout file with sed before cat can cat the second line from it.
Also, sed can get the input file as one of its parameters, so it’s a useless cat there.
Either sed -i, or use sponge.
Noob and Shot get it almost right. The reason you can’t do it that way is that the redirection is handled by the shell before the command is run. It goes something like this:
I suppose the reason it’s done this way is that it is fail-early. If you redirect to a file in a non-existing directory, the shell will notice and will never run your (potentially) destructive commands.
Instead of
layout = ”#{current_path}/app/views/layouts/application.html.erb” run “cat #{layout} | sed ’s??#{stats}?’ > ~/app.tmp” run “mv ~/app.tmp #{layout}”
Just use
run “sed -i ’’ -e ’s??#{stats}?’ #{current_path}/app/views/layouts/application.html.erb”
So many unix badasses reading err. I’ll update the post shortly with my new found knowledge. Thanks guys.
Others have already chimed in with the correct answer. POSIX shells run all the steps of a pipe chain in parallel. This includes the redirection at the end, which truncates your original file. Net result is that the file is truncated before it has a chance to be cat’d.
A few solutions for this exist. Instead of cat’ing the file to sed, use sed’s -i (in-place) flag as indicated earlier. The other option is to install the Debian “moreutils” package, which has a utility called sponge. “cat foo | sponge foo” will cause sponge to “soak up” standard in completely, and flush to the named file once it hits the EOF.
Just wondering why you are doing this with capistrano insead of just putting the code into your layout file? For instance, I just have <%= GOOGLE_ANALYTICS %> in all my layout files and then in my development.rb and production.rb config files I set the GOOGLE_ANALYTICS variable.
Wow, I love you guys.
Ahh, thanks for a great idea. Gave me another idea how to use capistrano.
Chime in.