#!/usr/bin/ruby # # $Id: ciabot_loginfo.rb,v 1.3 2004/12/04 03:20:32 shugo Exp $ # Copyright (C) 2004 Shugo Maeda # # This library is distributed under the terms of the Ruby license. # You can freely distribute/modify this library. # # Example of loginfo: # # ALL $CVSROOT/CVSROOT/ciabot_loginfo.rb --exclude '^CVSROOT' --project ruby --cvsweb-uri 'http://cvs.ruby-lang.org/cgi-bin/cvsweb.cgi/@path@?cvsroot=src;@query@' --from cvs-admin@ruby-lang.org --to cia@cia.navi.cx %{sVv} require "optparse" require "net/smtp" def escape_xml(s) return s.gsub(/&/n, '&').gsub(/\"/n, '"'). gsub(/>/n, '>').gsub(/#{escape_xml(@path)}" else return "#{escape_xml(@path)}" end end end class CommitLog VERSION = "0.1" attr_accessor :project, :cvsweb_uri, :module, :branch, :author attr_reader :commit_count, :files, :log, :status, :log_count def initialize(project, cvsweb_uri, cvsroot, author, commit_count, exclude_pattern) @project = project @cvsweb_uri = cvsweb_uri @cvsroot = cvsroot @author = author @commit_count = commit_count @exclude_pattern = exclude_pattern @module = nil @branch = nil @files = [] @file_table = {} @log = "" @status = "" @log_count = 0 @current_dir = nil @pushbacked_line = nil @excluded = false end def parse(input, args) parse_input(input) parse_args(args) if !@excluded @current_dir = nil @file_table.clear @log_count += 1 end def ready? return @log_count == @commit_count end def excluded? return @excluded end def to_xml files_xml = @files.collect { |file| file.to_xml }.join("\n") log = @log.dup unless @status.empty? log << "Status:\n" log << @status end if @branch branch = "\n#{escape_xml(@branch)}" end return < CIA client for Ruby CVS #{escape_xml(VERSION)} http://cvs.ruby-lang.org/ciabot/ ruby ruby#{branch} #{Time.now.to_i} #{escape_xml(@author)} #{files_xml} #{escape_xml(log.chomp)} EOF end private def parse_input(input) while line = get_line(input) case line when /^Update of (.*)/ cvs_module = $1.strip.sub(/^#{Regexp.quote(@cvsroot)}\//, "") if @exclude_pattern && @exclude_pattern.match(cvs_module) @excluded = true return end @module, @current_dir = cvs_module.split(/\//, 2) when /^(Modified|Added|Removed) Files:/ parse_files(input, $1.downcase) when /^Log Message:/ @log += parse_log(input) when /^Status:/ @status += parse_log(input) end end end def parse_files(input, action) while line = get_line(input) if /^(Log Message|Status):/.match(line) pushback_line(line) return end if m = /^\s+Tag:\s+(\S+)$/.match(line) @branch = m[1] next end line.strip.split(/\s+/).each do |name| if @current_dir path = File.join(@current_dir, name) else path = name end file = FileInfo.new(@cvsweb_uri, @module, path, action) @files.push(file) @file_table[name] = file end end end def parse_log(input) result = "" while line = get_line(input) if /^Status:/.match(line) pushback_line(line) return result end result << line if @log_count == 0 end return result end def get_line(input) if @pushbacked_line line = @pushbacked_line @pushbacked_line = nil return line else return input.gets end end def pushback_line(line) @pushbacked_line = line end def parse_args(args) if args.length == 1 # cvs 1.11 ary = args[0].split(/ /) ary.shift ary.each do |s| name, old_rev, new_rev = s.split(/,/) set_revision(name, old_rev, new_rev) end else # cvs 1.12 ary = args.dup while name = ary.shift old_rev = ary.shift new_rev = ary.shift set_revision(name, old_rev, new_rev) end end end def set_revision(name, old_revision, new_revision) file = @file_table[name] file.old_revision = old_revision file.new_revision = new_revision end end def send_mail(log, sender, recipients) print("sending a XML-based commit mail...") mail = <