Saturday, June 11, 2005

Controlling Subversion with Ruby and the command line

I love the syntax and ease of developing in Ruby. Unfortunately, there isn't much Ruby work. Therefore, I use Ruby as often as I can for simple tasks I'd like to automate.

Subversion's command line client does everything you need, but not always as easily as possible. For example, I'd like a command that adds all the unknown files returned from a `svn status`. Yes, you can `svn add .`, but that seems to try to add everything and produces warnings.

I think you see where I'm going with this.

Where should we start? With tests obviously.

require 'svndir'
require 'test/unit'

class SvnTestCase < Test::Unit::TestCase
def testMassAdd()
tempFile = createTempFile()
assert_equal("?",tempFileStatus(tempFile))

svnDir = SvnDir.new()
svnDir.add();

assert_equal("A",tempFileStatus(tempFile))
removeTempFile(tempFile)
end

def createTempFile(fileName = "tempFile.temp.temp")
flunk("#{fileName} file already exists") if File.exist?(fileName)
`echo fileName > #{fileName}`
assert(File.exist?(fileName))
fileName
end

def removeTempFile(fileName)
`svn revert #{fileName}` if tempFileStatus(fileName) == "A"
File.delete(fileName) if File.exist?(fileName)
assert(!File.exist?(fileName))
end

def tempFileStatus(tempFile)
`svn status`.to_s =~ /(\?|A)\s+#{tempFile}/
$1
end
end

Now that I know what I'm looking for from a SvnDir class I can implement it:

class SvnDir
def add()
svnStatus().each { |line| addFile(line) if unknown?(line) }
end

def svnStatus()
`svn status`.to_s.split(/\n/)
end

def unknown?(statusLine)
statusLine =~ /^\?/
end

def addFile(statusLine)
statusLine =~ /^\?\s+(.*)$/
`svn add #{$1}`
end
end

I'm still learning Ruby, so please comment with better ways to do this.

I asked Subversion guru Mike Mason if there was an easier way, and he suggested TortoiseSVN. It's true, adding is easier in Tortoise, but I'm just too much of a control freak to give up my command line.
Post a Comment