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