#!/usr/bin/env ruby # svnql : an sql like interface to svn log (from the working copy) # # This program is released under the terms of the "Creative Commons Attribution 3.0 License" # http://creativecommons.org/licenses/by/3.0/ # # svnql is copyright 2007, Claudio Cicali require 'rubygems' require 'sqlite3' require 'readline' require 'rexml/document' include REXML def prompt print "# " end def help puts "Select one of: revision, author, date or message" if @q_orig != '' puts "Last queries: #{@q_orig.uniq.join(' | ')}" end prompt and return true end db = SQLite3::Database.new(":memory:" ) db.execute('create table entries (revision integer, author varchar(100), date varchar(100), message varchar(255))') rows = db.execute( "select * from entries" ) puts "Loading XML log..." xml='' qlog = IO.popen('svn log --xml', 'w+') qlog.close_write while entry = qlog.gets xml += entry end doc = Document.new(xml) doc.root.elements.each do |el| # Every element is a log entry revision = el.attributes['revision'] author = el.elements['author'].text date = el.elements['date'].text[0..9] message = el.elements['msg'].text.to_s.gsub("'", "''") db.execute "insert into entries values (#{revision}, '#{author}', '#{date}', '#{message}') " end puts db.get_first_value( "select count(*) from entries" ) + ' entries loaded.' puts "Columns are: revision, author, date and message. Use Ctrl+d to quit or ? for a brief help." print "Query? # " @q_orig=[] while q=readline do begin q.chomp! next unless q.strip != '' next if q=='?' and help @q_orig.push(q) q = q.strip.gsub('select', '') if match = q.match(/order by .*$/) order = match[0] q = q.gsub(/order by .*$/,'') end nr=-1 q = 'select ' + q if q.match(/ where /) q = q.gsub('where', 'from entries where') else q += ' from entries' end q += " #{order.to_s}" db.execute(q) columns = nil db.execute2(q) do |row| nr += 1 puts row.join(',') end puts "+------ #{nr} rows" rescue SQLite3::SQLException puts "in '#{q}' :" + $! prompt and next end puts puts "Last query was '#{@q_orig.last}' (#{q})" prompt end