When I ssh into our development server, I automatically CD into a work directory, do a 'cvs up -d' (-d picks up new directories) and then run all of the tests. However, I almost always ssh into dev twice because one window is for my code and another window is for my tests and I'm tired of hitting <ctrl-c> all the time on the second window. With the help of smylers explaining some odd (to me) bits of bash syntax, I now use something like this:
#!/usr/local/bin/bash if [ -f ~/.bashrc ]; then source ~/.bashrc; fi cd /home/cpoe/work/main/ timestamp='.login_time' if [ -e $timestamp ]; then last_time=`cat $timestamp` else last_time=0 fi curr_time=`date +%s` let elapsed="$curr_time - $last_time" if [ $elapsed -gt 600 ] # five minutes then `perl -e 'print time' > $timestamp` /usr/bin/cvs up -d /usr/local/bin/runtests -lr fi
With that, if I've ssh'd into the dev server and run the tests within the last five minutes, the next ssh will not do the cvs up or run the tests. It could probably be cleaned up more since I'm not much of a bash programmer, but it's pretty handy.
Unlike sh, bash has arithmetic evaluation that would make your script much simpler. I also wouldn’t check for the dotfile’s existence, just read it with error messages suppressed. It’s also bizarre that you’re using date +%s
to get the timestamp in one place and perl -e 'print time'
in another – and the backticks around that second place are even more so. All in all here’s how I’d write that:
#!/usr/local/bin/bash
[ -r ~/.bashrc ] && source ~/.bashrc
timestamp=.login_time
cd/home/cpoe/work/main/
last_time=$( cat "$timestamp" 2>&- )
curr_time=$( date +%s )
if (( curr_time - last_time > 600 )) # five (???) minutes
then
echo "$curr_time" > "$timestamp"
/usr/bin/cvs up -d
/usr/local/bin/runtests -lr
fi
But actually, “run the tests if it’s been 5 minutes since my last login” strikes me as a hack. I think what you rather want to say is “skip the tests if cvs up
didn’t find any updates to pull.” That would look something like this:
#!/usr/local/bin/bash
[ -r ~/.bashrc ] && source ~/.bashrc
timestamp=.login_time
cd/home/cpoe/work/main/
tmp=$( mktemp ) && {
/usr/bin/cvs up -d | tee "$tmp"
[ -s "$tmp" ] &&/usr/local/bin/runtests -lr
rm -f "$tmp"
}
This is based on the fact that cvs
prints its U foo/bar.c
lines to stdin, but its chatter to stderr. So it copies cvs
’s stdout to a temporary file whose size will be nonzero only if cvs
actually did any updates. The tests run only if that’s the case.
Re:Various improvements
Ovid on 2007-03-26T10:47:58
By the way, I did implement many of your suggestions, thank you. However, I deliberately didn't want to go with the 'don't run tests if there are no updates to CVS'. There are plenty of other ways -- admittedly less common -- that tests can fail even without CVS updates. When those failures occur, I'd like to catch them!
Re:Various improvements
Aristotle on 2007-03-26T11:45:06
Ah. Btw, a much more direct way to do this just occured to me: use the file’s mtime.
#!/usr/local/bin/bash
[ -r ~/.bashrc ] && source ~/.bashrc
timestamp=.login_time
cd/home/cpoe/work/main/
if [[ `find "$timestamp" -mmin +5 -print` ]] ; then
touch "$timestamp"
/usr/bin/cvs up -d
/usr/local/bin/runtests -lr
fiThe idiomatic bit here is using
find
to check the file’s age. The-mmin +5
predicate means “if the mtime of the file under consideration is equal to or greater than 5 minutes.” Sincefile
is given only a single filename to check, its output will be empty if that one file was last touched less than 5 minutes ago. The condition is then false, so nothing happens.