]> arthur.barton.de Git - bup.git/blob - lib/bup/ls.py
df299e58787b040f930a8938d65cbb6c4ad5bbf4
[bup.git] / lib / bup / ls.py
1 """Common code for listing files from a bup repository."""
2 import copy, os.path, 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 d,directory show directories, not contents; don't follow symlinks
52 F,classify append type indicator: dir/ sym@ fifo| sock= exec*
53 file-type append type indicator: dir/ sym@ fifo| sock=
54 human-readable    print human readable file sizes (i.e. 3.9K, 4.7M)
55 n,numeric-ids list numeric IDs (user, group, etc.) rather than names
56 """
57
58 def do_ls(args, pwd, default='.', onabort=None, spec_prefix=''):
59     """Output a listing of a file or directory in the bup repository.
60
61     When a long listing is not requested and stdout is attached to a
62     tty, the output is formatted in columns. When not attached to tty
63     (for example when the output is piped to another command), one
64     file is listed per line.
65
66     """
67     if onabort:
68         o = options.Options(optspec % spec_prefix, onabort=onabort)
69     else:
70         o = options.Options(optspec % spec_prefix)
71     (opt, flags, extra) = o.parse(args)
72
73     # Handle order-sensitive options.
74     classification = None
75     show_hidden = None
76     for flag in flags:
77         (option, parameter) = flag
78         if option in ('-F', '--classify'):
79             classification = 'all'
80         elif option == '--file-type':
81             classification = 'type'
82         elif option in ('-a', '--all'):
83             show_hidden = 'all'
84         elif option in ('-A', '--almost-all'):
85             show_hidden = 'almost'
86
87     L = []
88     def output_node_info(node, name):
89         info = node_info(node, name,
90                          show_hash = opt.hash,
91                          long_fmt = opt.l,
92                          classification = classification,
93                          numeric_ids = opt.numeric_ids,
94                          human_readable = opt.human_readable)
95         if not opt.l and istty1:
96             L.append(info)
97         else:
98             print info
99
100     ret = 0
101     for path in (extra or [default]):
102         try:
103             if opt.directory:
104                 n = pwd.lresolve(path)
105             else:
106                 n = pwd.try_resolve(path)
107
108             if not opt.directory and stat.S_ISDIR(n.mode):
109                 if show_hidden == 'all':
110                     output_node_info(n, '.')
111                     # Match non-bup "ls -a ... /".
112                     if n.parent:
113                         output_node_info(n.parent, '..')
114                     else:
115                         output_node_info(n, '..')
116                 for sub in n:
117                     name = sub.name
118                     if show_hidden in ('almost', 'all') \
119                        or not len(name)>1 or not name.startswith('.'):
120                         output_node_info(sub, name)
121             else:
122                 output_node_info(n, os.path.normpath(path))
123         except vfs.NodeError as e:
124             log('error: %s\n' % e)
125             ret = 1
126
127     if L:
128         sys.stdout.write(columnate(L, ''))
129
130     return ret