----Next_Part(Mon_Mar_13_23_58_08_2006_761)--
Content-Type: Multipart/Mixed;
boundary="--Next_Part(Mon_Mar_13_23_58_08_2006_761)--"
----Next_Part(Mon_Mar_13_23_58_08_2006_761)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi,
In <
[email protected]>
"svn pre-commit hook" on Sat, 11 Mar 2006 06:28:43 +0900,
Bil Kleb said:
Can someone (Kou?) please sketch out how to intercept
a Subversion transaction with a pre-commit hook and
throw each file matching, say, /\.rb$/ to some StyleChecker?
What about attached script?
You can use the attached script with the following
pre-commit script:
#!/bin/sh
REPOS="$1"
TXN="$2"
/.../ruby \
/.../pre-check-file.rb "$REPOS" "$TXN" \
-p PATTERN1 -c CHECK_COMMAND1 \
-p PATTERN2 -c CHECK_COMMAND2 \
... \
|| exit 1
exit 0
For example (reject space indented Ruby scripts and C programs):
#!/bin/sh
REPOS="$1"
TXN="$2"
/usr/bin/ruby \
~/work/ruby/pre-check-file.rb "$REPOS" "$TXN" \
-p \.rb$ -c 'grep -v ^ ' \
-p \.c$ -c 'grep -v ^ ' \
|| exit 1
exit 0
Thanks,
--
kou
----Next_Part(Mon_Mar_13_23_58_08_2006_761)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="pre-check-file.rb"
#!/usr/bin/env ruby
require 'thread'
require 'optparse'
require 'ostruct'
def parse(args)
options = OpenStruct.new
options.patterns = []
options.checkers = []
opts = OptionParser.new do |opts|
opts.separator ""
opts.on("-I", "--include=PATH",
"Add PATH to load path") do |path|
$LOAD_PATH.unshift(path)
end
opts.on("-p", "--pattern=PATTERN",
"Add PATTERN to check target patterns") do |pattern|
options.patterns << /#{pattern}/
end
opts.on("-c", "--checker=CHECKER",
"Add CHECKER to check programs") do |checker|
options.checkers << checker
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit!(1)
end
end
opts.parse!(args)
if options.patterns.empty?
STDERR.puts("no pattern is given.")
exit!(1)
elsif options.patterns.size != options.checkers.size
message = "patterns size (#{options.patterns.size}) and "
message << "checkers size (#{options.checkers.size}) are mismatch."
STDERR.puts(message)
exit!(1)
end
options
end
class FileChecker
def initialize(path, txn, patterns, checkers)
@fs = Svn::Repos.open(path).fs
@txn = @fs.open_txn(txn)
@root = @txn.root
@rev = @fs.youngest_rev
@patterns = patterns
@checkers = checkers
end
def check
invalid_infos = run_checker
if invalid_infos.empty?
0
else
invalid_infos.each do |path, result, checker|
STDERR.puts("#{path} wasn't passed check: #{checker}")
result.each do |line|
STDERR.puts(" #{line}")
end
end
1
end
end
def run_checker
invalid_infos = []
changed_paths.each do |path|
@patterns.each_with_index do |pattern, i|
if pattern =~ path
checker = @checkers
success, result = run(checker) do |output, input|
output.print(@root.file_contents(path) {|f| f.read})
end
invalid_infos << [path, result, checker] unless success
end
end
end
invalid_infos
end
def changed_paths(base_rev=nil)
base_rev ||= @txn.base_revision
base_root = @fs.root(base_rev)
editor = Svn:elta::ChangedEditor.new(@root, base_root)
base_root.dir_delta('', '', @root, '', editor)
(editor.added_files + editor.updated_files).uniq.sort
end
private
def run(command)
pw = IO.pipe
pr = IO.pipe
pe = IO.pipe
pid = exit_status = nil
Thread.exclusive do
verbose = $VERBOSE
$VERBOSE = nil
pid = fork do
$VERBOSE = verbose
pw[1].close
STDIN.reopen(pw[0])
pw[0].close
pr[0].close
STDOUT.reopen(pr[1])
pr[1].close
pe[0].close
STDERR.reopen(pe[1])
pe[1].close
exec(command)
exit!(1)
end
$VERBOSE = verbose
end
pw[0].close
pr[1].close
pe[1].close
pw[1].sync = true
yield(pw[1], pr[0]) if block_given?
pw[1].close
pid, exit_status = Process.waitpid2(pid)
return [exit_status.exitstatus.zero?, pe[0].read]
ensure
unless exit_status
Thread.start do
begin
until Process.waitpid(pid, Process::WNOHANG)
sleep 1
end
rescue
# ignore
end
end
end
end
end
def main
if ARGV.find {|x| ["-h", "--help"].include?(x)}
parse(ARGV)
else
path = ARGV.shift
txn = ARGV.shift
options = parse(ARGV)
end
require 'svn/core'
require 'svn/fs'
require 'svn/delta'
require 'svn/repos'
require 'svn/client'
checker = FileChecker.new(path, txn, options.patterns, options.checkers)
checker.check
end
begin
exit main
rescue Exception
if $!.is_a?(SystemExit)
raise
else
STDERR.puts($!.class)
STDERR.puts($!)
STDERR.puts($@)
exit!(1)
end
end
----Next_Part(Mon_Mar_13_23_58_08_2006_761)----
----Next_Part(Mon_Mar_13_23_58_08_2006_761)----