subdirs.py

'''\
List sub-directories.

commands:
    sizes           - List directory sizes
    recent          - Scan for recently modified files
    list            - Generate a text listing
    xml             - Generate an XML listing

    main            - Main function (normal use)
    demo            - Demo function (show off and test app)
    test            - Test function (development)

usage:
    module.dispatch({command}, args={arguments})    -- calling module from code

    $PYTHON module_name {command} {arguments}       -- executing module externally

Developer@Sonnack.com
April 2016
'''
####################################################################################################
from __future__ import print_function
from sys import argvexc_info
from traceback import extract_tb
from os import pathlistdir
from datetime import datetimetimedelta
from time import localtime
from logger import loggerinfodebugtrace
from filelist import fileobjListFilesListFolderListFolders
from zoo import add_commas
####################################################################################################
Log = logger('subdirs')

BasePath = r'C:\CJS\prj\Python\app'
DemoFilepath = r'C:\cjs\www\root\pub'


##================================================================================================##
def create_xml_listing (*args):
    '''\
List files in XML format.

arguments:
    base-path
    output-file

'''
    basepath = str(args[0]) if 0 < len(argselse DemoFilepath
    listname = str(args[1]) if 1 < len(argselse 'filelist.xml'

    Log.debug('xml-listing/parameters: %d' % len(args))
    Log.info('xml-listing/basepath: %s' % basepath)
    Log.info('xml-listing/listname: %s' % listname)

    fn = path.join(basepathlistname)
    fp = open(fn'w')
    try:
        print('<?xml version="1.0" encoding="UTF-8"?>'file=fp)
        print('<filelist basepath="%s">' % basepathfile=fp)
        _create_xml_listing(basepathfp)
        print('</filelist>'file=fp)
        Log.info('wrote: %s' % fn)
    except:
        raise
    finally:
        fp.close()
    return [basepathfn]
##------------------------------------------------------------------------------------------------##
def _create_xml_listing (pathnamefp):
    Log.trace('xml-listing: %s' % pathname)
    fs = []  # list of files
    ds = []  # list of directories
    # Get list of files in this directory...
    ns = listdir(pathname)
    for n in ns:
        fn = path.join(pathnamen)
        if path.isfile(fn):
            fs.append(fn)
            continue
        if path.isdir(fn):
            ds.append(fn)
            continue

    print('<directory name="%s">' % pathnamefile=fp)
    # Process sub-directories...
    for dn in sorted(ds):
        # RECURSE...
        _create_xml_listing(dnfp)

    for fn in sorted(fs):
        tm = localtime(path.getctime(fn))
        tc = datetime(tm[0],tm[1],tm[2],tm[3],tm[4],tm[5])
        tm = localtime(path.getmtime(fn))
        tu = datetime(tm[0],tm[1],tm[2],tm[3],tm[4],tm[5])
        t = (fnpath.getsize(fn), tctu)
        s = '<file name="%s" size="%d" cdate="%s" mdate="%s" />'
        print(s % tfile=fp)

    print('</directory>'file=fp)

##================================================================================================##
def list_directory_sizes (*args):
    '''\
List Directory Sizes.

arguments:
    base-path
    output-file

'''
    basepath = args[0if 0 < len(argselse DemoFilepath
    listname = args[1if 1 < len(argselse 'dir-sizes.list'

    Log.debug('list-directory-sizes/parameters: %d' % len(args))
    Log.info('list-directory-sizes/basepath: %s' % basepath)
    Log.info('list-directory-sizes/listname: %s' % listname)

    result = []
    t_bytes = _list_directory_sizes(basepathresult)

    fn = path.join(basepathlistname)
    fp = open(fn'w')
    try:
        print('   Total Bytes   Files     Dir Bytes  Files   Directory Name'file=fp)
        print('==============  ======  ============  =====   ========================================='file=fp)
        for d in result:
            s1 = add_commas(d[1]) if d[1] != d[3else '-'
            s2 = add_commas(d[2]) if d[2] != d[4else '-'
            s3 = add_commas(d[3])
            s4 = add_commas(d[4])
            print('%14s %7s %13s %6s   %s' % (s1s2s3s4d[0]), file=fp)
        Log.info('wrote: %s' % fn)
    except:
        raise
    finally:
        fp.close()
    return result
##------------------------------------------------------------------------------------------------##
def _list_directory_sizes (pathnameresult):
    Log.trace('list-directory-size: %s' % pathname)

    ds = []  # list of directories
    dt = [pathname0L0L0L0L# [dirname, total-size, total-count, dir-size, dir-count]
    result.append(dt)
    # Get list of files in this directory...
    ns = listdir(pathname)
    for n in ns:
        fn = path.join(pathnamen)
        if path.isfile(fn):
            dt[3] += path.getsize(fn)
            dt[4] += 1
            continue
        if path.isdir(fn):
            ds.append(fn)
            continue

    # Process sub-directories...
    dt[1] += dt[3]
    dt[2] += dt[4]
    for dn in sorted(ds):
        # RECURSE...
        t = _list_directory_sizes(dnresult)
        # Add sub-dir size to this one's total...
        dt[1] += t[1]
        dt[2] += t[2]

    return dt


##================================================================================================##
def create_text_listing (*args):
    '''\
List files in a nice text format.

arguments:
    base-path
    output-file

'''
    basepath = str(args[0]) if 0 < len(argselse DemoFilepath
    listname = str(args[1]) if 1 < len(argselse 'files.list'

    Log.debug('text-listing/parameters: %d' % len(args))
    Log.info('text-listing/basepath: %s' % basepath)
    Log.info('text-listing/listname: %s' % listname)

    ts = ListFolder(basepath)
    Log.debug('text-listing/found: %d' % len(ts))

    fn = path.join(basepathlistname)
    fp = open(fn'w')
    try:
        for t in ts:
            Log.trace('Dir: %s' % t[0])
            print(t[0], file=fp)
            for f in t[1]:
                fname = path.join(t[0], f)
                fo = fileobj(fname)
                Log.trace('File: %s' % f)
                print('%-40s %9d %s %s' % (ffo.fsizefo.createdfo.updated), file=fp)
            print(file=fp)
        Log.trace()
        Log.info('wrote: %s' % fn)
    except:
        raise
    finally:
        fp.close()
    return ts


##================================================================================================##
def find_recent_files (*args):
    '''\
Find Recent Files.

arguments:
    nbr-days-back
    base-path
    output-file

'''
    datespan = int(args[0]) if 0 < len(argselse 3
    basepath = str(args[1]) if 1 < len(argselse DemoFilepath
    listname = str(args[2]) if 2 < len(argselse 'recent-files.list'

    Log.debug('find-recent-files/parameters: %d' % len(args))
    Log.info('find-recent-files/datespan: %d' % datespan)
    Log.info('find-recent-files/basepath: %s' % basepath)
    Log.info('find-recent-files/listname: %s' % listname)

    dt = datetime.now() - timedelta(datespan)
    ts = ListFolder(basepath)

    fs = []
    for t in ts:
        Log.trace('Dir: %s' % t[0])
        for f in t[1]:
            fn = path.join(t[0], f)
            fo = fileobj(fn)
            if fo.updated < dt:
                continue
            Log.trace('File: %s  [%s, %d]' % (ffo.updatedfo.fsize))
            fs.append(fn)
    Log.trace()

    fn = path.join(basepathlistname)
    fp = open(fn'w')
    try:
        for f in fs:
            print(ffile=fp)
        Log.info('wrote: %s' % fn)
    except:
        raise
    finally:
        fp.close()
    return fs



##================================================================================================##
def dump_filelist (flist):
    Log.trace()
    Log.trace('Total Dirs: %d' % len(flist))
    Log.trace('Total Files: %d' % sum(map(lambda t: len(t[1]), flist)))
    Log.trace()
    for t in flist:
        Log.trace('Dir: %s  (%d files)' % (t[0], len(t[1])))
        for f in t[1]:
            Log.trace('. File: %s' % path.join(t[0], f))
    Log.trace()
##================================================================================================##
def do_test (*args):
    Log.trace('test/parameters: %s' % str(args))
    basepath = args[0if 0 < len(argselse DemoFilepath
    ts = ListFolder(basepath)
    dump_filelist(ts)
    return 'Done!'
##================================================================================================##
def do_demo (*args):
    Log.trace('demo/parameters: %s' % str(args))
    ts = ListFolders(args)
    dump_filelist(ts)
    return 'Done!'
##================================================================================================##
def do_main (*args):
    Log.trace('main/parameters: %s' % str(args))
    ts = ListFolders(args)
    dump_filelist(ts)
    return 'Done!'
####################################################################################################
def dispatch (cmd, *args):
    Log.trace('command: %s' % cmd)
    Log.trace('arguments: %d' % len(args))
    if cmd == 'sizes': return list_directory_sizes(*args)
    if cmd == 'recent': return find_recent_files(*args)
    if cmd == 'list': return create_text_listing(*args)
    if cmd == 'xml': return create_xml_listing(*args)
    if cmd == 'test': return do_test(*args)
    if cmd == 'demo': return do_demo(*args)
    if cmd == 'main': return do_main(*args)
    return 'Nothing to do!'
####################################################################################################
if __name__ == '__main__':
    print('autorun: %s' % argv[0])
    Log.start(path.join(BasePath,'subdirs.log'))
    Log.level(info())
    cmd = argv[1if 1 < len(argvelse ''
    etc = argv[2:if 2 < len(argvelse []
    try:
        obj = dispatch(cmd, *etc)
        print(obj)
        Log.info(obj)
    except:
        etypeevaluetb = exc_info()
        ts = extract_tb(tb)
        Log.error('%s: %s' % (etype.__name__,str(evalue)))
        for t in ts[-3:]:
            Log.error('[%d] %s  (%s)' % (t[1], t[2], t[0]))
            Log.error('    %s' % t[3])
        raise
    finally:
        Log.end()
####################################################################################################
'''eof'''