Skip to content

Commit

Permalink
accept and process a list of dirs. process is a success if one or mor…
Browse files Browse the repository at this point in the history
…e dir returns a valid value
  • Loading branch information
jbaeth committed Jul 6, 2020
1 parent ffd24b9 commit c3904c8
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 182 deletions.
5 changes: 3 additions & 2 deletions src/allmydata/scripts/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ class ListOptions(FileStoreOptions):
("classify", "F", "Append '/' to directory names, and '*' to mutable."),
("json", None, "Show the raw JSON output."),
]
def parseArgs(self, where=""):
self.where = argv_to_unicode(where)

def parseArgs(self, *where):
self.where = [argv_to_unicode(directory) for directory in where]

synopsis = "[options] [PATH]"

Expand Down
357 changes: 186 additions & 171 deletions src/allmydata/scripts/tahoe_ls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,184 +13,199 @@ def list(options):
where = options.where
stdout = options.stdout
stderr = options.stderr

if not nodeurl.endswith("/"):
nodeurl += "/"
if where.endswith("/"):
where = where[:-1]
try:
rootcap, path = get_alias(aliases, where, DEFAULT_ALIAS)
except UnknownAliasError as e:
e.display(stderr)
return 1
url = nodeurl + "uri/%s" % urllib.quote(rootcap)
if path:
# move where.endswith check here?
url += "/" + escape_path(path)
assert not url.endswith("/")
url += "?t=json"
resp = do_http("GET", url)
if resp.status == 404:
print("No such file or directory", file=stderr)
return 2
if resp.status != 200:
print(format_http_error("Error during GET", resp), file=stderr)
if resp.status == 0:
return 3
else:
return resp.status

data = resp.read()

if options['json']:
# The webapi server should always output printable ASCII.
if is_printable_ascii(data):
print(data, file=stdout)
return 0
else:
print("The JSON response contained unprintable characters:", file=stderr)
print(quote_output(data, quotemarks=False), file=stderr)


def list_dir(directory):
rc = 0
if directory.endswith("/"):
directory = directory[:-1]

try:
rootcap, path = \
get_alias(aliases, directory, DEFAULT_ALIAS)
except UnknownAliasError as e:
e.display(stderr)
return 1
url = nodeurl + "uri/%s" % urllib.quote(rootcap)
if path:
# move where.endswith check here?
url += "/" + escape_path(path)
assert not url.endswith("/")
url += "?t=json"
resp = do_http("GET", url)
if resp.status == 404:
print("%s: No such file or directory" % directory, file=stderr)
return 2

if resp.status != 200:
print(format_http_error("Error during GET", resp), file=stderr)
if resp.status == 0:
return 3
else:
return resp.status

try:
parsed = json.loads(data)
except Exception as e:
print("error: %s" % quote_output(e.args[0], quotemarks=False), file=stderr)
print("Could not parse JSON response:", file=stderr)
print(quote_output(data, quotemarks=False), file=stderr)
return 1

nodetype, d = parsed
children = {}
if nodetype == "dirnode":
children = d['children']
else:
# paths returned from get_alias are always valid UTF-8
childname = path.split("/")[-1].decode('utf-8')
children = {childname: (nodetype, d)}
if "metadata" not in d:
d["metadata"] = {}
childnames = sorted(children.keys())
now = time.time()

# we build up a series of rows, then we loop through them to compute a
# maxwidth so we can format them tightly. Size, filename, and URI are the
# variable-width ones.
rows = []
has_unknowns = False

for name in childnames:
child = children[name]
name = unicode(name)
childtype = child[0]

# See webapi.txt for a discussion of the meanings of unix local
# filesystem mtime and ctime, Tahoe mtime and ctime, and Tahoe
# linkmotime and linkcrtime.
ctime = child[1].get("metadata", {}).get('tahoe', {}).get("linkcrtime")
if not ctime:
ctime = child[1]["metadata"].get("ctime")

mtime = child[1].get("metadata", {}).get('tahoe', {}).get("linkmotime")
if not mtime:
mtime = child[1]["metadata"].get("mtime")
rw_uri = to_str(child[1].get("rw_uri"))
ro_uri = to_str(child[1].get("ro_uri"))
if ctime:
# match for formatting that GNU 'ls' does
if (now - ctime) > 6*30*24*60*60:
# old files
fmt = "%b %d %Y"
data = resp.read()

if options['json']:
# The webapi server should always output printable ASCII.
if is_printable_ascii(data):
print(data, file=stdout)
return 0
else:
fmt = "%b %d %H:%M"
ctime_s = time.strftime(fmt, time.localtime(ctime))
else:
ctime_s = "-"
if childtype == "dirnode":
t0 = "d"
size = "-"
classify = "/"
elif childtype == "filenode":
t0 = "-"
size = str(child[1].get("size", "?"))
classify = ""
if rw_uri:
classify = "*"
else:
has_unknowns = True
t0 = "?"
size = "?"
classify = "?"
t1 = "-"
if ro_uri:
t1 = "r"
t2 = "-"
if rw_uri:
t2 = "w"
t3 = "-"
if childtype == "dirnode":
t3 = "x"

uri = rw_uri or ro_uri

line = []
if options["long"]:
line.append(t0+t1+t2+t3)
line.append(size)
line.append(ctime_s)
if not options["classify"]:
classify = ""

encoding_error = False
print("The JSON response contained unprintable characters:", file=stderr)
print(quote_output(data, quotemarks=False), file=stderr)
return 1

try:
line.append(unicode_to_output(name) + classify)
except UnicodeEncodeError:
encoding_error = True
line.append(quote_output(name) + classify)

if options["uri"]:
line.append(uri)
if options["readonly-uri"]:
line.append(quote_output(ro_uri or "-", quotemarks=False))

rows.append((encoding_error, line))

max_widths = []
left_justifys = []
for (encoding_error, row) in rows:
for i,cell in enumerate(row):
while len(max_widths) <= i:
max_widths.append(0)
while len(left_justifys) <= i:
left_justifys.append(False)
max_widths[i] = max(max_widths[i], len(cell))
if cell.startswith("URI"):
left_justifys[i] = True
if len(left_justifys) == 1:
left_justifys[0] = True
fmt_pieces = []
for i in range(len(max_widths)):
piece = "%"
if left_justifys[i]:
piece += "-"
piece += str(max_widths[i])
piece += "s"
fmt_pieces.append(piece)
fmt = " ".join(fmt_pieces)

rc = 0
for (encoding_error, row) in rows:
if encoding_error:
print((fmt % tuple(row)).rstrip(), file=stderr)
rc = 1
else:
print((fmt % tuple(row)).rstrip(), file=stdout)
parsed = json.loads(data)
except Exception as e:
print("error: %s" % quote_output(e.args[0], quotemarks=False), file=stderr)
print("Could not parse JSON response:", file=stderr)
print(quote_output(data, quotemarks=False), file=stderr)
return 1

if rc == 1:
print("\nThis listing included files whose names could not be converted to the terminal" \
"\noutput encoding. Their names are shown using backslash escapes and in quotes.", file=stderr)
if has_unknowns:
print("\nThis listing included unknown objects. Using a webapi server that supports" \
"\na later version of Tahoe may help.", file=stderr)
nodetype, d = parsed
children = {}
if nodetype == "dirnode":
children = d['children']
else:
# paths returned from get_alias are always valid UTF-8
childname = path.split("/")[-1].decode('utf-8')
children = {childname: (nodetype, d)}
if "metadata" not in d:
d["metadata"] = {}
childnames = sorted(children.keys())
now = time.time()

# we build up a series of rows, then we loop through them to compute a
# maxwidth so we can format them tightly. Size, filename, and URI are the
# variable-width ones.
rows = []
has_unknowns = False

for name in childnames:
child = children[name]
name = unicode(name)
childtype = child[0]

# See webapi.txt for a discussion of the meanings of unix local
# filesystem mtime and ctime, Tahoe mtime and ctime, and Tahoe
# linkmotime and linkcrtime.
ctime = child[1].get("metadata", {}).get('tahoe', {}).get("linkcrtime")
if not ctime:
ctime = child[1]["metadata"].get("ctime")

mtime = child[1].get("metadata", {}).get('tahoe', {}).get("linkmotime")
if not mtime:
mtime = child[1]["metadata"].get("mtime")
rw_uri = to_str(child[1].get("rw_uri"))
ro_uri = to_str(child[1].get("ro_uri"))
if ctime:
# match for formatting that GNU 'ls' does
if (now - ctime) > 6 * 30 * 24 * 60 * 60:
# old files
fmt = "%b %d %Y"
else:
fmt = "%b %d %H:%M"
ctime_s = time.strftime(fmt, time.localtime(ctime))
else:
ctime_s = "-"
if childtype == "dirnode":
t0 = "d"
size = "-"
classify = "/"
elif childtype == "filenode":
t0 = "-"
size = str(child[1].get("size", "?"))
classify = ""
if rw_uri:
classify = "*"
else:
has_unknowns = True
t0 = "?"
size = "?"
classify = "?"
t1 = "-"
if ro_uri:
t1 = "r"
t2 = "-"
if rw_uri:
t2 = "w"
t3 = "-"
if childtype == "dirnode":
t3 = "x"

uri = rw_uri or ro_uri

line = []
if options["long"]:
line.append(t0 + t1 + t2 + t3)
line.append(size)
line.append(ctime_s)
if not options["classify"]:
classify = ""

encoding_error = False
try:
line.append(unicode_to_output(name) + classify)
except UnicodeEncodeError:
encoding_error = True
line.append(quote_output(name) + classify)

if options["uri"]:
line.append(uri)
if options["readonly-uri"]:
line.append(quote_output(ro_uri or "-", quotemarks=False))

rows.append((encoding_error, line))

max_widths = []
left_justifys = []
for (encoding_error, row) in rows:
for i, cell in enumerate(row):
while len(max_widths) <= i:
max_widths.append(0)
while len(left_justifys) <= i:
left_justifys.append(False)
max_widths[i] = max(max_widths[i], len(cell))
if cell.startswith("URI"):
left_justifys[i] = True
if len(left_justifys) == 1:
left_justifys[0] = True
fmt_pieces = []
for i in range(len(max_widths)):
piece = "%"
if left_justifys[i]:
piece += "-"
piece += str(max_widths[i])
piece += "s"
fmt_pieces.append(piece)
fmt = " ".join(fmt_pieces)

for (encoding_error, row) in rows:
if encoding_error:
print((fmt % tuple(row)).rstrip(), file=stderr)
rc = 1
else:
print((fmt % tuple(row)).rstrip(), file=stdout)

if rc == 1:
print("\nThis listing included files whose names could not be converted to the terminal" \
"\noutput encoding. Their names are shown using backslash escapes and in quotes.", file=stderr)
if has_unknowns:
print("\nThis listing included unknown objects. Using a webapi server that supports" \
"\na later version of Tahoe may help.", file=stderr)
return rc

rc = []
if not where:
rc.append(list_dir(u''))
else:
for directory in where:
rc.append(list_dir(directory))
return min(rc)

return rc
Loading

0 comments on commit c3904c8

Please sign in to comment.