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 |
| 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() |
