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

import sys, os

def DeleteFilesAsNeeded( directory, maxUsage, # pylint: disable=redefined-outer-name
                         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:
      # pylint: disable-next=consider-using-f-string
      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 OSError as 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( key=lambda f: f['mtime']  )
   while total > maxUsage:
      f = allfiles.pop()
      if verbose:
         # pylint: disable-next=consider-using-f-string
         print( "removing", f[ 'name' ], "(%d bytes)" % f[ 'size' ] )
      if not dryrun:
         try:
            os.unlink( f['name'] )
         except OSError as e:
            errorHandler( e )
            continue
      total -= f['size']

if __name__ == "__main__":
   import re
   import optparse # pylint: disable=deprecated-module
   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 )
