Add a getopt-ified version of an old tool that I've been using for ages:
backout_commit.rb. Tool can be used to automate the process of backing out either small or large commits based off of one or more commit messages. The result of the script is a shell script which can be edited or run as needed. New and dead files are taken into consideration. See the program's usage statement for more configuration details. Here's an example usage: <programlisting> $ mutt [find commit message, save to disk as cvsmsg.txt] $ backout_commit.rb ~/cvsmsg.txt Backout directory: /usr Backout script: backout-2003-01-31-14-04.sh Scanning through cvsmsg.txt...done. Change to /usr and run this script. Please look through this script and make changes as necessary. There are commented out commands available in the script. Example script usage: mv backout-2003-01-31-14-04.sh /usr cd /usr less backout-2003-01-31-14-04.sh /bin/sh backout-2003-01-31-14-04.sh rm -f backout-2003-01-31-14-04.sh </programlisting>
This commit is contained in:
parent
96db12517f
commit
d61fae8409
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=110160
@ -2,11 +2,14 @@
|
||||
|
||||
This directory is for tools.
|
||||
|
||||
A tool is something which is sometimes useful, and doesn't fit any of the
|
||||
other categories.
|
||||
A tool is something which is sometimes useful, and doesn't fit any of
|
||||
the other categories.
|
||||
|
||||
Please make a subdir per program, and add a brief description to this file.
|
||||
Please make a subdir per program, and add a brief description to this
|
||||
file.
|
||||
|
||||
backout_commit A tool for reading in a commit message and generating
|
||||
a script that will backout the commit.
|
||||
commitsdb A tool for reconstructing commit history using md5
|
||||
checksums of the commit logs.
|
||||
crypto Exercise the crypto framework through /dev/crypto
|
||||
|
350
tools/tools/backout_commit/backout_commit.rb
Normal file
350
tools/tools/backout_commit/backout_commit.rb
Normal file
@ -0,0 +1,350 @@
|
||||
#!/usr/bin/env ruby -w
|
||||
|
||||
# $FreeBSD$
|
||||
|
||||
# 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()
|
Loading…
Reference in New Issue
Block a user