naturalselection 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (c) 2009-2010 Evert Pot
  4. # All rights reserved.
  5. # http://www.rooftopsolutions.nl/
  6. #
  7. # This utility is distributed along with SabreDAV
  8. # license: http://sabre.io/license/ Modified BSD License
  9. import os
  10. from optparse import OptionParser
  11. import time
  12. def getfreespace(path):
  13. stat = os.statvfs(path)
  14. return stat.f_frsize * stat.f_bavail
  15. def getbytesleft(path,threshold):
  16. return getfreespace(path)-threshold
  17. def run(cacheDir, threshold, sleep=5, simulate=False, min_erase = 0):
  18. bytes = getbytesleft(cacheDir,threshold)
  19. if (bytes>0):
  20. print "Bytes to go before we hit threshold:", bytes
  21. else:
  22. print "Threshold exceeded with:", -bytes, "bytes"
  23. dir = os.listdir(cacheDir)
  24. dir2 = []
  25. for file in dir:
  26. path = cacheDir + '/' + file
  27. dir2.append({
  28. "path" : path,
  29. "atime": os.stat(path).st_atime,
  30. "size" : os.stat(path).st_size
  31. })
  32. dir2.sort(lambda x,y: int(x["atime"]-y["atime"]))
  33. filesunlinked = 0
  34. gainedspace = 0
  35. # Left is the amount of bytes that need to be freed up
  36. # The default is the 'min_erase setting'
  37. left = min_erase
  38. # If the min_erase setting is lower than the amount of bytes over
  39. # the threshold, we use that number instead.
  40. if left < -bytes :
  41. left = -bytes
  42. print "Need to delete at least:", left;
  43. for file in dir2:
  44. # Only deleting files if we're not simulating
  45. if not simulate: os.unlink(file["path"])
  46. left = int(left - file["size"])
  47. gainedspace = gainedspace + file["size"]
  48. filesunlinked = filesunlinked + 1
  49. if(left<0):
  50. break
  51. print "%d files deleted (%d bytes)" % (filesunlinked, gainedspace)
  52. time.sleep(sleep)
  53. def main():
  54. parser = OptionParser(
  55. version="naturalselection v0.3",
  56. description="Cache directory manager. Deletes cache entries based on accesstime and free space thresholds.\n" +
  57. "This utility is distributed alongside SabreDAV.",
  58. usage="usage: %prog [options] cacheDirectory",
  59. )
  60. parser.add_option(
  61. '-s',
  62. dest="simulate",
  63. action="store_true",
  64. help="Don't actually make changes, but just simulate the behaviour",
  65. )
  66. parser.add_option(
  67. '-r','--runs',
  68. help="How many times to check before exiting. -1 is infinite, which is the default",
  69. type="int",
  70. dest="runs",
  71. default=-1
  72. )
  73. parser.add_option(
  74. '-n','--interval',
  75. help="Sleep time in seconds (default = 5)",
  76. type="int",
  77. dest="sleep",
  78. default=5
  79. )
  80. parser.add_option(
  81. '-l','--threshold',
  82. help="Threshold in bytes (default = 10737418240, which is 10GB)",
  83. type="int",
  84. dest="threshold",
  85. default=10737418240
  86. )
  87. parser.add_option(
  88. '-m', '--min-erase',
  89. help="Minimum number of bytes to erase when the threshold is reached. " +
  90. "Setting this option higher will reduce the amount of times the cache directory will need to be scanned. " +
  91. "(the default is 1073741824, which is 1GB.)",
  92. type="int",
  93. dest="min_erase",
  94. default=1073741824
  95. )
  96. options,args = parser.parse_args()
  97. if len(args)<1:
  98. parser.error("This utility requires at least 1 argument")
  99. cacheDir = args[0]
  100. print "Natural Selection"
  101. print "Cache directory:", cacheDir
  102. free = getfreespace(cacheDir);
  103. print "Current free disk space:", free
  104. runs = options.runs;
  105. while runs!=0 :
  106. run(
  107. cacheDir,
  108. sleep=options.sleep,
  109. simulate=options.simulate,
  110. threshold=options.threshold,
  111. min_erase=options.min_erase
  112. )
  113. if runs>0:
  114. runs = runs - 1
  115. if __name__ == '__main__' :
  116. main()