#!/usr/bin/env python
# Copyright (c) 2006-2009, 2010 Arista Networks, Inc.  All rights reserved.
# Arista Networks, Inc. Confidential and Proprietary.

import sys, os

def DeleteFilesAsNeeded( directory, maxUsage,
                         verbose=False, quiet=False, dryrun=False ):
   """Delete oldest file first under 'directory', so that the total usage
   within 'directory' (and all its descendants) stays under the given
   'maxUsage' threshold.  This function never crosses devices or
   follows symlinks."""

   def errorHandler(e):
      if not quiet:
         sys.stderr.write( "warning: " + str( e ) + "\n" )

   dirStat = os.lstat( directory )
   if verbose:
      print "walking", directory, "(device=%s)" % dirStat.st_dev
   total = 0
   allfiles = []
   
   for root, dirs, files in os.walk( directory, topdown=True, onerror=errorHandler ):
      rs = os.lstat( root )
      if rs.st_dev != dirStat.st_dev:
         if verbose:
            print root, "is on different device than", directory, "(skipping)"
         dirs[:] = []
         return
      for f in files:
         name = root + "/" + f
         try:
            st = os.lstat( name )
         except IOError, e:
            errorHandler( e )
            continue
         allfiles.append( { 'name': name, 'mtime': st.st_mtime,
                            'size': st.st_size } )
         total += st.st_size

   if verbose:
      print "found", total, "bytes in", len(allfiles), "files"
   if total <= maxUsage:
      return
   allfiles.sort( lambda f1, f2: cmp( f2['mtime'], f1['mtime'] ))
   while total > maxUsage:
      f = allfiles.pop()
      if verbose:
         print "removing", f['name'], "(%d bytes)" % f['size']
      if not dryrun:
         try:
            os.unlink( f['name'] )
         except IOError, e:
            errorHandler( e )
            continue
      total -= f['size']

if __name__ == "__main__":
   import re
   import optparse
   op = optparse.OptionParser( usage =
                               """%prog [options] directory ####[b|k|m|g]
example: %prog /tmp/mydir 1000k""" )
   def usage():
      op.print_help()
      sys.exit( 1 )
      
   op.add_option( "-v", "--verbose", action="store_true", dest="verbose",
                  help="explain what is being done" )
   op.add_option( "-q", "--quiet", action="store_true", dest="quiet",
                  help="suppress all normal output" )
   op.add_option( "-n", "--dry-run", action="store_true", dest="dryrun",
                  help="don't actually do anything" )
   ( options, args ) = op.parse_args()
   if len(args) != 2:
      op.error( "incorrect number of arguments" )
   ( directory, maxUsageStr ) = args
   if not os.path.isdir( directory ):
      sys.stderr.write( "%s: not a directory\n", directory )
      sys.exit( 1 )
   m = re.match( "^([0-9]+)([bkmg])$", maxUsageStr ) or usage()
   ( maxUsage, unit ) = m.groups()
   maxUsage = \
       int(maxUsage) * { 'b': 1, 'k': 1000, 'm': 1000000, 'g': 1000000000 }[ unit ]
   DeleteFilesAsNeeded( directory, maxUsage, verbose=options.verbose,
                        quiet=options.quiet, dryrun=options.dryrun )
