Wednesday, November 20, 2013

Using Ruby to Delete Unused Files in a Rails Project

I have amassed a rather large set of icons for a RoR project I'm working. Initially I just checked all these files into the repository and everything was great. Gradually the list of icons (most of them not used) got longer and longer. Now I'm to the point where running rake assets:precompile in my production environment takes forever. It's time to defriend all those unused icons.

The first step is to get a list of all the icons I actually use. Lucky for me, every icon is conveniently defined in a CSS file.

def referenced_icons(subdir)
  path_to_css = File.join(Dir.pwd, 'app/assets/stylesheets/all/icons.css.scss')

  # Open the CSS file and scan for lines referencing PNG 
  # files and get just the filename
  used_icons = File.open(path_to_css)  do |f| 
    f.grep(/png/).map{|x| x[Regexp.new("(?<=#{subdir}\/).*.png")]}
  end

  # Beat the list into a smaller package
  used_icons.compact.uniq.sort
end

Great! I can get a list of all the PNG files I actually use. Now who am I going to defriend.

def not_my_friends(subdir)
  used_icons = referenced_icons(subdir)
  path_to_pngs = File.join(Dir.pwd, "app/assets/images/icons/#{subdir}/*.png")
  
  # Reject files not in the used_icons list
  Dir.glob(path_to_pngs).reject do |f|
    b = Pathname(f).basename.to_s
    used_icons.include?(b)
  end
end

And now for the defriending:

not_my_friends('some_dir').each{|x| File.delete(x)}

It feels good to lighten the load (by about 2400 unused icons!). Now back to work!