#!/usr/bin/env python
# statfile.py -- present os.stat results in a friendlier form.

import os, time, pwd, grp
from stat import *

def statfile(path):
    "Read meta-data of file path and return a ls -l like one-liner"
    stat_val  = os.stat(path)
    stat_dict = parse_stat(path, stat_val)
    stat_line = format_stat(stat_dict)
    return stat_line

def parse_stat(path, sval):
    "Parse os.stat tuple sval into a dictionary"
    d = {}
    d['path']      = path
    
    mode           = sval[ST_MODE]
    d['type']      = mode_to_filetype(mode)
    d['perms']     = permissions_to_string(S_IMODE(mode))
    d['dev']       = sval[ST_DEV]
    d['ino']       = sval[ST_INO]
    d['nlinks']    = sval[ST_NLINK]
    d['size']      = sval[ST_SIZE]
    d['owner']     = uid_to_user(sval[ST_UID])
    d['group']     = gid_to_group(sval[ST_GID])
    d['atime']     = epoch_to_string(sval[ST_ATIME])
    d['mtime']     = epoch_to_string(sval[ST_MTIME])
    d['ctime']     = epoch_to_string(sval[ST_CTIME])
    return d

def format_stat(sdict):
    "Format stat dictionary as an ls -l like one-liner"
    s = '(%(dev)d,%(ino)d) %(type)s%(perms)s %(nlinks)d \
%(owner)s %(group)s %(size)d %(mtime)s %(path)s' % sdict 
    return s
    
def mode_to_filetype(mode):
    "Return the file type, accoding to mode"
    if S_ISREG(mode):  return '-'      # regular file
    if S_ISDIR(mode):  return 'd'      # directory
    if S_ISLNK(mode):  return 'l'      # symlink
    if S_ISFIFO(mode): return 'p'      # FIFO
    if S_ISSOCK(mode): return 's'      # socket
    if S_ISCHR(mode):  return 'c'      # character device
    if S_ISBLK(mode):  return 'b'      # block device
    return '?'                         # unknown type: shouldn't happen

def permissions_to_string(perm):
    "Convert permissions (octal) into a string such as rwxr-xr-x"
    bits = [ '-', '-', '-', '-', '-', '-', '-', '-', '-' ]
    if perm & 0x1:    bits[8] = 'x'    # X for other
    if perm & 0x2:    bits[7] = 'w'    # W for other
    if perm & 0x4:    bits[6] = 'r'    # R for other
    if perm & 0x8:    bits[5] = 'x'    # X for group
    if perm & 0x10:   bits[4] = 'w'    # W for group
    if perm & 0x20:   bits[3] = 'r'    # R for group
    if perm & 0x40:   bits[2] = 'x'    # X for owner
    if perm & 0x80:   bits[1] = 'w'    # W for owner
    if perm & 0x100:  bits[0] = 'r'    # R for owner
    if perm & 0x400:  bits[5] = 'g'    # set-gid on exec
    if perm & 0x800:  bits[2] = 's'    # set-uid on exec
    return ''.join(bits)

def uid_to_user(uid):
    "Convert user-id to user name"
    return pwd.getpwuid(uid)[0]

def gid_to_group(gid):
    "Convert group-id to group name"
    return grp.getgrgid(gid)[0]

def epoch_to_string(tsec):
    "Convert Epoch-based seconds tsec into localtime string"
    return time.asctime(time.localtime(tsec))

if __name__ == '__main__':
    import sys
    for fname in sys.argv[1:]:
        print statfile(fname)
