euccas
6/4/2013 - 5:28 AM

[ruby] clean old files

#!/usr/bin/env ruby

USAGE=<<EOS
Delete files in specified folders that are older than a given number of days.
  Options:
  -v         - verbose. Will list folders and files.
  -d         - dry run. Like verbose, but does not delete files.
  -h         - Show this usage help.
 
  Arguments:
  no of days - an integer.
  paths      - a space-separated list of folders.
 
  e.g. of usage:
  clear_old_files.rb -d 3 ~/source_root/tmp/files ~/source_root/public/downloads
 
  Exits with non-zero return code if the number of days is not numeric or if any of the paths do not exist.
 
EOS

require 'find'

opts    = ''
opts    << ARGV.shift while ARGV[0] && ARGV[0].start_with?('-')
verbose = opts[/v/i] != nil
dry_run = opts[/d/i] != nil
if opts[/h/i] != nil
  puts USAGE
  exit
end
verbose = true if dry_run

begin
  no_days = Integer(ARGV.shift)
rescue ArgumentError
  $stderr.print "Error: The first argument must be the number of days to keep; exiting.\n"
  exit 1  
end

if no_days == 0
  $stderr.print "Error: No arguments specified; exiting.\n"
  exit 1  
end

paths     = ARGV
time      = Time.now - (no_days*24*60*60)
to_delete = []

if paths.empty?
  $stderr.print "Error: No paths specified; exiting.\n"
  exit 1  
end

puts "Deleting files older than #{time}" if verbose
begin
  paths.each {|path| raise IOError, "Path \"#{path}\" does not exist" unless File.directory?(path) }
rescue IOError => e
  $stderr.print "Error: #{e.message}; exiting.\n"
  exit 1  
end

paths.each do |path|
  puts "Cleaning path: \"#{path}\"" if verbose
  Find.find(path) do |f|
    Find.prune if File.directory?(f) && f != path
    to_delete << f if File.file?(f) && File.lstat(f).mtime < time
  end
end

if dry_run
  to_delete.each {|f| puts "  To be deleted: \"#{f}\"" }
else
  to_delete.each do |f|
    puts "  deleting \"#{f}\"" if verbose
    File.delete f
  end
end