root/livinglogic.python.xist/src/ll/scripts/uls.py @ 3744:590683d9139c

Revision 3744:590683d9139c, 4.9 KB (checked in by Walter Doerwald <walter@…>, 11 years ago)

Stringify urls only once.

Line 
1#!/usr/local/bin/python
2# -*- coding: utf-8 -*-
3
4
5## Copyright 2009 by LivingLogic AG, Bayreuth/Germany.
6## Copyright 2009 by Walter Dörwald
7##
8## All Rights Reserved
9##
10## See ll/__init__.py for the license
11
12
13from __future__ import with_statement
14
15import sys, optparse, contextlib, datetime, pwd, grp, stat, curses
16
17from ll import url
18
19try:
20    import astyle
21except ImportError:
22    from ll import astyle
23
24style_pad = astyle.Style.fromstr("black:black:bold")
25style_sizeunit = astyle.Style.fromstr("yellow:black")
26
27def rpad(s, l):
28    meas = str(s)
29    if not isinstance(s, (basestring, astyle.Text)):
30        s = str(s)
31    if len(meas) < l:
32        return astyle.style_default(s, style_pad("."*(l-len(meas))))
33    return s
34
35def lpad(s, l):
36    meas = str(s)
37    if not isinstance(s, (basestring, astyle.Text)):
38        s = str(s)
39    if len(meas) < l:
40        return astyle.style_default(style_pad("."*(l-len(meas))), s)
41    return s
42
43
44def findcolcount(urls, width, spacing):
45    def width4cols(numcols, spacing):
46        cols = [0]*numcols
47        rows = (len(urls)+numcols-1)//numcols
48        for (i, (u, su)) in enumerate(urls):
49            cols[i//rows] = max(cols[i//rows], len(su))
50        return (sum(cols) + (numcols-1)*spacing, rows, cols)
51
52    numcols = len(urls)
53    while True:
54        (s, rows, cols) = width4cols(numcols, spacing)
55        if s <= width or numcols == 1:
56            return (rows, cols)
57        numcols -=1
58
59
60def main(args=None):
61    uids = {}
62    gids = {}
63    modedata = (
64        (stat.S_IRUSR, "-r"),
65        (stat.S_IWUSR, "-w"),
66        (stat.S_IXUSR, "-x"),
67        (stat.S_IRGRP, "-r"),
68        (stat.S_IWGRP, "-w"),
69        (stat.S_IXGRP, "-x"),
70        (stat.S_IROTH, "-r"),
71        (stat.S_IWOTH, "-w"),
72        (stat.S_IXOTH, "-x"),
73    )
74    sep = style_pad("|")
75    curses.setupterm()
76    width = curses.tigetnum('cols')
77    def printone(url, long, human):
78        if long:
79            stat = url.stat()
80            if stat.st_uid not in uids:
81                user = uids[stat.st_uid] = pwd.getpwuid(stat.st_uid)[0]
82            else:
83                user = uids[stat.st_uid]
84            if stat.st_gid not in gids:
85                group = gids[stat.st_gid] = grp.getgrgid(stat.st_gid)[0]
86            else:
87                group = gids[stat.st_gid]
88            mtime = datetime.datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S")
89            mode = "".join([text[bool(stat.st_mode&bit)] for (bit, text) in modedata])
90            size = stat.st_size
91            if human:
92                s = "BKMGTP"
93                for c in s:
94                    if size < 2048:
95                        if c == "B":
96                            size = str(int(size))
97                        else:
98                            size = astyle.style_default(str(int(size)), style_sizeunit(c))
99                        break
100                    size /= 1024.
101            stdout.write(mode, sep, rpad(user, 8), sep, rpad(group, 8), sep, lpad(size, 5 if human else 12), sep, lpad(stat.st_nlink, 3), sep, mtime, sep)
102        if url.isdir():
103            stdout.writeln(astyle.style_dir(str(url)))
104        else:
105            stdout.writeln(astyle.style_file(str(url)))
106
107    def printblock(urls, width, spacing):
108        urls = [(u, str(u)) for u in urls]
109        (rows, cols) = findcolcount(urls, width, spacing)
110        for i in xrange(rows):
111            for (j, w) in enumerate(cols):
112                index = i+j*rows
113                try:
114                    (u, su) = urls[index]
115                except IndexError:
116                    pass
117                else:
118                    if u.isdir():
119                        su = astyle.style_dir(su)
120                    else:
121                        su = astyle.style_file(su)
122                    if index + rows < len(urls):
123                        su = rpad(su, w+spacing)
124                    stdout.write(su)
125            stdout.writeln()
126
127    def printall(base, url, one, long, recursive, human, spacing):
128        if url.isdir():
129            if url.path.segments[-1][0]:
130                url.path.segments.append(("",))
131            if not long and not one:
132                urls = [(url/child).relative(base) for child in url.listdir()]
133                if urls:
134                    printblock(urls, width, spacing)
135                    if recursive:
136                        for child in url.dirs():
137                            printall(base, url/child, one, long, recursive, human, spacing)
138            else:
139                for child in url.listdir():
140                    printone(url/child, long, human)
141                    if recursive:
142                        printall(base, url/child, one, long, recursive, human, spacing)
143        else:
144            printone(url, long, human)
145
146    colors = ("yes", "no", "auto")
147    p = optparse.OptionParser(usage="usage: %prog [options] [url] [url] ...")
148    p.add_option("-c", "--color", dest="color", help="Color output (%s)" % ", ".join(colors), default="auto", choices=colors)
149    p.add_option("-1", "--one", dest="one", help="One entry per line?", action="store_true")
150    p.add_option("-l", "--long", dest="long", help="Long format?", action="store_true")
151    p.add_option("-s", "--human-readable-sizes", dest="human", help="Output human readable sizes?", action="store_true")
152    p.add_option("-r", "--recursive", dest="recursive", help="Recursive listing?", action="store_true")
153    p.add_option("-w", "--spacing", dest="spacing", help="Spacing between columns", type="int", default=3)
154   
155    (options, args) = p.parse_args(args)
156
157    if options.color == "yes":
158        color = True
159    elif options.color == "no":
160        color = False
161    else:
162        color = None
163    stdout = astyle.Stream(sys.stdout, color)
164    stderr = astyle.Stream(sys.stderr, color)
165
166    if not args:
167        args = ["."]
168
169    with url.Context():
170        for u in args:
171            u = url.URL(u)
172            printall(u, u, options.one, options.long, options.recursive, options.human, options.spacing)
173
174
175if __name__ == "__main__":
176    sys.exit(main())
Note: See TracBrowser for help on using the browser.