Current Path : /usr/src/tools/tools/backout_commit/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //usr/src/tools/tools/backout_commit/backout_commit.rb |
#!/usr/bin/env ruby -w # $FreeBSD: release/9.1.0/tools/tools/backout_commit/backout_commit.rb 110160 2003-01-31 22:08:14Z seanc $ # Please note, that this utility must be kept in sync with # CVSROOT/log_accum.pl. If someone has a different output from their # mail client when saving e-mails as text files, feel free to hack it # in as an option. # # If someone would like to hack in the ability to generate diffs based # off of this script, by all means, be my guest. require 'getoptlong' $basedir = '/usr' $backout_script = "backout-#{Time.now.strftime("%Y-%m-%d-%H-%M")}.sh" $commit_authors = [] $commit_dates = [] $commit_file = nil $commit_message = nil $cvsbin = nil $cvs_path = '/usr/bin/cvs' $cvsrc_ignore = true $debug = 0 $echo_path = '/usr/bin/echo' $echo_warnings = true $force_script_edit = false $force_remove = false $output = $stdout $quiet_script = false $shell_path = '/bin/sh' $shell_args = '--' def debug(level, *msgs) if level <= $debug if $debug > 1 $output.puts "DEBUG(#{level}): #{msgs.shift}" else $output.puts msgs.shift end for msg in msgs $output.puts "\t #{msg}" end end end # def debug() def usage(msg, info = nil) out = (msg.nil? ? $stdout : $stderr) out.puts "#{File.basename($0)} usage:" << (msg.nil? ? '' : " #{msg}") out.puts "#{info}" unless info.nil? out.puts "" out.puts " -s, --backout-script=<file> Specifies the filename of the script" out.puts " -D, --basedir=<dir> Specifies the base directory [/usr]" out.puts " -a, --commit-author=<uid> Forces a commit author" out.puts " -d, --commit-date=<date> Forces a commit date" out.puts " -m, --commit-file=<path> Specifies a commit message file" out.puts " -M, --commit-message=<msg> Specifies a commit message" out.puts " -c, --cvs-path=<path> Specifies the CVS binary to be used [cvs]" out.puts " -C, --cvsrc-ignore=<bool> If true, will ignore options in ~/.cvsrc" out.puts " -e, --echo-path=<path> Specifies the path to echo" out.puts " -f, --force-remove=<bool> If true, removes new files [false]" out.puts " -F, --force-edit=<bool> If true, add -C to the shell arguments in" out.puts " the backout script if the shell is sh," out.puts " which forces an edit of the script" out.puts " -O, --output=<stdio> Specifies what fd to direct the output to" out.puts " -A, --shell-args=<string> Specifies the shell arguments to be used" out.puts " -S, --shell-path=<path> Specifies the shell to be used [/bin/sh]" out.puts " -W, --warnings=<bool> Turns on or off warnings [true]" exit(msg.nil? ? 0 : 1) end OPTION_LIST = [ ['--backout-script','-s', GetoptLong::REQUIRED_ARGUMENT], ['--basedir','-D', GetoptLong::REQUIRED_ARGUMENT], ['--commit-author','-a', GetoptLong::REQUIRED_ARGUMENT], ['--commit-date','-d', GetoptLong::REQUIRED_ARGUMENT], ['--commit-file','-m', GetoptLong::REQUIRED_ARGUMENT], ['--commit-message','-M', GetoptLong::REQUIRED_ARGUMENT], ['--cvs-path','-c',GetoptLong::REQUIRED_ARGUMENT], ['--cvsrc-ignore','-C',GetoptLong::REQUIRED_ARGUMENT], ['--echo-path','-e',GetoptLong::REQUIRED_ARGUMENT], ['--force-edit','-F',GetoptLong::REQUIRED_ARGUMENT], ['--force-remove','-f',GetoptLong::REQUIRED_ARGUMENT], ['--output', '-O', GetoptLong::REQUIRED_ARGUMENT], ['--quiet-script','-q',GetoptLong::REQUIRED_ARGUMENT], ['--shell-args','-A',GetoptLong::REQUIRED_ARGUMENT], ['--shell-path','-S',GetoptLong::REQUIRED_ARGUMENT], ['--warnings','-w', GetoptLong::REQUIRED_ARGUMENT], ] opt_parser = GetoptLong.new(*OPTION_LIST) opt_parser.quiet = true begin opt_parser.each do |opt,arg| case opt when '--backout-script' debug(3, "backout script was #{$backout_script.inspect} : is #{arg.inspect}") $backout_script = arg when '--basedir' debug(3, "base directory was #{$basedir.inspect} : is #{arg.inspect}") $basedir = arg when '--commit-author' debug(3, "commit author #{arg.inspect} added to list") $commit_authors.push(arg.dup) when '--commit-date' debug(3, "commit date #{arg.inspect} added to list") $commit_date.push(arg.dup) when '--commit-file' debug(3, "commit file was #{$commit_file.inspect} : is #{arg.inspect}") $commit_file = arg when '--commit-message' debug(3, "commit message was #{$commit_message.inspect} : is #{arg.inspect}") $commit_message = arg when '--cvs-path' debug(3, "cvs path was #{$cvs_path.inspect} : is #{arg.inspect}") $cvs_path = arg when '--cvsrc-ignore' if arg =~ /true|yes/i $cvsrc_ignore = true elsif arg =~ /false|no/i $cvsrc_ignore = false else usage("#{opt}: unknown bool format \"#{arg}\"", "Valid options are \"true\", \"false\", \"yes\", or \"no\"") end debug(3, "ignoring of ~/.cvsrc is set to #{$cvsrc_ignore.inspect}") when '--echo-path' debug(3, "echo path was #{$echo_path.inspect} : is #{arg.inspect}") $echo_path = arg when '--force-edit' if arg =~ /true|yes/i $force_script_edit = true elsif arg =~ /false|no/i $force_script_edit = false else usage("#{opt}: unknown bool format \"#{arg}\"", "Valid options are \"true\", \"false\", \"yes\", or \"no\"") end debug(3, "force edit of backout script is set to #{$force_script_edit.inspect}") when '--force-remove' if arg =~ /true|yes/i $force_remove = true elsif arg =~ /false|no/i $force_remove = false else usage("#{opt}: unknown bool format \"#{arg}\"", "Valid options are \"true\", \"false\", \"yes\", or \"no\"") end debug(3, "force removal of files is set to #{$force_remove.inspect}") when '--output' case arg when 'stdout' $output = $stdout when 'stderr' $output = $stderr else usage("#{opt}: unknown output format","Valid outputs are \"stdout\" and \"stderr\"") end debug(3, "output set to #{arg}") when '--quiet-script' if arg =~ /true|yes/i $quiet_script = true elsif arg =~ /false|no/i $quiet_script = false else usage("#{opt}: unknown bool format \"#{arg}\"", "Valid options are \"true\", \"false\", \"yes\", or \"no\"") end debug(3, "quiet script is set to #{$quiet_script.inspect}") when '--shell-args' debug(3, "shell args were #{$shell_args.inspect} : is #{arg.inspect}") $shell_args = arg when '--shell-path' debug(3, "shell path was #{$shell_path.inspect} : is #{arg.inspect}") $shell_path = arg when '--warnings' if arg =~ /true|yes/i $echo_warnings = true elsif arg =~ /false|no/i $echo_warnings = false else usage("#{opt}: unknown bool format \"#{arg}\"", "Valid options are \"true\", \"false\", \"yes\", or \"no\"") end debug(3, "warnings are set to #{$echo_warnings.inspect}") end end rescue GetoptLong::InvalidOption usage("invalid argument") rescue GetoptLong::MissingArgument usage("missing argument") rescue GetoptLong::NeedlessArgument => msg usage("passed an extra argument: #{msg}") end debug(3, "Verbosity set to: #{$debug}") $cvsbin = $cvs_path $cvsbin << " -f" if $cvsrc_ignore if ARGV.length < 1 usage("require a commit message to parse") end $output.puts("Backout directory:\t#{$basedir}") $output.puts("Backout script:\t\t#{$backout_script}") $output.puts("") # Backout script - to be run by hand File.open($backout_script, "w+") do |f| removals = [] updates = [] files = [] f.puts("#!#{$shell_path}#{($force_script_edit && $shell_path == '/bin/sh') ? ' -C' : ''} #{$shell_args}") f.puts() f.puts("# Generated at: #{Time.now()}") f.puts("# Generated by: #{ENV['USER']}\@#{ENV['HOST']}") f.puts() f.puts("BASEDIR=#{$basedir}") f.puts('if [ $BASEDIR != $PWD ]; then') f.puts(' echo "Please change to $BASEDIR before running this shell script"') f.puts(' exit 1') f.puts('fi') f.puts() author_regexp = Regexp.new(/^([^\ ]+)\s+([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2}) ([A-Z]{3})$/) file_regexp = Regexp.new(/^ ([\d\.]+)\s+\+([\d]+) \-([\d]+)\s+(.*?)$/) newdead_regexp = Regexp.new(/^(.*?) \((new|dead)\)$/) rev_regexp = Regexp.new(/^ Revision Changes Path$/) for email_file in ARGV File.open(email_file) do |e| $output.print("Scanning through #{email_file}...") found_files = false for line in e line.chomp! if found_files == false amd = author_regexp.match(line) if !amd.nil? $commit_authors.push(amd[1].dup) $commit_dates.push(Time.local(*amd[2..7]).dup) elsif rev_regexp.match(line) found_files = true end else # if found_files md = file_regexp.match(line) next if md.nil? filename = md[4] ndmd = newdead_regexp.match(filename) if !ndmd.nil? filename = ndmd[1] if ndmd[2] == 'new' removals.push(filename) f.puts("#{$force_remove ? '' : '# '}#{$echo_path} -n \"Removing #{filename}...\"") if !$quiet_script f.puts("#{$force_remove ? '' : '# '}#{$cvsbin} rm -f #{filename}") f.puts("#{$force_remove ? '' : '# '}#{$echo_path} \"done.\"") if !$quiet_script f.puts() files.push(filename) next end end f.puts("#{$echo_path} -n \"Updating #{filename} to #{md[1]}...\"") if !$quiet_script f.puts("#{$cvsbin} up -p -r #{md[1]} #{filename} > #{filename}") f.puts("#{$echo_path} \"done.\"") if !$quiet_script f.puts() files.push(filename) end # if found_files end # for line in.. $output.puts("done.") end # File.open() end # for email_file in ARGV... if removals.length > 0 && $force_remove == false f.puts("#{$echo_warnings ? '' : '# '}#{$echo_path} \"You may want to remove the following file#{removals.length > 1 ? 's' : ''}:\"") for filename in removals f.puts("#{$echo_warnings ? '' : '# '}#{$echo_path} \"\t#{filename}\"") end f.puts() f.puts("#{$echo_warnings ? '' : '# '}#{$echo_path} \"There is code in #{$backout_script} to remove #{removals.length > 1 ? 'these files' : 'this file'} for you,\"") f.puts("#{$echo_warnings ? '' : '# '}#{$echo_path} \"just uncomment them or pass the option --force-remove=true to #{$0}.\"") end f.puts() f.puts("# # # Uncomment the following line to commit the backout.") f.puts("# # #{$echo_path} -n \"Committing backout...\"") if !$quiet_script if !$commit_message.nil? if $commit_message.empty? or $commit_message =~ /^default|no|yes|true|false/i $commit_message = "Backout of commit by #{$commit_authors.join(', ')} done on #{$commit_dates.join(', ')} because\n[___FILL_IN_THE_BLANK___]\n" end f.puts() f.puts("# # # EDIT COMMIT MESSAGE HERE") f.puts("CVSCOMMITMSG=<<DONTUSECVSMSG") f.puts($commit_message) f.puts('DONTUSECVSMSG') f.puts() elsif !$commit_file.nil? f.puts("if [ ! -r #{$commit_file} ]; then") f.puts(" #{$echo_path} \"The commit message file #{$commit_file} is not readable,\"") f.puts(" #{$echo_path} \"please fix this and re-run the script.\"") f.puts(" exit 1") f.puts("fi") f.puts() end f.print("# # #{$cvsbin} ci") if !$commit_message.nil? f.print(" -m \"$CVSCOMMITMSG\"") elsif !$commit_file.nil? f.print(" -F \"#{$commit_file}\"") end f.puts(" #{files.join(' ')}") if !$quiet_script if $commit_message.nil? and $commit_file.nil? f.print("# # #{$echo_path} \"Commit complete. Backout should be complete. Please check to verify.\"") else f.puts("# # #{$echo_path} \"done.\"") end end end # File.open() $output.puts() $output.puts("Change to #{$basedir} and run this script. Please look through this script and") $output.puts("make changes as necessary. There are commented out commands available") $output.puts("in the script.") $output.puts() if !$commit_message.nil? $output.puts("If you scroll to the bottom of #{$backout_script} you should be able to") $output.puts("find a HERE document with your commit message, if you would like to make") $output.puts("any further changes to your message.") $output.puts() end if !$commit_file.nil? begin stat = File.stat($commit_file) rescue Errno::ENOENT $output.puts("The output file specified, \"#{$commit_file}\" DOES NOT EXIST!!! Please be sure to") $output.puts("create/edit the file \"#{$commit_file}\" before you run this script") $output.puts() end end $output.puts("Example script usage:") $output.puts("\tmv #{$backout_script} #{$basedir}") $output.puts("\tcd #{$basedir}") $output.puts("\tless #{$backout_script}") $output.puts("\t#{$shell_path} #{$backout_script}") $output.puts("\trm -f #{$backout_script}") $output.puts()