#!/usr/bin/env python #================================================================ # bigfiles.py: Script to show files in descending order by size. # For documentation in "literate programming" style, see: # http://www.nmt.edu/help/lang/python/examples/pathinfo/ #---------------------------------------------------------------- SCRIPT_NAME = "bigfiles.py" EXTERNAL_VERSION = "1.1" #================================================================ # Imports #---------------------------------------------------------------- import sys, os import pathinfo # - - - - - m a i n - - - - - def main(): """Main program.""" print "=== %s %s ===" % (SCRIPT_NAME, EXTERNAL_VERSION) #-- 1 -- # [ if sys.argv[1:] is empty -> # dirList := [ "." ] # else -> # dirList := sys.argv[1:] ] dirList = sys.argv[1:] if len(dirList) == 0: dirList = [ "." ] #-- 2 -- # [ sys.stdout +:= reports listing files below each # directory named in dirList, with files in descending # order by size ] for dirName in dirList: #-- 2 body -- # [ dirName is a string -> # sys.stdout +:= a report listing the files below # directory (dirName), with files in descending # order by size ] report ( dirName ) # - - - r e p o r t - - - def report ( dirName ): """Generate the report for one directory subtree. [ dirName is a string -> sys.stdout +:= a report listing the files below directory (dirName), with files in descending order by size ] """ #-- 1 - # [ basePath := dirName's absolute path name # sys.stdout +:= report heading showing dirName's real # absolute path ] basePath = os.path.abspath ( dirName ) print "\n === %s ===" % os.path.realpath ( dirName ) #-- 2 -- # [ bigReport := a BigReport object describing all the # accessible files in directory tree (dirName) ] bigReport = BigReport ( basePath ) #-- 3 -- # [ bigReport is a BigReport object -> # sys.stdout +:= lines describing files in bigReport # in descending order by size ] for bigInfo in bigReport.genFiles(): print bigInfo #================================================================ # Functions and classes #---------------------------------------------------------------- # - - - - - c l a s s B i g I n f o - - - - - class BigInfo(pathinfo.PathInfo): """Represents information about one file; sorts by size. Exports: BigInfo ( path, basePath ): [ (path is the path name to a file) and (basePath is the path name of some directory above path) -> return a new BigInfo instance with those values ] .__cmp__ ( self, other ): [ other is a BigInfo instance -> return cmp ( other.size, self.size ) ] .__str__ ( self ): [ return a string describing self's modification time, its size, and its path name relative to basePath ] State/Invariants: .__basePath: [ as passed to constructor, read-only ] """ # - - - B i g I n f o . _ _ i n i t _ _ - - - def __init__ ( self, path, basePath ): """Constructor for BigInfo.""" #-- 1 -- pathinfo.PathInfo.__init__ ( self, path ) #-- 2 -- self.__basePath = basePath # - - - B i g I n f o . _ _ c m p _ _ - - - def __cmp__ ( self, other ): """Compare two BigInfo objects. [ other is a BigInfo object -> if self should precede other -> return a negative number else if self should follow other -> return a positive number else -> return 0 ] """ #-- 1 -- compare = - cmp ( self.size, other.size ) #-- 2 -- if compare != 0: return compare #-- 3 -- return cmp(self.path, other.path) # - - - B i g I n f o . _ _ s t r _ _ - - - def __str__ ( self ): """Format a BigInfo for printing.""" #-- 1 -- # [ if self represents a directory -> # suffix := "/" # else -> # suffix := "" ] if self.isDir(): suffix = "/" else: suffix = "" #-- 2 -- # [ self.__basePath is the absolute path of a directory # above self.path -> # relPath := path to self.path relative to # self.__basePath ] absPath = os.path.abspath ( self.path ) relPath = absPath [ len(self.__basePath) + 1 : ] #-- 3 -- if relPath == "": relPath = "." suffix = "" #-- 4 -- return ( "%s %10s %s%s" % (self.modTime(), self.size, relPath, suffix) ) # - - - - - c l a s s B i g R e p o r t - - - - - class BigReport: """Holds the big-files report. Exports: BigReport ( dir ): [ dir is a string -> if dir names a directory to which we have access -> return a BigReport object describing all the accessible files in that directory's subtree else -> raise OSError ] .genFiles(): [ generate a sequence of BigInfo objects representing the files in self, in descending order by file size, with the path name as a secondary key ] Class invariants: .__bigList: [ a list of information on all the files in self as BigInfo objects, sorted ] """ # - - - B i g R e p o r t . _ _ i n i t _ _ - - - def __init__ ( self, dir ): """Constructor for the BigReport class.""" #-- 1 -- self.__bigList = [] #-- 2 -- # [ dir is a string -> # self.__bigList := self.__bigList with BigInfo # objects added representing every accessible # file in the subtree named by dir ] os.path.walk ( dir, self.__visitor, dir ) #-- 3 -- # [ self.__bigList := self.__bigList, sorted ] self.__bigList.sort() # - - - B i g R e p o r t . _ _ v i s i t o r - - - def __visitor ( self, basePath, dirName, nameList ): """Visitor function for os.path.walk. [ (basePath is the absolute path name to a directory above dirName) and (dirName is the name of a directory) and (nameList is a list of the names within that directory) -> self.__bigList := self.__bigList with BigInfo objects added representing the accessible ordinary files in nameList ] """ #-- 1 -- # [ self.__bigList := self.__bigList with a BigInfo # object added representing dirName ] try: dirInfo = BigInfo ( dirName, basePath ) self.__bigList.append ( dirInfo ) except OSError, detail: pass #-- 2 -- for fileName in nameList: #-- 2 body -- # [ if fileName names an accessible regular file -> # self.__bigList := self.__bigList with a new # BigInfo object representing fileName # else -> I ] #-- 2.1 -- # [ filePath := dirName + fileName ] filePath = os.path.join ( dirName, fileName ) #-- 2.2 -- # [ if filePath is an accessible path to a regular file -> # self.__bigList := self.__bigList + (a BigInfo # showing the status of filePath) # else -> I ] try: bigInfo = BigInfo ( filePath, basePath ) if bigInfo.isFile(): self.__bigList.append ( bigInfo ) except OSError, detail: pass # - - - B i g R e p o r t . g e n F i l e s - - - def genFiles ( self ): """Generate the BigInfo objects in self.__bigList.""" for bigInfo in self.__bigList: yield bigInfo raise StopIteration # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if __name__ == "__main__": main()