2 import urllib, simplejson
3 from twisted.protocols.basic import LineOnlyReceiver
4 from allmydata.util.abbreviate import abbreviate_space_both
5 from allmydata.scripts.slow_operation import SlowOperationRunner
6 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
8 from allmydata.scripts.common_http import do_http, format_http_error
9 from allmydata.util.encodingutil import quote_output, quote_path
14 class ManifestStreamer(LineOnlyReceiver):
18 self.transport = FakeTransport()
20 def run(self, options):
22 stdout = options.stdout
23 stderr = options.stderr
24 self.options = options
25 nodeurl = options['node-url']
26 if not nodeurl.endswith("/"):
28 self.nodeurl = nodeurl
31 rootcap, path = get_alias(options.aliases, where, DEFAULT_ALIAS)
32 except UnknownAliasError, e:
37 url = nodeurl + "uri/%s" % urllib.quote(rootcap)
39 url += "/" + escape_path(path)
40 # todo: should it end with a slash?
41 url += "?t=stream-manifest"
42 resp = do_http("POST", url)
43 if resp.status not in (200, 302):
44 print >>stderr, format_http_error("ERROR", resp)
46 #print "RESP", dir(resp)
47 # use Twisted to split this into lines
50 chunk = resp.read(100)
53 if self.options["raw"]:
56 self.dataReceived(chunk)
59 def lineReceived(self, line):
60 stdout = self.options.stdout
61 stderr = self.options.stderr
63 print >>stderr, quote_output(line, quotemarks=False)
65 if line.startswith("ERROR:"):
68 print >>stderr, quote_output(line, quotemarks=False)
72 d = simplejson.loads(line.decode('utf-8'))
74 print >>stderr, "ERROR could not decode/parse %s\nERROR %r" % (quote_output(line), e)
76 if d["type"] in ("file", "directory"):
77 if self.options["storage-index"]:
78 si = d.get("storage-index", None)
80 print >>stdout, quote_output(si, quotemarks=False)
81 elif self.options["verify-cap"]:
82 vc = d.get("verifycap", None)
84 print >>stdout, quote_output(vc, quotemarks=False)
85 elif self.options["repair-cap"]:
86 vc = d.get("repaircap", None)
88 print >>stdout, quote_output(vc, quotemarks=False)
90 print >>stdout, "%s %s" % (quote_output(d["cap"], quotemarks=False),
91 quote_path(d["path"], quotemarks=False))
93 def manifest(options):
94 return ManifestStreamer().run(options)
96 class StatsGrabber(SlowOperationRunner):
98 def make_url(self, base, ophandle):
99 return base + "?t=start-deep-stats&ophandle=" + ophandle
101 def write_results(self, data):
102 stdout = self.options.stdout
103 keys = ("count-immutable-files",
104 "count-mutable-files",
105 "count-literal-files",
108 "size-immutable-files",
109 "size-mutable-files",
110 "size-literal-files",
113 "largest-immutable-file",
115 width = max([len(k) for k in keys])
116 print >>stdout, "Counts and Total Sizes:"
118 fmt = "%" + str(width) + "s: %d"
121 if not k.startswith("count-") and value > 1000:
122 absize = abbreviate_space_both(value)
123 print >>stdout, fmt % (k, data[k]), " ", absize
125 print >>stdout, fmt % (k, data[k])
126 if data["size-files-histogram"]:
127 print >>stdout, "Size Histogram:"
129 maxlen = max([len(str(maxsize))
130 for (minsize, maxsize, count)
131 in data["size-files-histogram"]])
132 maxcountlen = max([len(str(count))
133 for (minsize, maxsize, count)
134 in data["size-files-histogram"]])
135 minfmt = "%" + str(maxlen) + "d"
136 maxfmt = "%-" + str(maxlen) + "d"
137 countfmt = "%-" + str(maxcountlen) + "d"
138 linefmt = minfmt + "-" + maxfmt + " : " + countfmt + " %s"
139 for (minsize, maxsize, count) in data["size-files-histogram"]:
140 if prevmax is not None and minsize != prevmax+1:
141 print >>stdout, " "*(maxlen-1) + "..."
143 print >>stdout, linefmt % (minsize, maxsize, count,
144 abbreviate_space_both(maxsize))
147 return StatsGrabber().run(options)