source: trunk/src/allmydata/scripts/tahoe_ls.py

Last change on this file was 1cfe843d, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-22T23:40:25Z

more python2 removal

  • Property mode set to 100644
File size: 6.3 KB
Line 
1"""
2Ported to Python 3.
3"""
4
5from six import ensure_text
6
7import time
8from urllib.parse import quote as url_quote
9import json
10from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
11                                     UnknownAliasError
12from allmydata.scripts.common_http import do_http, format_http_error
13from allmydata.util.encodingutil import unicode_to_output, quote_output, is_printable_ascii, to_bytes
14
15def ls(options):
16    nodeurl = options['node-url']
17    aliases = options.aliases
18    where = options.where
19    stdout = options.stdout
20    stderr = options.stderr
21
22    if not nodeurl.endswith("/"):
23        nodeurl += "/"
24    if where.endswith("/"):
25        where = where[:-1]
26    try:
27        rootcap, path = get_alias(aliases, where, DEFAULT_ALIAS)
28    except UnknownAliasError as e:
29        e.display(stderr)
30        return 1
31
32    path = str(path, "utf-8")
33    url = nodeurl + "uri/%s" % url_quote(rootcap)
34    if path:
35        # move where.endswith check here?
36        url += "/" + escape_path(path)
37    assert not url.endswith("/")
38    url += "?t=json"
39    resp = do_http("GET", url)
40    if resp.status == 404:
41        print("No such file or directory", file=stderr)
42        return 2
43    if resp.status != 200:
44        print(format_http_error("Error during GET", resp), file=stderr)
45        if resp.status == 0:
46            return 3
47        else:
48            return resp.status
49
50    data = resp.read()
51    if options['json']:
52        # The webapi server should always output printable ASCII.
53        if is_printable_ascii(data):
54            data = str(data, "ascii")
55            print(data, file=stdout)
56            return 0
57        else:
58            print("The JSON response contained unprintable characters:", file=stderr)
59            print(quote_output(data, quotemarks=False), file=stderr)
60            return 1
61
62    try:
63        parsed = json.loads(data)
64    except Exception as e:
65        print("error: %s" % quote_output(e.args[0], quotemarks=False), file=stderr)
66        print("Could not parse JSON response:", file=stderr)
67        print(quote_output(data, quotemarks=False), file=stderr)
68        return 1
69
70    nodetype, d = parsed
71    children = {}
72    if nodetype == "dirnode":
73        children = d['children']
74    else:
75        # paths returned from get_alias are always valid UTF-8
76        childname = path.split("/")[-1]
77        children = {childname: (nodetype, d)}
78        if "metadata" not in d:
79            d["metadata"] = {}
80    childnames = sorted(children.keys())
81    now = time.time()
82
83    # we build up a series of rows, then we loop through them to compute a
84    # maxwidth so we can format them tightly. Size, filename, and URI are the
85    # variable-width ones.
86    rows = []
87    has_unknowns = False
88
89    for name in childnames:
90        child = children[name]
91        name = str(name)
92        childtype = child[0]
93
94        # See webapi.txt for a discussion of the meanings of unix local
95        # filesystem mtime and ctime, Tahoe mtime and ctime, and Tahoe
96        # linkmotime and linkcrtime.
97        ctime = child[1].get("metadata", {}).get('tahoe', {}).get("linkcrtime")
98        if not ctime:
99            ctime = child[1]["metadata"].get("ctime")
100
101        mtime = child[1].get("metadata", {}).get('tahoe', {}).get("linkmotime")
102        if not mtime:
103            mtime = child[1]["metadata"].get("mtime")
104        rw_uri = to_bytes(child[1].get("rw_uri"))
105        ro_uri = to_bytes(child[1].get("ro_uri"))
106        if ctime:
107            # match for formatting that GNU 'ls' does
108            if (now - ctime) > 6*30*24*60*60:
109                # old files
110                fmt = "%b %d  %Y"
111            else:
112                fmt = "%b %d %H:%M"
113            ctime_s = time.strftime(fmt, time.localtime(ctime))
114        else:
115            ctime_s = "-"
116        if childtype == "dirnode":
117            t0 = "d"
118            size = "-"
119            classify = "/"
120        elif childtype == "filenode":
121            t0 = "-"
122            size = str(child[1].get("size", "?"))
123            classify = ""
124            if rw_uri:
125                classify = "*"
126        else:
127            has_unknowns = True
128            t0 = "?"
129            size = "?"
130            classify = "?"
131        t1 = "-"
132        if ro_uri:
133            t1 = "r"
134        t2 = "-"
135        if rw_uri:
136            t2 = "w"
137        t3 = "-"
138        if childtype == "dirnode":
139            t3 = "x"
140
141        uri = rw_uri or ro_uri
142
143        line = []
144        if options["long"]:
145            line.append(t0+t1+t2+t3)
146            line.append(size)
147            line.append(ctime_s)
148        if not options["classify"]:
149            classify = ""
150
151        line.append(name + classify)
152
153        if options["uri"]:
154            line.append(ensure_text(uri))
155        if options["readonly-uri"]:
156            line.append(quote_output(ensure_text(ro_uri) or "-", quotemarks=False))
157
158        rows.append(line)
159
160    max_widths = []
161    left_justifys = []
162    for row in rows:
163        for i,cell in enumerate(row):
164            while len(max_widths) <= i:
165                max_widths.append(0)
166            while len(left_justifys) <= i:
167                left_justifys.append(False)
168            max_widths[i] = max(max_widths[i], len(cell))
169            if ensure_text(cell).startswith("URI"):
170                left_justifys[i] = True
171    if len(left_justifys) == 1:
172        left_justifys[0] = True
173    fmt_pieces = []
174    for i in range(len(max_widths)):
175        piece = "%"
176        if left_justifys[i]:
177            piece += "-"
178        piece += str(max_widths[i])
179        piece += "s"
180        fmt_pieces.append(piece)
181    fmt = " ".join(fmt_pieces)
182
183    rc = 0
184    for row in rows:
185        row = (fmt % tuple(row)).rstrip()
186        encoding_error = False
187        try:
188            row = unicode_to_output(row)
189        except UnicodeEncodeError:
190            encoding_error = True
191            row = quote_output(row)
192        if encoding_error:
193            print(row, file=stderr)
194            rc = 1
195        else:
196            print(row, file=stdout)
197
198    if rc == 1:
199        print("\nThis listing included files whose names could not be converted to the terminal" \
200                        "\noutput encoding. Their names are shown using backslash escapes and in quotes.", file=stderr)
201    if has_unknowns:
202        print("\nThis listing included unknown objects. Using a webapi server that supports" \
203                        "\na later version of Tahoe may help.", file=stderr)
204
205    return rc
Note: See TracBrowser for help on using the repository browser.