1 | """ |
---|
2 | Ported to Python 3. |
---|
3 | """ |
---|
4 | |
---|
5 | from urllib.parse import quote as url_quote |
---|
6 | import json |
---|
7 | from twisted.protocols.basic import LineOnlyReceiver |
---|
8 | from allmydata.util.abbreviate import abbreviate_space_both |
---|
9 | from allmydata.scripts.slow_operation import SlowOperationRunner |
---|
10 | from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \ |
---|
11 | UnknownAliasError |
---|
12 | from allmydata.scripts.common_http import do_http, format_http_error |
---|
13 | from allmydata.util.encodingutil import quote_output, quote_path |
---|
14 | |
---|
15 | class FakeTransport: |
---|
16 | disconnecting = False |
---|
17 | |
---|
18 | class 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 | |
---|
101 | def manifest(options): |
---|
102 | return ManifestStreamer().run(options) |
---|
103 | |
---|
104 | class 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 | |
---|
154 | def stats(options): |
---|
155 | return StatsGrabber().run(options) |
---|