8784: Fix test for latest firefox.
[arvados.git] / sdk / python / arvados / commands / ls.py
1 from __future__ import print_function
2 from __future__ import division
3
4 import argparse
5 import collections
6 import logging
7 import re
8 import sys
9
10 import arvados
11 import arvados.commands._util as arv_cmd
12
13 from arvados._version import __version__
14
15 FileInfo = collections.namedtuple('FileInfo', ['stream_name', 'name', 'size'])
16
17 def parse_args(args):
18     parser = argparse.ArgumentParser(
19         description='List contents of a manifest',
20         parents=[arv_cmd.retry_opt])
21
22     parser.add_argument('locator', type=str,
23                         help="""Collection UUID or locator, optionally with a subdir path.""")
24     parser.add_argument('-s', action='store_true',
25                         help="""List file sizes, in KiB.""")
26     parser.add_argument('--version', action='version',
27                         version="%s %s" % (sys.argv[0], __version__),
28                         help='Print version and exit.')
29
30     return parser.parse_args(args)
31
32 def size_formatter(coll_file):
33     return "{:>10}".format((coll_file.size + 1023) // 1024)
34
35 def name_formatter(coll_file):
36     return "{}/{}".format(coll_file.stream_name, coll_file.name)
37
38 def main(args, stdout, stderr, api_client=None, logger=None):
39     args = parse_args(args)
40
41     if api_client is None:
42         api_client = arvados.api('v1')
43
44     if logger is None:
45         logger = logging.getLogger('arvados.arv-ls')
46
47     try:
48         r = re.search(r'^(.*?)(/.*)?$', args.locator)
49         collection = r.group(1)
50         get_prefix = r.group(2)
51
52         cr = arvados.CollectionReader(collection, api_client=api_client,
53                                       num_retries=args.retries)
54         if get_prefix:
55             if get_prefix[-1] == '/':
56                 get_prefix = get_prefix[:-1]
57             stream_name = '.' + get_prefix
58             reader = cr.find(stream_name)
59             if not (isinstance(reader, arvados.CollectionReader) or
60                     isinstance(reader, arvados.collection.Subcollection)):
61                 logger.error("'{}' is not a subdirectory".format(get_prefix))
62                 return 1
63         else:
64             stream_name = '.'
65             reader = cr
66     except (arvados.errors.ApiError,
67             arvados.errors.ArgumentError,
68             arvados.errors.NotFoundError) as error:
69         logger.error("error fetching collection: {}".format(error))
70         return 1
71
72     formatters = []
73     if args.s:
74         formatters.append(size_formatter)
75     formatters.append(name_formatter)
76
77     for f in files_in_collection(reader, stream_name):
78         print(*(info_func(f) for info_func in formatters), file=stdout)
79
80     return 0
81
82 def files_in_collection(c, stream_name='.'):
83     # Sort first by file type, then alphabetically by file path.
84     for i in sorted(c.keys(),
85                     key=lambda k: (
86                         isinstance(c[k], arvados.collection.Subcollection),
87                         k.upper())):
88         if isinstance(c[i], arvados.arvfile.ArvadosFile):
89             yield FileInfo(stream_name=stream_name,
90                            name=i,
91                            size=c[i].size())
92         elif isinstance(c[i], arvados.collection.Subcollection):
93             for f in files_in_collection(c[i], "{}/{}".format(stream_name, i)):
94                 yield f