"""pathinfo.py: Object to represent a snapshot of a file's status.
For documentation in "literate programming" style, see:
http://www.nmt.edu/help/lang/python/examples/pathinfo/
"""
#================================================================
# Imports
#----------------------------------------------------------------
import os, stat, time
#================================================================
# Manifest constants
#----------------------------------------------------------------
TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
#================================================================
# Functions and classes
#----------------------------------------------------------------
# - - - - - c l a s s P a t h I n f o - - - - -
class PathInfo:
"""Represents a snapshot of one file's status.
Class invariants:
.path:
[ the pathname passed to the class constructor ]
.size:
[ self.path's size in bytes as an integer ]
.createEpoch:
[ the epoch time when self.path was created ]
.modEpoch:
[ the epoch time when self.path was last modified ]
.mode:
[ the mode bits for self.path ]
"""
# - - - P a t h I n f o . _ _ i n i t _ _ - - -
def __init__ ( self, path ):
"""Constructor for the PathInfo class.
[ path is a string ->
if path names an inode whose status is readable ->
return a new PathInfo containing that status
else -> raise OSError ]
"""
#-- 1 --
self.path = path
#-- 2 --
# [ if path names an existing, accessible file path ->
# self.status := the status tuple for path
# else -> raise OSError ]
self.status = os.lstat ( path )
#-- 3 --
# [ self.status is a status tuple ->
# self.size := size from self.status
# self.createEpoch := creation epoch time from
# self.status
# self.modEpoch := modification epoch time
# from self.status
# self.mode := mode bits from self.status ]
self.size = self.status[stat.ST_SIZE]
self.createEpoch = self.status[stat.ST_CTIME]
self.modEpoch = self.status[stat.ST_MTIME]
self.mode = self.status[stat.ST_MODE]
# - - - P a t h I n f o . i s F i l e - - -
def isFile ( self ):
"""Predicate to test whether this path is an ordinary file.
[ if self represents an ordinary file ->
return a true value
else ->
return a false value ]
"""
return stat.S_ISREG ( self.mode )
# - - - P a t h I n f o . i s D i r - - -
def isDir ( self ):
"""Predicate to test whether this path is a directory.
[ if self represents a directory ->
return a true value
else ->
return a false value ]
"""
return stat.S_ISDIR ( self.mode )
# - - - P a t h I n f o . i s D i r - - -
def isLink ( self ):
"""Predicate to test whether this path is a soft link.
[ if self represents a soft link ->
return a true value
else ->
return a false value ]
"""
return stat.S_ISLNK ( self.mode )
# - - - P a t h I n f o . a b s P a t h - - -
def absPath ( self ):
"""Return self's absolute path name."""
return os.path.abspath ( self.path )
# - - - P a t h I n f o . r e a l P a t h - - -
def realPath ( self ):
"""Return self's absolute path name, with links resolved."""
return os.path.realpath ( self.path )
# - - - P a t h I n f o . { o w n e r } C a n { R e a d } - - -
# { g r o u p } { W r i t e }
# { w o r l d } { E x e c }
def ownerCanRead ( self ):
return self.mode & stat.S_IRUSR
def ownerCanWrite ( self ):
return self.mode & stat.S_IWUSR
def ownerCanExec ( self ):
return self.mode & stat.S_IXUSR
def groupCanRead ( self ):
return self.mode & stat.S_IRGRP
def groupCanWrite ( self ):
return self.mode & stat.S_IWGRP
def groupCanExec ( self ):
return self.mode & stat.S_IXGRP
def worldCanRead ( self ):
return self.mode & stat.S_IROTH
def worldCanWrite ( self ):
return self.mode & stat.S_IWOTH
def worldCanExec ( self ):
return self.mode & stat.S_IXOTH
# - - - m o d T i m e - - -
def modTime ( self ):
"""Format the modification time as yyyy-mm-dd hh:mm:ss."""
return time.strftime ( TIME_FORMAT,
time.localtime ( self.modEpoch ) )
# - - - P a t h I n f o . _ _ s t r _ _ - - -
def __str__ ( self ):
"""Convert self to a string."""
return ( "%s%s %s %8d %s" %
(self.__fileType(), self.__permFlags(),
self.modTime(), self.size, self.path) )
# - - - P a t h I n f o . _ _ f i l e T y p e - - -
def __fileType ( self ):
"""Return the file type code.
[ if self is a regular file ->
return "-"
if self is a directory ->
return "d"
if self is a soft link ->
return "l" ]
"""
if self.isLink():
return "l"
elif self.isDir():
return "d"
elif self.isFile():
return "-"
else:
return "?"
# - - - P a t h I n f o . _ _ p e r m F l a g s - - -
def __permFlags ( self ):
"""Format self.mode's permissions as 'rwxrwxrwx'.
"""
return ( "%s%s%s" %
(self.__rwx ( self.mode & stat.S_IRUSR,
self.mode & stat.S_IWUSR,
self.mode & stat.S_IXUSR ),
self.__rwx ( self.mode & stat.S_IRGRP,
self.mode & stat.S_IWGRP,
self.mode & stat.S_IXGRP ),
self.__rwx ( self.mode & stat.S_IROTH,
self.mode & stat.S_IWOTH,
self.mode & stat.S_IXOTH ) ) )
# - - - P a t h I n f o . _ _ r w x - - -
def __rwx ( self, r, w, x ):
"""Format three permission bits.
[ r, w, and x are Boolean values indicating read,
write and execute permissions ->
return a three-character string displaying those
permissions as "ls -l" displays them ]
"""
return ( "%s%s%s" %
(self.__dasher ( r, "r" ),
self.__dasher ( w, "w" ),
self.__dasher ( x, "x" ) ) )
# - - - P a t h I n f o . _ _ d a s h e r - - -
def __dasher ( self, bit, flag ):
"""Format a permission bit as in ls -l.
[ (bit is a Boolean value) and (flag is a string) ->
if bit is true ->
return flag
else -> return "-" ]
"""
if bit: return flag
else: return "-"
# - - - P a t h I n f o . _ _ c m p _ _ - - -
def __cmp__ ( self, other ):
"""Comparison operator for PathInfo objects.
[ other is a PathInfo object ->
if self.path < other.path ->
return a negative number
else if self.path > other.path ->
return a positive number
else ->
return 0 ]
"""
return cmp ( self.path, other.path )