Mercurial > hg > config
comparison python/tree.py @ 391:cccfe246452e
rename
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Sat, 27 Jul 2013 20:33:53 -0700 (2013-07-28) |
parents | python/tree2.py@9d02187611ae |
children | 5417eb6364ee |
comparison
equal
deleted
inserted
replaced
390:9d02187611ae | 391:cccfe246452e |
---|---|
7 | 7 |
8 import optparse | 8 import optparse |
9 import os | 9 import os |
10 import sys | 10 import sys |
11 | 11 |
12 here = os.path.dirname(os.path.realpath(__file__)) | 12 # ASCII delimeters |
13 ascii_delimeters = { | |
14 'vertical_line' : '|', | |
15 'item_marker' : '+', | |
16 'last_child' : '\\' | |
17 } | |
18 | |
19 # unicode delimiters | |
20 unicode_delimeters = { | |
21 'vertical_line' : '│', | |
22 'item_marker' : '├', | |
23 'last_child' : '└' | |
24 } | |
13 | 25 |
14 def depth(directory): | 26 def depth(directory): |
27 """returns the integer depth of a directory or path relative to '/' """ | |
28 | |
15 directory = os.path.abspath(directory) | 29 directory = os.path.abspath(directory) |
16 level = 0 | 30 level = 0 |
17 while True: | 31 while True: |
18 directory, remainder = os.path.split(directory) | 32 directory, remainder = os.path.split(directory) |
19 level += 1 | 33 level += 1 |
20 if not remainder: | 34 if not remainder: |
21 break | 35 break |
22 return level | 36 return level |
23 | 37 |
24 def tree(directory): | 38 def tree(directory, |
39 item_marker=unicode_delimeters['item_marker'], | |
40 vertical_line=unicode_delimeters['vertical_line'], | |
41 last_child=unicode_delimeters['last_child'], | |
42 sort_key=lambda x: x.lower()): | |
43 """ | |
44 display tree directory structure for `directory` | |
45 """ | |
46 | |
25 retval = [] | 47 retval = [] |
26 level = depth(directory) | 48 indent = [] |
27 pre = [] | |
28 directories = {} | |
29 lvlndctr = [] | |
30 last = {} | 49 last = {} |
31 passed_last = {} | 50 top = depth(directory) |
32 columns = [] | 51 |
33 lastdepth = depth | |
34 indent = 0 | |
35 for dirpath, dirnames, filenames in os.walk(directory, topdown=True): | 52 for dirpath, dirnames, filenames in os.walk(directory, topdown=True): |
36 basename = os.path.basename(dirpath) | |
37 parent = os.path.abspath(os.path.dirname(dirpath)) | |
38 indent = depth(dirpath) - level | |
39 dirnames[:] = sorted(dirnames, key=lambda x: x.lower()) | |
40 last[os.path.abspath(dirpath)] = dirnames and dirnames[-1] or None | |
41 directories[dirpath] = dirnames | |
42 | 53 |
43 retval.append('%s%s%s' % ('│' * (indent-1), | 54 abspath = os.path.abspath(dirpath) |
44 ('├' if basename == basename else '└') if indent else '', | 55 basename = os.path.basename(abspath) |
45 basename)) | 56 parent = os.path.dirname(abspath) |
46 filenames = sorted(filenames, key=lambda x: x.lower()) | 57 level = depth(abspath) - top |
47 retval.extend(['%s%s%s' % ('│' * (indent), | 58 |
48 '├' if (((index < len(filenames) -1)) or dirnames) else '└', | 59 # sort articles of interest |
49 name) | 60 for resource in (dirnames, filenames): |
50 for index, name in | 61 resource[:] = sorted(resource, key=sort_key) |
51 enumerate(filenames) | 62 |
52 ]) | 63 files_end = item_marker |
64 dirpath_marker = item_marker | |
65 | |
66 if level > len(indent): | |
67 indent.append(vertical_line) | |
68 indent = indent[:level] | |
69 | |
70 if dirnames: | |
71 files_end = item_marker | |
72 last[abspath] = dirnames[-1] | |
73 else: | |
74 files_end = last_child | |
75 | |
76 if last.get(parent) == os.path.basename(abspath): | |
77 # last directory of parent | |
78 dirpath_mark = last_child | |
79 indent[-1] = ' ' | |
80 elif not indent: | |
81 dirpath_mark = '' | |
82 else: | |
83 dirpath_mark = item_marker | |
84 | |
85 # append the directory and piece of tree structure | |
86 # if the top-level entry directory, print as passed | |
87 retval.append('%s%s%s'% (''.join(indent[:-1]), | |
88 dirpath_mark, | |
89 basename if retval else directory)) | |
90 # add the files | |
91 if filenames: | |
92 last_file = filenames[-1] | |
93 retval.extend([('%s%s%s' % (''.join(indent), | |
94 files_end if filename == last_file else item_marker, | |
95 filename)) | |
96 for index, filename in enumerate(filenames)]) | |
97 | |
53 return '\n'.join(retval) | 98 return '\n'.join(retval) |
54 | 99 |
55 def main(args=sys.argv[1:]): | 100 def main(args=sys.argv[1:]): |
56 | 101 |
102 # parse command line options | |
57 usage = '%prog [options]' | 103 usage = '%prog [options]' |
58 parser = optparse.OptionParser(usage=usage, description=__doc__) | 104 parser = optparse.OptionParser(usage=usage, description=__doc__) |
105 parser.add_option('-a', '--ascii', dest='use_ascii', | |
106 action='store_true', default=False, | |
107 help="use ascii delimeters (%s)" % ascii_delimeters) | |
59 options, args = parser.parse_args(args) | 108 options, args = parser.parse_args(args) |
60 if not args: | 109 if not args: |
61 args = ['.'] | 110 args = ['.'] |
62 | 111 |
112 # sanity check | |
63 not_directory = [arg for arg in args | 113 not_directory = [arg for arg in args |
64 if not os.path.isdir(arg)] | 114 if not os.path.isdir(arg)] |
65 if not_directory: | 115 if not_directory: |
66 parser.error("Not a directory: %s" % (', '.join(not_directory))) | 116 parser.error("Not a directory: %s" % (', '.join(not_directory))) |
67 | 117 |
118 delimeters = unicode_delimeters | |
119 if options.use_ascii: | |
120 delimeters = ascii_delimeters | |
121 | |
122 # print the tree | |
68 for arg in args: | 123 for arg in args: |
69 print (tree(arg)) | 124 print (tree(arg, **delimeters)) |
70 | 125 |
71 if __name__ == '__main__': | 126 if __name__ == '__main__': |
72 main() | 127 main() |