]> arthur.barton.de Git - bup.git/blob - lib/bup/ls.py
Restore ls -l item sizes, and add initial tests for them.
[bup.git] / lib / bup / ls.py
1 """Common code for listing files from a bup repository."""
2 import copy, stat, xstat
3 from bup import metadata, options, vfs
4 from helpers import *
5
6
7 def node_info(n, name,
8               show_hash = False,
9               long_fmt = False,
10               classification = None,
11               numeric_ids = False,
12               human_readable = False):
13     """Return a string containing the information to display for the node
14     n.  Classification may be "all", "type", or None."""
15     result = ''
16     if show_hash:
17         result += "%s " % n.hash.encode('hex')
18     if long_fmt:
19         meta = copy.copy(n.metadata())
20         if meta:
21             meta.path = name
22             meta.size = n.size()
23         else:
24             # Fake it -- summary_str() is designed to handle a fake.
25             meta = metadata.Metadata()
26             meta.size = n.size()
27             meta.mode = n.mode
28             meta.path = name
29             meta.atime, meta.mtime, meta.ctime = n.atime, n.mtime, n.ctime
30             if stat.S_ISLNK(meta.mode):
31                 meta.symlink_target = n.readlink()
32         result += metadata.summary_str(meta,
33                                        numeric_ids = numeric_ids,
34                                        classification = classification,
35                                        human_readable = human_readable)
36     else:
37         result += name
38         if classification:
39             mode = n.metadata() and n.metadata().mode or n.mode
40             result += xstat.classification_str(mode, classification == 'all')
41     return result
42
43
44 optspec = """
45 %sls [-a] [path...]
46 --
47 s,hash   show hash for each file
48 a,all    show hidden files
49 A,almost-all    show hidden files except . and ..
50 l        use a detailed, long listing format
51 F,classify append type indicator: dir/ sym@ fifo| sock= exec*
52 file-type append type indicator: dir/ sym@ fifo| sock=
53 human-readable    print human readable file sizes (i.e. 3.9K, 4.7M)
54 n,numeric-ids list numeric IDs (user, group, etc.) rather than names
55 """
56
57 def do_ls(args, pwd, default='.', onabort=None, spec_prefix=''):
58     """Output a listing of a file or directory in the bup repository.
59
60     When a long listing is not requested and stdout is attached to a
61     tty, the output is formatted in columns. When not attached to tty
62     (for example when the output is piped to another command), one
63     file is listed per line.
64
65     """
66     if onabort:
67         o = options.Options(optspec % spec_prefix, onabort=onabort)
68     else:
69         o = options.Options(optspec % spec_prefix)
70     (opt, flags, extra) = o.parse(args)
71
72     # Handle order-sensitive options.
73     classification = None
74     show_hidden = None
75     for flag in flags:
76         (option, parameter) = flag
77         if option in ('-F', '--classify'):
78             classification = 'all'
79         elif option == '--file-type':
80             classification = 'type'
81         elif option in ('-a', '--all'):
82             show_hidden = 'all'
83         elif option in ('-A', '--almost-all'):
84             show_hidden = 'almost'
85
86     L = []
87     def output_node_info(node, name):
88         info = node_info(node, name,
89                          show_hash = opt.hash,
90                          long_fmt = opt.l,
91                          classification = classification,
92                          numeric_ids = opt.numeric_ids,
93                          human_readable = opt.human_readable)
94         if not opt.l and istty1:
95             L.append(info)
96         else:
97             print info
98
99     ret = 0
100     for path in (extra or [default]):
101         try:
102             n = pwd.try_resolve(path)
103
104             if stat.S_ISDIR(n.mode):
105                 if show_hidden == 'all':
106                     output_node_info(n, '.')
107                     # Match non-bup "ls -a ... /".
108                     if n.parent:
109                         output_node_info(n.parent, '..')
110                     else:
111                         output_node_info(n, '..')
112                 for sub in n:
113                     name = sub.name
114                     if show_hidden in ('almost', 'all') \
115                        or not len(name)>1 or not name.startswith('.'):
116                         output_node_info(sub, name)
117             else:
118                 output_node_info(n, path)
119         except vfs.NodeError, e:
120             log('error: %s\n' % e)
121             ret = 1
122
123     if L:
124         sys.stdout.write(columnate(L, ''))
125
126     return ret