dl_cleanup.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #!/usr/bin/env python
  2. """
  3. # OpenWRT download directory cleanup utility.
  4. # Delete all but the very last version of the program tarballs.
  5. #
  6. # Copyright (c) 2010 Michael Buesch <[email protected]>
  7. """
  8. import sys
  9. import os
  10. import re
  11. import getopt
  12. DEBUG = 0
  13. # Commandline options
  14. opt_dryrun = False
  15. def parseVer_1234(match):
  16. progname = match.group(1)
  17. progversion = (int(match.group(2)) << 64) |\
  18. (int(match.group(3)) << 48) |\
  19. (int(match.group(4)) << 32) |\
  20. (int(match.group(5)) << 16)
  21. return (progname, progversion)
  22. def parseVer_123(match):
  23. progname = match.group(1)
  24. patchlevel = match.group(5)
  25. if patchlevel:
  26. patchlevel = ord(patchlevel[0])
  27. else:
  28. patchlevel = 0
  29. progversion = (int(match.group(2)) << 64) |\
  30. (int(match.group(3)) << 48) |\
  31. (int(match.group(4)) << 32) |\
  32. patchlevel
  33. return (progname, progversion)
  34. def parseVer_12(match):
  35. progname = match.group(1)
  36. patchlevel = match.group(4)
  37. if patchlevel:
  38. patchlevel = ord(patchlevel[0])
  39. else:
  40. patchlevel = 0
  41. progversion = (int(match.group(2)) << 64) |\
  42. (int(match.group(3)) << 48) |\
  43. patchlevel
  44. return (progname, progversion)
  45. def parseVer_r(match):
  46. progname = match.group(1)
  47. progversion = (int(match.group(2)) << 64)
  48. return (progname, progversion)
  49. def parseVer_ymd(match):
  50. progname = match.group(1)
  51. progversion = (int(match.group(2)) << 64) |\
  52. (int(match.group(3)) << 48) |\
  53. (int(match.group(4)) << 32)
  54. return (progname, progversion)
  55. extensions = (
  56. ".tar.gz",
  57. ".tar.bz2",
  58. ".orig.tar.gz",
  59. ".orig.tar.bz2",
  60. ".zip",
  61. ".tgz",
  62. ".tbz",
  63. )
  64. versionRegex = (
  65. (re.compile(r"(.+)[-_](\d+)\.(\d+)\.(\d+)\.(\d+)"), parseVer_1234), # xxx-1.2.3.4
  66. (re.compile(r"(.+)[-_](\d\d\d\d)-?(\d\d)-?(\d\d)"), parseVer_ymd), # xxx-YYYY-MM-DD
  67. (re.compile(r"(.+)[-_](\d+)\.(\d+)\.(\d+)(\w?)"), parseVer_123), # xxx-1.2.3a
  68. (re.compile(r"(.+)[-_](\d+)\.(\d+)(\w?)"), parseVer_12), # xxx-1.2a
  69. (re.compile(r"(.+)[-_]r?(\d+)"), parseVer_r), # xxx-r1111
  70. )
  71. blacklist = (
  72. ("linux", re.compile(r"linux-.*")),
  73. ("gcc", re.compile(r"gcc-.*")),
  74. ("boost", re.compile(r"boost.*")),
  75. ("wl_apsta", re.compile(r"wl_apsta.*")),
  76. (".fw", re.compile(r".*\.fw")),
  77. (".arm", re.compile(r".*\.arm")),
  78. (".bin", re.compile(r".*\.bin")),
  79. ("rt-firmware", re.compile(r"RT\d+_Firmware.*")),
  80. )
  81. class EntryParseError(Exception): pass
  82. class Entry:
  83. def __init__(self, directory, filename):
  84. self.directory = directory
  85. self.filename = filename
  86. self.progname = ""
  87. for ext in extensions:
  88. if filename.endswith(ext):
  89. filename = filename[0:0-len(ext)]
  90. break
  91. else:
  92. if DEBUG:
  93. print "Extension did not match on", filename
  94. raise EntryParseError("ext")
  95. for (regex, parseVersion) in versionRegex:
  96. match = regex.match(filename)
  97. if match:
  98. (self.progname, self.version) = parseVersion(match)
  99. break
  100. else:
  101. if DEBUG:
  102. print "Version regex did not match on", filename
  103. raise EntryParseError("ver")
  104. def deleteFile(self):
  105. path = (self.directory + "/" + self.filename).replace("//", "/")
  106. print "Deleting", path
  107. if not opt_dryrun:
  108. os.unlink(path)
  109. def __eq__(self, y):
  110. return self.filename == y.filename
  111. def __ge__(self, y):
  112. return self.version >= y.version
  113. def usage():
  114. print "OpenWRT download directory cleanup utility"
  115. print "Usage: " + sys.argv[0] + " [OPTIONS] <path/to/dl>"
  116. print ""
  117. print " -d|--dry-run Do a dry-run. Don't delete any files"
  118. print " -B|--show-blacklist Show the blacklist and exit"
  119. def main(argv):
  120. global opt_dryrun
  121. try:
  122. (opts, args) = getopt.getopt(argv[1:],
  123. "hdB",
  124. [ "help", "dry-run", "show-blacklist", ])
  125. if len(args) != 1:
  126. raise getopt.GetoptError()
  127. except getopt.GetoptError:
  128. usage()
  129. return 1
  130. directory = args[0]
  131. for (o, v) in opts:
  132. if o in ("-h", "--help"):
  133. usage()
  134. return 0
  135. if o in ("-d", "--dry-run"):
  136. opt_dryrun = True
  137. if o in ("-B", "--show-blacklist"):
  138. for (name, regex) in blacklist:
  139. print name
  140. return 0
  141. # Create a directory listing and parse the file names.
  142. entries = []
  143. for filename in os.listdir(directory):
  144. if filename == "." or filename == "..":
  145. continue
  146. for (name, regex) in blacklist:
  147. if regex.match(filename):
  148. if opt_dryrun:
  149. print filename, "is blacklisted"
  150. break
  151. else:
  152. try:
  153. entries.append(Entry(directory, filename))
  154. except (EntryParseError), e: pass
  155. # Create a map of programs
  156. progmap = {}
  157. for entry in entries:
  158. if entry.progname in progmap.keys():
  159. progmap[entry.progname].append(entry)
  160. else:
  161. progmap[entry.progname] = [entry,]
  162. # Traverse the program map and delete everything but the last version
  163. for prog in progmap:
  164. lastVersion = None
  165. versions = progmap[prog]
  166. for version in versions:
  167. if lastVersion is None or version >= lastVersion:
  168. lastVersion = version
  169. if lastVersion:
  170. for version in versions:
  171. if version != lastVersion:
  172. version.deleteFile()
  173. if opt_dryrun:
  174. print "Keeping", lastVersion.filename
  175. return 0
  176. if __name__ == "__main__":
  177. sys.exit(main(sys.argv))