Skip to content

Instantly share code, notes, and snippets.

@h3rald
Created September 11, 2011 19:06
Show Gist options
  • Save h3rald/1209976 to your computer and use it in GitHub Desktop.
Save h3rald/1209976 to your computer and use it in GitHub Desktop.
Directory Scanner based on SHA1 hash comparison
require "pathname"
require "digest/sha1"
require "yaml"
require 'trollop'
module DirScan
class Scanner
def initialize dir=Dir.pwd, options={:verbose => false}
@dir = Pathname.new(dir).expand_path
@file = Pathname.new('dirscan.yml').expand_path
@verbose = options[:verbose]
end
def scan
puts "Scanning '#{@dir}'..."
@contents = {}.tap do |contents|
@dir.find do |f|
contents[f.to_s] = sha1 f if f.file?
end
end
end
def sha1 file
Digest::SHA1.new.tap do |hash|
File.open(file, 'r') do |fh|
while buffer = fh.read(1024) do
hash << buffer
end
end
end.to_s
end
def save
puts "Saving '#{@file}'..."
File.open(@file, 'w+') do |f|
h = {
:directory => @dir,
:timestamp => Time.now,
:contents => @contents
}
f.write h.to_yaml
end
end
def compare
@snapshot = YAML.load_file @file
a_hash = @snapshot[:contents]
b_hash = scan
a_hash.delete_if {|k, v| k =~ /[\/\\]dirscan.yml$/}
b_hash.delete_if {|k, v| k =~ /[\/\\]dirscan.yml$/}
@result = {:created => [], :updated => [], :deleted => [], :unchanged => []}
a_hash.each do |a_key, a_value|
b_value = b_hash.delete a_key
case
when !b_value then
@result[:deleted] << a_key
when b_value != a_value then
@result[:updated] << a_key
else
@result[:unchanged] << a_key
end
end
@result[:created] = b_hash.keys
end
def report
total = @result.values.map{|v| v.size}.inject :'+'
puts "="*50
puts "Total files: #{total}"
puts "- Unchanged: #{@result[:unchanged].size}"
puts
puts "Differences since #{@snapshot[:timestamp]}:"
puts "- Updated: #{@result[:updated].size}"
show_files :updated
puts "- Deleted: #{@result[:deleted].size}"
show_files :deleted
puts "- Created: #{@result[:created].size}"
show_files :created
puts "="*50
end
protected
def show_files key
return unless @verbose
@result[key].each do |file|
puts "\t#{file.gsub /^#{Regexp.escape @dir.to_s}/, ''}"
end
end
end
end
options = Trollop::options do
opt :scan, "Scan directory", :default => Dir.pwd
opt :compare, "Compare files", :default => false
opt :write, "Save snapshot file", :default => false
opt :verbose, "Display file names as well", :default => false
end
scanner = DirScan::Scanner.new(options[:scan], :verbose => options[:verbose])
if options[:compare] then
scanner.compare
scanner.save if options[:write]
scanner.report
else
scanner.scan
scanner.save
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment