OSX, Growl, And Subversion

Today I found myself trying to figure out how to make a terminal window stay permanent on my desktop or dashboard on OSX, similar to what I've done in the past with Linux. I just wanted to have the terminal window monitoring things in the background for me. Actually, all I wanted to do was keep track of when my local working copy of our Subversion repository was out of sync. I wanted a solution that would keep out of my way, but I also wanted it to be easy.

My search for a solution seemed short-lived when a Google search suggested a dashboard widget for the Terminal application. The problem with it was that the download server was dead or simply blocked by my company's Internet filter. One way or another, it wasn't long before I went in search of another solution.

At that very instant, I received a Growl notification from some program. That's when it dawned on me--I could tell Growl to tell me when my working copy was out of sync. I had done stuff like that in the past, so I set out to write my solution. This is what I came up with:

#!/bin/bash
MY_BOX=[my IP address]
DEV_ROOT='/path/to/svn/working copy'
cd $DEV_ROOT

MY_REV=`svn log --limit 1 | awk '/^r/ {print $1}' | sed 's/[^0-9]//g'`
SVN_REV=`svn log --limit 1 -r HEAD | awk '/^r/ {print $1}' | sed 's/[^0-9]//g'`

if [[ $MY_REV != $SVN_REV ]]; then
    ssh username@$MY_BOX "growlnotify -s -d47111 -n 'iTerm' -t 'Out Of Sync' -m 'Your working copy is out of sync.  Repository is at revision $SVN_REV, and your working copy is at $MY_REV.'"
fi

Now, a little bit about my environment. As I've mentioned before, all of our development really takes place on Linux-powered virtual machines. We simply use our Macs as the system to interact with those virtual machines. That is why there's the ssh line in that script.

Basically, this script just checks the most recent revision in your local working copy. Then it checks the latest revision in the repository itself. It compares the two revision numbers, and if it finds a difference, it will SSH into my OSX box to send me a Growl notification. On the OSX side, I have Growl and growlnotify installed. Here's a summary of the options to growlnotify:

  • -s: make the notification sticky--don't hide the notification until the user specifically closes it.
  • -d47111: a unique identifier for the notification. This makes it so you can send the same message over and over and it would update any existing notifications with that ID instead of creating a new notification (unless one doesn't exist already).
  • -n 'iTerm': I believe this was supposed to be the "source" application. I don't remember right now.
  • -t 'Out Of Sync': The title for the notification.
  • -m 'Your working copy...': The message to send to my Mac.

This is a fabulous little reminder to me. I have it set up as a cronjob that runs every minute on my Linux-powered development virtual machine. Hopefully this will help others!

Even More New VIM Fun

It appears that my last article generated a bit of interest! I had one good friend share some enlightening tips with me after he read about my findings. He opened my eyes to the world of abbreviations in VIM. Oh boy, oh boy!!

I'll pretty much just continue today's earlier post, by showing another (super awesome) way to insert blocks into your Django templates. If you were to enter this line into your ~/.vimrc file...

ab bl <Esc>bi{% block <Esc>ea %}{% endblock %}<Esc>h%i

...you would be able to type this...

content bl

...while you're in insert mode. As soon as you hit your spacebar after the bl, VIM would turn it into...

{% block content %} {% endblock %}

...and put you in insert mode between the two tags. Perfect!

For those of you who are interested in understanding the abbreviation, first it will take you out of insert mode (<Esc>). Then it jumps to the beginning of the word before the bl abbreviation and drops back into insert mode (bi). Next it inserts {% block and hops out of insert mode long enough to move the cursor to the end of the word you typed before the bl abbreviation. It finishes inserting {% endblock %}, gets out of insert mode, goes back a character (to account for the space you typed after bl) (h), moves the cursor to the matching opening brace for the } at the end of {% endblock %} (%), and finally puts you back into insert mode (i). Whew! It's all the same old VIM stuff, just packed into one uber-powerful abbreviation!

Thank to Jonathan Geddes for the guidance on this! I find this method to be superior to the one I posted about earlier because you don't even have to leave insert mode to get the code block stuff inserted into your templates!

Bulk Update With Mercurial

Some of you may well know that I was previously an subversion user, more out of comfort than necessity. SVN was the first version control system that I became well acquainted with, so it just seemed like a natural choice for me when I thought I needed version control.

Several months ago I read a blog article by a buddy, in which he briefly discussed Mercurial. I had been meaning to give some distributed version control systems a shot after some disasters related to the centralized nature of SVN. This blog article prompted me to take a stab at Mercurial and some others.

Within a few days I was sold on Mercurial. I won't go into details simply because I'm not one for religious wars that way. Let's just say that Mercurial seemed to be perfect for my wants and needs.

There were, however, a few things about using Mercurial that I miss from the SVN world. One such thing is that you can update several "working copies" of something in SVN with a single command. For example, I keep a lot of my 3rd party Django applications in one directory. Many of these applications use SVN. Sometimes I'll just run a command like this:

svn up /path/to/third/party/apps/*

Each project that uses SVN will automatically be updated without much fuss with such a command. However, with Mercurial, it appears that you need to be in an actual Mercurial repository in order to update it. There are extensions to get around this problem, but I was looking for something a little different.

Since I use Linux almost exclusively, I didn't feel bad about just using the power within to do the work. The following command does everything I need it to:

find -name ".hg" -type d | xargs -t -i bash -c "(cd {}; hg pull; hg up)"

This command finds any directories called .hg anywhere under your current location on the filesystem. Any matches will be used in the command at the end: cd {}; hg pull; hg up

So far I haven't had any problems with this command, but your mileage may vary. To make things even easier, I made an alias for this rather long command:

alias hgupall='find -name ".hg" -type d | xargs -t -i bash -c "(cd {}; hg pull; hg up)"'

I put that line in my ~/.bashrc script, which is executed each time I log into my computer. With that in place, all I need to do is something like this:

cd /path/to/third/party/apps
hgupall

And the aliased command handles the rest. Pretty slick stuff. Hooray for Mercurial and Linux!

Mercurial 1.3 Released

Today marks the official release of Mercurial 1.3, an awesome distributed version control system. This release comes with several nifty features, including the following, straight from the What's New wiki page:

Major Changes

  • experimental support for sub-repositories
  • Python 2.3 is no longer supported; now requires Python 2.4-2.6

Commands

  • merge: add -P/--preview option
  • update: don't unlink added files when -C/--clean is specified
  • update: added -c/--check option to abort on local changes
  • update: allow merges going backwards
  • push: improved handling of named branches
  • branches/heads: add a -c/--closed option to show closed branches
  • help: new extensions topic

General

  • add patch.eol config setting to work with cross-platform patches
  • fixed support for SSL through proxies
  • add ability to load hooks from arbitrary Python modules
  • hide passwords for HTTP repositories in error and log output
  • fix Python 2.6 support in the Windows installer
  • add mechanism for specifying HTTP authentication details in hgrc
  • prompts and choices are now shown even in non-interactive mode
  • performance improvements, especially on Windows
  • much improved zsh completion
  • improved Danish, Japanese, Italian and simplified Chinese translations
  • new German, French, Greek, Brazilian Portuguese and traditional Chinese translations

Web interface

  • read configuration data from webdir configs
  • add branches page to hgweb
  • pluggable templater engine support
  • refresh hgwebdir configuration periodically
  • let web.encoding override ui.encoding setting
  • deal with dicts/lists like webdir config paths

I'm quite stoked about this release :) For additional information, please check the project's wiki.

My VIM Adventures

Along with my recent adventures with Fedora 11, I decided to force myself to become more proficient with VIM. For those of you who do not know, VIM is based on perhaps one of the oldest surviving text editors around today. There are often religious-grade battles between those who believe in VIM and those who believe in Emacs, another long-surviving text editor. I'm not trying to get into any debates about which is better, and I'm not interested in why I should not be using VIM. If you still feel like I need to be set straight, please use the contact me form instead of the comments section.

Anyway, most people who use these editors fall into 1 of 3 categories (there are probably more categories actually):

  1. They're familiar with it enough to get the job done, but they're not exactly proficient. Therefore, they don't care about evangelizing the editor.
  2. They're proficient with the editor, but they're afraid of the politics involved in religious wars relating to text editors, so they don't evangelize.
  3. They're proficient with the editor and feel that the whole world would be better off if everyone used their preferred text editor. As such, they cannot shut up about the dang thing and drive all of their friends, coworkers, and acquaintances mad.

A few of you will probably agree with what I'm about to say. I fear I have transitioned from stage 1 to stage 3 fairly rapidly. I can't stop talking about VIM all of the sudden! You'd think it's the next best thing after sliced bread the way I've been blabbering about it. And here I am, writing an article about it. Hah.

Ever since I first started using Linux, I have been using vi to handle most of my text editing when I was in a terminal. I knew enough to get around. Basic things like navigation and inserting text were pretty much all I knew how to do. I dabbled with a tutorial here and there, but it wasn't long before the things I learned were lost, since I usually preferred a graphical text editor over VIM.

My recent experimentation with VIM has proved to be very fruitful, if I do say so myself. I am no longer tied down to some editor that is slow and bulky, I don't have much to worry about when I switch computers (chances are that VIM is on any computer I use regularly), and I don't even need to be sitting at the computer I'm using VIM on! In fact, today I was doing most of my work over an SSH session to my netbook. I felt more productive today than I have in a very long time.

It's been a long time since I've enjoyed using a mouse to perform basic tasks on my computer. Using VIM allows me to rid myself of the mouse entirely for my text editing tasks, and I don't feel at all limited in my capabilities. Things that used to be quite sketchy operations using my favorite graphical editors end up being very simple with VIM.

I also love the obscurity favor of it all.

Examples

I wish I could just keep adding stuff to this list! There are so many neat things I want to share with everyone about VIM! I'm sure there are more efficient ways to do some of the things I have been learning with VIM, but this works very well for me.

Laziness

I do a lot of reStructuredText for various things. In fact, I'm writing this article using VIM right now. ReST is fantastic, but it's horrible to do using an editor that is not set up with a mono spaced font. I like to see things nicely lined up (I'm a Python developer, after all). I also like to have my section headings have an underline that is as long as the heading itself. For example, the heading just above this looks like this:

Examples
========

In this particular instance, it's not a big deal to hold down the equals key long enough to underline the word "Examples". However, sometimes I get some pretty lengthy section titles. The lazy side of me doesn't want my finger to hang around on the same key for very long (or tap it dozens of times, for that matter). Also, trying to figure out how many characters are in a section title without a mono spaced font is very annoying.

The/a solution? Say I have a section heading that is 50 characters long. To underline it, all I have to do is type 50i= and hit the escape key.

Cutting Text Mid-Line

Another neat thing is being able to cut text from the cursor to a particular character somewhere later on (or earlier on!) in the same line. Say I have a hyperlink whose address I wish to change:

<a href="http://www.somelong.com/that/I/want/to/change/">Link Text</a>

Instead of using the mouse to highlight the href attribute's value (or highlight it using shift on the keyboard), I just position my cursor on the h in http and type dt". VIM will lop that address right out of there (and you can paste it elsewhere if you'd like). I used this particular shortcut countless times today as I replaced things like {% url some-named-url with,some,parameters %} with {{ some_object.get_absolute_url }} in some Django templates.

Search & Replace

And I cannot neglect the classic search and replace functionality in VIM. You can use fancy regular expressions in VIM to replace some text with something else. I was trying to do a little refactoring today, and I came up with a command like this:

:s/something/lambda (a,b,c): \0(a,b,c)/g

That sort of command works great to replace all occurrences of "something" on the current line with "lambda (a,b,c): something(a,b,c)". Fantastic. What about a global search and replace, instead of just the current line? Stash a % at the front of the command (:%s/something/lambda (a,b,c): \0(a,b,c)/g) and you're in business.

Now what if you only wanted to perform that search and replace over a certain group of lines instead of a single line or the whole file? This is one I'm particularly thrilled about:

:.,.+9 s/something/lambda (a,b,c): \0(a,b,c)/g

That little beauty will perform the search and replace on the current line and the following 9 lines. How awesome is that?

Moving & Deleting Words

Sometimes as I am writing something, I decide I would like to reword a sentence as I near the end. Sometimes this involves simply deleting a word or two. Sometimes it means chopping a few words out of the beginning part of a sentence to put them back at the end somewhere. Whatever the case, VIM seems to handle my needs perfectly well.

Say I have this sentence (from the Vimperator Web site): "Writing efficient user interfaces is the main maxim, here at Vimperator labs." If I want to move the "here at Vimperator labs" to the beginning of the sentence, assuming I just finished typing it, I would place my cursor over the period at the end, type dT,, hit ( to go to the beginning of the sentence, hit P to insert what I just copied, and then handle the rest of the clean up (capitalization, fixing the comma, etc). I could have also done something like, 4db instead of dT,.

If I want to cut/delete an entire word, or to the end of whatever word my cursor is currently on, I could use dw. For more than one word, just put a number before the command. It's great stuff!

Taking It Too Far

I've gotten so carried away with all of this VIM business. I really have. I installed vimperator in Firefox. This extension gives Firefox a VIM-like interface. Now I can do pretty much all of my regular surfing without using the mouse. Some may argue that this is absolutely impractical because it would take much longer to get to the right link on a page using the keyboard than it would with the mouse. That may be true. I dunno, but I still think it's awesome that I really don't need my mouse to browse the Internet now.

As I was playing with vimperator tonight, one of my buddies pointed out another useful extension called It's All Text. This extension allows you to use your preferred text editing program in regular old text boxes in Firefox. It is this extension which has just made writing my blog articles 200x more efficient. Now I can quickly and easily write my articles right here in VIM without having to copy and paste all over the place. Pretty dang incredible.

Oh yes, I'd like to thank Chad Hansen and Jonathan Geddes for helping me out as I explore the depths of VIM. You guys rock!

My Fedora 11 Adventures: Part V

Fedora 11 has been treating me pretty well now that I don't have Firefox installed. I am considering the head of manually installing Firefox 3.0.11 in my home directory to see if that fares any better. Another goal I have for today is to change some of the settings for the login screen. So far I haven't been able to figure out how to access that one.

The Login Manager

Surfing a few sites this morning has suggested that I'm not the only one struggling to rid myself of the stock Fedora login manager preferences. One person did suggest a trick for changing the background image, though. I tried it out, but I'm not so sure it worked as planned--I got a ton of SELinux notifications, and I'm not prepared to log out and back in at this time.

Well that's cool. I was just playing around in the terminal looking for any commands that might help me change the settings for the login screen. One command, gdmflexiserver, seemed to lock my screen and show the login screen again. Sure enough, the background I had chosen before was there instead of the nasty default image. Logging in as myself at this screen unlocked my session, and I had everything just as I left it.

Installing Firefox

I tried to download the .tar.bz2 archive of Firefox straight from their website, but that is only i686. My computer didn't know how to execute the program. Time to look into alternatives.

After a while I decided to try to compile my own Firefox. That didn't go very well--nearly an hour into the compile, it farted out complaining about floats or something. I don't have the time to dedicate to making Firefox work.