Updated `tree' program
François Pinard
pinard at iro.umontreal.ca
Sun Jul 9 10:38:21 EDT 2000
Hi, gang!
I updated my `tree' program (a `du' displayer) once again, and thought
that some might like that I share it with you. I was not satisfied with
all directory sizes being given in a single column, making difficult to
visually sort them out. So I tried two things. The `-m' option is surely
fun, but maybe not that useful for deep hierarchies, so I did not make it
the default. The old behaviour is available with the `-p' option.
-------------- next part --------------
#!/usr/bin/env python
# Produce directory hierarchy with sizes, well sorted and indented.
# Copyright ? 1996, 1999, 2000 Progiciels Bourbeau-Pinard inc.
# Fran?ois Pinard <pinard at iro.umontreal.ca>, 1996.
# Idea from Pierre Rioux <riouxp at bch.umontreal.ca>, 1996-07-12.
"""\
Produce directory hierarchy with sizes, well sorted and indented.
Usage: tree [OPTION]... PATH...
-p display sizes vertically within a single prefix column
-m if not -p, mirror the structure while displaying sizes
-b within a directory, show biggest hierarchies first
-l LEVEL disregard directories more than LEVEL levels deep
-s SIZE disregard hierarchies smaller than SIZE Kb
By default, sizes are printed before the name, and sort is lexicographical.
Use `.' to list the current directory.
"""
import getopt, os, string, sys
class run:
biggest = 0
mirror = 0
prefix = 0
level = None
size = None
def main(*arguments):
if not arguments:
sys.stdout.write(__doc__)
sys.exit(0)
# Decode options.
options, arguments = getopt.getopt(arguments, 'bl:mps:')
for option, value in options:
if option == '-b':
run.biggest = 1
elif option == '-l':
run.level = int(value)
elif option == '-m':
run.mirror = 1
elif option == '-p':
run.prefix = 1
elif option == '-s':
run.size = int(value)
# Get the data, properly filtered.
pairs = []
for line in os.popen('du %s' % string.join(arguments)).readlines():
text, path = string.split(line, '\t')
size = int(text)
if run.size is None or size >= run.size:
split = string.split(path[:-1], '/')
if run.level is None or len(split) <= run.level:
pairs.append([split, size])
# Sort the information as wanted.
if run.biggest:
value = {}
for split, size in pairs:
value[tuple(split)] = -size
items = []
for split, size in pairs:
item = []
for counter in range(len(split)):
item.append((value[tuple(split[:counter+1])], split[counter]))
items.append(item)
items.sort()
pairs = []
for item in items:
split = map(lambda((size, fragment)): fragment, item)
size = -item[-1][0]
pairs.append([split, size])
else:
pairs.sort()
# Erase unneeded fragments of vertical lines.
clean(pairs)
pairs.reverse()
clean(pairs)
pairs.reverse()
# Erase leftmost white columns.
skip = 0
split, size = pairs[0]
while not split[skip]:
skip = skip + 1
# Format size information.
margin_size = 0
for pair in pairs:
split, size = pair
if run.prefix:
pair[1] = '%d ' % size
elif run.mirror:
margin = '%d _/' % size
items = split[skip:-1]
items.reverse()
for item in items:
if item:
margin = margin + ' |'
else:
margin = margin + ' '
pair[1] = margin
else:
split[-1] = '%d %s' % (size, split[-1])
pair[1] = ''
margin_size = max(margin_size, len(pair[1]))
# Produce resulting display.
write = sys.stdout.write
for split, margin in pairs:
write(' ' * (margin_size - len(margin)))
write(margin)
for item in split[skip:-1]:
if item:
write('| ')
else:
write(' ')
write('\\_ %s\n' % split[-1])
def clean(pairs):
# The basename is always written. Intermediate directories normally
# print as `|', yet None is used to inhibit the vertical line.
draw = []
for split, size in pairs:
while len(draw) > len(split) - 1:
del draw[-1]
while len(draw) < len(split) - 1:
draw.append(0)
draw.append(1)
for counter in range(len(split) - 1):
if not draw[counter]:
split[counter] = None
if __name__ == '__main__':
apply(main, tuple(sys.argv[1:]))
-------------- next part --------------
--
Fran?ois Pinard http://www.iro.umontreal.ca/~pinard
More information about the Python-list
mailing list