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