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

Last change on this file was 53084f7, checked in by Alexandre Detiste <alexandre.detiste@…>, at 2024-02-27T23:49:07Z

remove more Python2 compatibility

  • Property mode set to 100644
File size: 5.8 KB
Line 
1"""
2Ported to Python 3.
3"""
4
5from urllib.parse import quote as url_quote
6import json
7from twisted.protocols.basic import LineOnlyReceiver
8from allmydata.util.abbreviate import abbreviate_space_both
9from allmydata.scripts.slow_operation import SlowOperationRunner
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 quote_output, quote_path
14
15class FakeTransport(object):
16    disconnecting = False
17
18class ManifestStreamer(LineOnlyReceiver, object):
19    delimiter = b"\n"
20
21    def __init__(self):
22        self.transport = FakeTransport()
23
24    def run(self, options):
25        self.rc = 0
26        stdout = options.stdout
27        stderr = options.stderr
28        self.options = options
29        nodeurl = options['node-url']
30        if not nodeurl.endswith("/"):
31            nodeurl += "/"
32        self.nodeurl = nodeurl
33        where = options.where
34        try:
35            rootcap, path = get_alias(options.aliases, where, DEFAULT_ALIAS)
36        except UnknownAliasError as e:
37            e.display(stderr)
38            return 1
39        path = str(path, "utf-8")
40        if path == '/':
41            path = ''
42        url = nodeurl + "uri/%s" % url_quote(rootcap)
43        if path:
44            url += "/" + escape_path(path)
45        # todo: should it end with a slash?
46        url += "?t=stream-manifest"
47        resp = do_http("POST", url)
48        if resp.status not in (200, 302):
49            print(format_http_error("ERROR", resp), file=stderr)
50            return 1
51        #print("RESP", dir(resp))
52        # use Twisted to split this into lines
53        self.in_error = False
54        # Writing bytes, so need binary stdout.
55        stdout = stdout.buffer
56        while True:
57            chunk = resp.read(100)
58            if not chunk:
59                break
60            if self.options["raw"]:
61                stdout.write(chunk)
62            else:
63                self.dataReceived(chunk)
64        return self.rc
65
66    def lineReceived(self, line):
67        stdout = self.options.stdout
68        stderr = self.options.stderr
69        if self.in_error:
70            print(quote_output(line, quotemarks=False), file=stderr)
71            return
72        if line.startswith(b"ERROR:"):
73            self.in_error = True
74            self.rc = 1
75            print(quote_output(line, quotemarks=False), file=stderr)
76            return
77
78        try:
79            d = json.loads(line.decode('utf-8'))
80        except Exception as e:
81            print("ERROR could not decode/parse %s\nERROR  %r" % (quote_output(line), e), file=stderr)
82        else:
83            if d["type"] in ("file", "directory"):
84                if self.options["storage-index"]:
85                    si = d.get("storage-index", None)
86                    if si:
87                        print(quote_output(si, quotemarks=False), file=stdout)
88                elif self.options["verify-cap"]:
89                    vc = d.get("verifycap", None)
90                    if vc:
91                        print(quote_output(vc, quotemarks=False), file=stdout)
92                elif self.options["repair-cap"]:
93                    vc = d.get("repaircap", None)
94                    if vc:
95                        print(quote_output(vc, quotemarks=False), file=stdout)
96                else:
97                    print("%s %s" % (
98                        quote_output(d["cap"], quotemarks=False),
99                        quote_path(d["path"], quotemarks=False)), file=stdout)
100
101def manifest(options):
102    return ManifestStreamer().run(options)
103
104class StatsGrabber(SlowOperationRunner):
105
106    def make_url(self, base, ophandle):
107        return base + "?t=start-deep-stats&ophandle=" + ophandle
108
109    def write_results(self, data):
110        stdout = self.options.stdout
111        keys = ("count-immutable-files",
112                "count-mutable-files",
113                "count-literal-files",
114                "count-files",
115                "count-directories",
116                "size-immutable-files",
117                "size-mutable-files",
118                "size-literal-files",
119                "size-directories",
120                "largest-directory",
121                "largest-immutable-file",
122                )
123        width = max([len(k) for k in keys])
124        print("Counts and Total Sizes:", file=stdout)
125        for k in keys:
126            fmt = "%" + str(width) + "s: %d"
127            if k in data:
128                value = data[k]
129                if not k.startswith("count-") and value > 1000:
130                    absize = abbreviate_space_both(value)
131                    print(fmt % (k, data[k]), "  ", absize, file=stdout)
132                else:
133                    print(fmt % (k, data[k]), file=stdout)
134        if data["size-files-histogram"]:
135            print("Size Histogram:", file=stdout)
136            prevmax = None
137            maxlen = max([len(str(maxsize))
138                          for (minsize, maxsize, count)
139                          in data["size-files-histogram"]])
140            maxcountlen = max([len(str(count))
141                               for (minsize, maxsize, count)
142                               in data["size-files-histogram"]])
143            minfmt = "%" + str(maxlen) + "d"
144            maxfmt = "%-" + str(maxlen) + "d"
145            countfmt = "%-" + str(maxcountlen) + "d"
146            linefmt = minfmt + "-" + maxfmt + " : " + countfmt + "    %s"
147            for (minsize, maxsize, count) in data["size-files-histogram"]:
148                if prevmax is not None and minsize != prevmax+1:
149                    print(" "*(maxlen-1) + "...", file=stdout)
150                prevmax = maxsize
151                print(linefmt % (minsize, maxsize, count,
152                                           abbreviate_space_both(maxsize)), file=stdout)
153
154def stats(options):
155    return StatsGrabber().run(options)
Note: See TracBrowser for help on using the repository browser.