Skip to content

Instantly share code, notes, and snippets.

@gotoken
Created March 31, 2010 05:14
Show Gist options
  • Save gotoken/349967 to your computer and use it in GitHub Desktop.
Save gotoken/349967 to your computer and use it in GitHub Desktop.
#! /usr/bin/env ruby
require "fileutils"
require "getopts"
ENV['LANG']="C"
USAGE = <<USAGE
usage: #$0 [options] dir1 dir2\n
options:
-f Force diffing. If not given, try to use cache under ~/.diffrb.
-b Ignore changes in amount of white space.
-B Ignore changes that just insert or delete blank lines.
-N treat only file as present but empty in the other directory.
-p Print diff(1) and exit.
--change | --add | --delete
Reports only change/add/delete. No two of these can't be given.
--diff
Reports as diff command to leads "| sh". Implies --change.
--noprefix
Do not print one-letter prefix A, C, nor D.
USAGE
opterr = getopts("fpbNB0", "change", "add", "delete", "help", "noprefix", "diff")
if $OPT_diff
$OPT_change = true
$OPT_add, $OPT_delete = nil
end
if $OPT_change && $OPT_add or
$OPT_change && $OPT_delete or
$OPT_delete && $OPT_add
abort USAGE
end
if ARGV.size != 2 or $OPT_help or !opterr
abort USAGE
end
non_directory = ARGV.find_all{|d| !File.directory?(d)}
if !non_directory.empty?
non_directory.each{|d|
STDERR.puts "#$0: #{d}: not a directory"
}
abort USAGE
end
$OPT_all = !$OPT_add && !$OPT_change && !$OPT_delete
dir1, dir2 = ARGV.map{|i| i.dup}
dir1.sub!(%r#/+$#, '')
dir2.sub!(%r#/+$#, '')
opts = "-q"
opts << "b" if $OPT_b
opts << "B" if $OPT_B
opts << "N" if $OPT_N
uopts = "-u"
uopts << "b" if $OPT_b
uopts << "B" if $OPT_B
uopts << "N" if $OPT_N
uopts << "0" if $OPT_0
rcdir = ENV["HOME"]+"/.diffrb"
fn = ARGV.map{|d| File.expand_path(d).gsub("/", "___")}.join("---")
difffile = File.join(rcdir, fn+".txt")
if !File.exist?(difffile) or $OPT_f
FileUtils.mkdir_p(rcdir)
STDERR.puts("# #$0: executing diff -qr #{dir1} #{dir2}")
system("diff -qr #{dir1} #{dir2} > #{difffile}")
end
diff = File.read(difffile)
if $OPT_p
print diff
exit
end
change = diff.scan(/Files #{Regexp::quote(dir1)}\/(.*?) and #{Regexp.quote(dir2)}\/\1 differ/u).flatten.sort
deleted = diff.scan(/Only in #{Regexp.quote(dir1)}\/(\S+): (.+)$/u).map{|i| i.join("/")}.sort
added = diff.scan(/Only in #{Regexp.quote(dir2)}\/(\S+): (.+)$/u).map{|i| i.join("/")}.sort
if !$OPT_add and !$OPT_delete
if $OPT_diff
change.each{|i| puts %<diff #{uopts} "#{dir1}/#{i}" "#{dir2}/#{i}">}
else
change.each{|i| puts $OPT_noprefix ? i : "C #{i}"}
end
end
if !$OPT_change and !$OPT_delete
added.each{|i| puts $OPT_noprefix ? i : "A #{i}"}
end
if !$OPT_add and !$OPT_change
deleted.each{|i| puts $OPT_noprefix ? i : "D #{i}"}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment