#!/usr/bin/ruby -w # Part of CVSspam # http://www.badgers-in-foil.co.uk/projects/cvsspam/ # Copyright (c) David Holroyd $tmpdir = ENV["TMPDIR"] || "/tmp" # try to pick a name to avoid collisions with other people's commits $dirtemplate = "#cvsspam.#{Process.getpgrp}.#{Process.uid}" def find_data_dir Dir["#{$tmpdir}/#{$dirtemplate}-*"].each do |dir| stat = File.stat(dir) return dir if stat.owned? end nil end # transform any special / unexpected characters appearing in the argument to # --from so that they will not cause problems if the value is inserted into # a file or directory name def make_fromaddr_safe_for_filename(addr) addr.gsub(/[^a-zA-Z0-1.,_-]/, "_") end # Option processing doesn't use GetoptLong (for the moment) bacause arguments # given to this script by CVS include the names of committed files. It # seems quite possible that one of those file names could begin with a '-' # and therefore be treated by GetoptLong as a value which requires processing. # This would probably result in an error. # # [That could be worked around by placing a '--' option (which tells GetoptLong # to stop processing option arguments) at the very end of the arguments to # record_lastdir.rb in commitinfo, but that's very easily forgotten, and isn't # really backwards compatable with the behaviour of older CVSspam releases.] if ARGV.first == "--from" # we could, of course, be tricked, if the first committed file in the list # happened to be named '--from' :S # drop the "--from" ARGV.shift # and use the value which was given following the option, $dirtemplate << "." << make_fromaddr_safe_for_filename(ARGV.shift) end $repositorydir = ARGV.shift $datadir = find_data_dir() if $datadir==nil $datadir = "#{$tmpdir}/#{$dirtemplate}-#{rand(99999999)}" Dir.mkdir($datadir, 0700) end $tags = nil # Record any tag name found in 'Entries' for files being commited. This is # required at pre-commit-time as we have no other way of dertermining what # branch a file was on if it's been removed. # # If the commitinfo-tags file exists from a previous, unsuccessful commit, # then it's possible for it to contain multiple entries for a particular file. # The consumer of commitinfo-tags must take care to only use the last entry # for a given filename. def write_tag(name, file) if $tags.nil? $tags = File.new("#{$datadir}/commitinfo-tags", File::WRONLY|File::CREAT|File::APPEND); return if $tags.nil? end $tags.puts("#{name}\t#{file}") end File.open("CVS/Entries") do |file| file.each_line do |line| next if line =~ /^D/ info = line.split(/\//) # skip entries not commited this invocation, if ARGV.delete(info[1]).nil? next end if info[5] =~ /^T(.+)/ write_tag($1, "#{$repositorydir}/#{info[1]}") end end end $tags.close unless $tags.nil? unless ARGV.empty? $stderr.puts "Nothing in CVS/Entries for "+ARGV.join(", ") end # Record the directory currently being commited to. # # This script (and collect_diffs.rb) will be run just for the files in a # single directory. # # A commit to files in multiple directories will therefore produce multiple # invocations of these scripts. To send the email only when the whole commit # is done, each run overwrites the 'lastdir' file; collect_diffs.rb will # later inspect the value it contains to work out if it needs to generate the # email yet. File.open("#{$datadir}/lastdir", "w") { |file| file.write $repositorydir } # vim:et:ts=2:sw=2