Altering many directories at once with CmdDirs

Feb 20, 2011

On any machine I use I create a directory, sandbox, at the root of my home directory to hold checkouts of source code I’m working on. This directory often contains code from many different repositories, dozens of projects that I intermittently work on. Many of these repositories depend on others, in particular Java submodules for Clearspring, and I want to be able to easily update all of them at once. With Subversion this is easy: the svn command allows you to act upon a checkout without being in the directory that contains it. Simply issuing svn up * from ~/sandbox ensures that I have the latest code revision in each of my checkouts and svn st * allows me to see if I have any uncommited changes.

While I love Git, it does not make such actions this simple. Git requires you to be in the repository directory (or set a number of environment variables) to work wit that repo. While the -exec option of find(1) allows me to descend into each directory and perform an action, I wanted to make this easy, because such all-checkout-actions are something that I want to do a number of times each day. Like most problems, this one is (best?) solved with Perl. Enter App::CmdDirs.

CmdDirs is a fairly simple Perl app that I have written to do what I describe above–descend into any number of directories and perform a command in each one.

titus:~/sandbox$ ls
CmdAll                 mac-itunes             genius-os
scoreboard             GAE                    hf
uaParser               WebService-LOC-CongRec iTunes-Sync
titus:~/sandbox$ cmddirs "git st"
Performing `git st` in <cmdall>
## master
?? App-CmdDirs-1.00.tar.gz

Performing `git st` in <itunes-sync>
## master

Performing `git st` in <uaparser>
## master
 M uaParser/test/test_user_agent.py

Performing `git st` in <webservice-loc-congrec>
## master

See the numerous directories? Note that there are 9 directories in my sandbox but git st was only performed in a few of them, those which are Git repositories. CmdDirs has a modicum of intelligence: if it knows what your command is, the command will only be performed in applicable directories. This can be overridden with -all, -git, or -svn doing what you expect. Git and Subversion are the only two things supported right now, because that’s all I have a need for. Writing new Traversers is simple–just copy the form of git.pm or svn.pm. You can probably Achieve at this endeavor even without knowing Perl.

Here’s a one-liner for installing cmddirs:

curl https://github.com/dinomite/CmdDirs/raw/master/bin/cmddirs > ~/bin/cmddirs && chmod a+x ~/bin/cmddirs