Sunday, August 2, 2009

Recent Files

As I get back to my projects after a break, I often struggle to remember which files I worked on last.

Here is the utility (ruby script) to show just a few recent files (click to download). After downloading the recent script, run chmod to set executable permission and put it on search path. Running the script with -h parameter prints additional usage information.

I use it on OS X - another OS mileage may vary.

#!/usr/bin/env ruby
#
# (c) 2009 Vlad Didenko
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    See the GNU General Public License at <http://www.gnu.org/licenses/> 
#    for the detailed text of the license.
#

require 'optparse'

$limit  = 10
$target = "."
$dirs = false

optparse = OptionParser.new do |opts|
  opts.banner = "Usage: recent [ -n LIMIT ]  [ -d ] [ -t DIRECTORY ]

    The utility traverses regular files and directories to find which ones are most
    recently modified. Symbolic links and special files (pipes, device files, etc.)
    are ignored. It does not detect hard link loops and filesystem boundaries.
  "

  opts.on( '-n',
           '--limit LIMIT',
           'Only output this number of files. Default is 10.'
  ) { |limit| $limit = limit.to_i }

  opts.on( '-d',
           '--dirs',
           'Include directories in the results. Default is false.'
  ) { $dirs = true }

  opts.on( '-t',
                '--target DIR',
                'Scan the specified directory.'
  ) { |dir| $target = dir }

  opts.on( '-h', '--help', 'Display this screen' ) do
    puts opts
    exit
  end
end.parse!

class RctFile
  attr_reader :mtime, :path
  
  def initialize( name )
    @path = name
    @mtime = File.mtime( name )
  end
  
  def <=>( other )
    - ( @mtime <=> other.mtime )
  end
  
  def recents(limit, dirs)
    r = ( dirs ? [ self ] : [] )
    return r unless File.executable?( @path ) and File.readable?( @path )
    Dir.foreach( @path ) do |file|
      next if file[0..0] == '.'
      fname = @path + '/' + file
      if File.directory?(fname)
        r = r + RctFile.new( fname ).recents( limit, dirs )
      elsif File.file?(fname)
        r << RctFile.new( fname )
      else
        next
      end
    end
    r.sort()[ 0..( limit - 1 ) ]
  end
end

RctFile.new( $target ).recents($limit, $dirs).each do |recent|
  puts "#{recent.mtime}\t#{recent.path}\n"
end