Skip to content

Instantly share code, notes, and snippets.

@akm
Created February 22, 2010 07:53
Show Gist options
  • Save akm/310915 to your computer and use it in GitHub Desktop.
Save akm/310915 to your computer and use it in GitHub Desktop.
#! /usr/bin/env ruby
require 'fileutils'
require "optparse"
OPTIONS = {
:default => 'n',
:confirmation => :once,
:sort => :path,
:display_format => '"mtime size path"',
:verbose => false
}
OptionParser.new do |opt|
opt.on("-o", "--confirm-once"){ OPTIONS[:confirmation] = :once}
opt.on("-e", "--confirm-each"){ OPTIONS[:confirmation] = :each}
opt.on("-y", "--confirm-none"){ OPTIONS[:confirmation] = :none}
opt.on("-D", "--display-format=#{OPTIONS[:display_format]}"){|v| OPTIONS[:display_format] = v}
opt.on("-R", "--sort-reverse"){ OPTIONS[:sort_reverse] = true}
opt.on("-P", "--sort-by-path" ){ OPTIONS[:sort] = :path}
opt.on("-N", "--sort-by-name" ){ OPTIONS[:sort] = :name}
opt.on("-S", "--sort-by-size" ){ OPTIONS[:sort] = :size}
opt.on("-A", "--sort-by-last-accessed-time"){ OPTIONS[:sort] = :atime}
opt.on("-C", "--sort-by-last-changed-time" ){ OPTIONS[:sort] = :ctime}
opt.on("-M", "--sort-by-last-modified-time"){ OPTIONS[:sort] = :mtime}
opt.on("-d", "--default=no"){|v| OPTIONS[:default] = v}
opt.on("-n", "--noop"){ OPTIONS[:noop] = true}
opt.on("-v", "--verbose"){ OPTIONS[:verbose] = true}
opt.parse!(ARGV)
end
class MetaFile
attr_reader :path
def initialize(path)
@path = path
end
def name
File.basename(@path)
end
alias_method :display_path, :path
alias_method :display_name, :name
def size
File.size(@path)
end
def display_size
self.class.commify(size)
end
%w(atime ctime mtime).each do |attr|
self.module_eval(<<-"EOS")
def #{attr}
File.#{attr}(@path)
end
def display_#{attr}
#{attr}.strftime("%Y-%m-%d %H:%M:%S")
end
EOS
end
def display
"%s % 20s byte %s" % [display_mtime, display_size, display_path]
end
def rm
FileUtils.rm(@path,
:verbose => self.class.verbose,
:noop => self.class.noop)
end
class << self
attr_accessor :verbose
attr_accessor :noop
def commify(num)
num.to_s.reverse.scan(/\d{1,3}/).join(",").reverse
end
def glob(*paths)
targets = []
paths.each do |path|
targets.concat(Dir.glob(path))
end
targets.map{|path| MetaFile.new(path) }
end
end
end
MetaFile.verbose = !!OPTIONS[:verbose]
MetaFile.noop = !!OPTIONS[:noop]
targets = MetaFile.glob(ARGV)
sort_attr = OPTIONS[:sort] || :path
sorted = targets.sort_by{|target| target.send(sort_attr) }
sorted = sorted.reverse if OPTIONS[:sort_reverse]
def confirm(msg, prompt, help_msg)
choices = /^[#{prompt.downcase}]/i
help_msg << "\nh - help, show this help"
valid_answer = false
begin
print "#{msg} [#{prompt}] "
answer = STDIN.gets
answer = OPTIONS[:default] if answer.strip.empty?
case answer
when /^h/i then
puts help_msg
when choices then
valid_answer = true
yield(answer)
end
end until valid_answer
end
if OPTIONS[:confirmation] == :once
sorted.each do |target|
puts target.display
end
end
puts "total %d files %s byte" % [
sorted.length,
MetaFile.commify(sorted.inject(0){|sum, t| sum + t.size})]
def delete_files(files)
files.each{|f| f.rm}
end
def confirm_once(files)
help_msg = <<EOS
y - yes
n - no
e - confirm each files
EOS
prompt = (OPTIONS[:default] =~ /^y/i) ? 'Yne' : 'yNe'
confirm("Now removing them. Are you sure?", prompt , help_msg) do |answer|
case answer
when /^y/i then delete_files(files)
when /^n/i then puts "aborted"
when /^e/i then confirm_each(files)
end
end
end
def confirm_each(files)
help_msg = <<EOS
y - yes, overwrite
n - no, do not overwrite
a - all, overwrite this and all others
q - quit, abort
EOS
prompt = (OPTIONS[:default] =~ /^y/i) ? 'Ynaq' : 'yNaq'
all_yes = false
files.each do |target|
if all_yes
target.rm
next
end
confirm("delete? #{target.display}", prompt, help_msg) do |answer|
case answer
when /^y/i then target.rm
when /^n/i then # do nothing
when /^a/i then target.rm; all_yes = true
when /^q/i then puts "aborted"; exit(true)
end
end
end
end
case OPTIONS[:confirmation]
when :none then delete_files(sorted)
when :once then confirm_once(sorted)
when :each then confirm_each(sorted)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment