#!/usr/bin/env python
import argparse
import fnmatch
import os
import sys
# Recursively generate index.html files for
# all subdirectories in a directory tree
index_file_name = 'index.html'
CSS = """
"""
def process_dir(top_dir, opts):
for parentdir, dirs, files in os.walk(unicode(top_dir)):
if not opts.dryrun:
index_file = open(os.path.join(parentdir, index_file_name), "w")
index_file.write('''
{css}
{curr_dir}
↰'''.format(
css=CSS,
curr_dir=os.path.basename(os.path.abspath(parentdir).encode('utf8'))
)
)
for dirname in sorted(dirs):
absolute_dir_path = os.path.join(parentdir, dirname)
if not os.access(absolute_dir_path, os.W_OK):
print("***ERROR*** folder {} is not writable! SKIPPING!".format(absolute_dir_path))
continue
if opts.verbose:
print('DIR:{}'.format(absolute_dir_path))
if not opts.dryrun:
index_file.write("""
📁 {link_text}""".format(
link=dirname.encode('utf8'),
link_text=dirname.encode('us-ascii', 'xmlcharrefreplace')))
for filename in sorted(files):
if opts.filter and not fnmatch.fnmatch(filename, opts.filter):
if opts.verbose:
print('SKIP: {}/{}'.format(parentdir, filename))
continue
if opts.verbose:
print('{}/{}'.format(parentdir, filename))
filename_escaped = filename.encode('us-ascii', 'xmlcharrefreplace')
filename_utf8 = filename.encode('utf8')
if filename.strip().lower() == index_file_name.lower():
continue
try:
size = int(os.path.getsize(os.path.join(parentdir, filename)))
if not opts.dryrun:
index_file.write(
"""
📄 {link_text}{size}""".format(
link=filename_utf8,
link_text=filename_escaped,
size=pretty_size(size))
)
except Exception as e:
print('ERROR writing file name:', e)
print('filename_utf8:')
repr(filename_utf8)
print('filename_escaped:'),
repr(filename_escaped)
if not opts.dryrun:
index_file.write("""
""")
index_file.close()
# bytes pretty-printing
UNITS_MAPPING = [
(1024 ** 5, ' PB'),
(1024 ** 4, ' TB'),
(1024 ** 3, ' GB'),
(1024 ** 2, ' MB'),
(1024 ** 1, ' KB'),
(1024 ** 0, (' byte', ' bytes')),
]
def pretty_size(bytes, units=UNITS_MAPPING):
"""Human-readable file sizes.
ripped from https://pypi.python.org/pypi/hurry.filesize/
"""
for factor, suffix in units:
if bytes >= factor:
break
amount = int(bytes / factor)
if isinstance(suffix, tuple):
singular, multiple = suffix
if amount == 1:
suffix = singular
else:
suffix = multiple
return str(amount) + suffix
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='''DESCRIPTION:
Generate directory index files recursively.
Start from current dir or from folder passed as first positional argument.
Optionally filter by file types with --filter "*.py". ''')
parser.add_argument('top_dir',
nargs='?',
action='store',
help='top folder from which to start generating indexes, '
'use current folder if not specified',
default=os.getcwd())
parser.add_argument('--filter', '-f',
help='only include files matching glob',
required=False)
parser.add_argument('--verbose', '-v',
action='store_true',
help='***WARNING: this can take a very long time with complex file tree structures***'
' verbosely list every processed file',
required=False)
parser.add_argument('--dryrun', '-d',
action='store_true',
help="don't write any files, just simulate the traversal",
required=False)
config = parser.parse_args(sys.argv[1:])
process_dir(config.top_dir, config)