1 """Common code for listing files from a bup repository."""
3 from __future__ import print_function
4 from itertools import chain
5 from stat import S_ISDIR, S_ISLNK
6 import copy, locale, os.path, stat, sys, xstat
8 from bup import metadata, options, vfs2 as vfs
9 from bup.repo import LocalRepo, RemoteRepo
10 from helpers import columnate, istty1, last, log
12 def item_hash(item, tree_for_commit):
13 """If the item is a Commit, return its commit oid, otherwise return
14 the item's oid, if it has one.
17 if tree_for_commit and isinstance(item, vfs.Commit):
19 return getattr(item, 'oid', None)
21 def item_info(item, name,
25 classification = None,
27 human_readable = False):
28 """Return a string containing the information to display for the VFS
29 item. Classification may be "all", "type", or None.
34 oid = item_hash(item, commit_hash)
35 result += '%s ' % (oid.encode('hex') if oid
36 else '0000000000000000000000000000000000000000')
38 meta = item.meta.copy()
40 # FIXME: need some way to track fake vs real meta items?
41 result += metadata.summary_str(meta,
42 numeric_ids=numeric_ids,
43 classification=classification,
44 human_readable=human_readable)
48 result += xstat.classification_str(vfs.item_mode(item),
49 classification == 'all')
54 %sls [-r host:path] [-l] [-d] [-F] [-a] [-A] [-s] [-n] [path...]
56 r,remote= remote repository path
57 s,hash show hash for each file
58 commit-hash show commit hash instead of tree for commits (implies -s)
59 a,all show hidden files
60 A,almost-all show hidden files except . and ..
61 l use a detailed, long listing format
62 d,directory show directories, not contents; don't follow symlinks
63 F,classify append type indicator: dir/ sym@ fifo| sock= exec*
64 file-type append type indicator: dir/ sym@ fifo| sock=
65 human-readable print human readable file sizes (i.e. 3.9K, 4.7M)
66 n,numeric-ids list numeric IDs (user, group, etc.) rather than names
69 def do_ls(args, default='.', onabort=None, spec_prefix=''):
70 """Output a listing of a file or directory in the bup repository.
72 When a long listing is not requested and stdout is attached to a
73 tty, the output is formatted in columns. When not attached to tty
74 (for example when the output is piped to another command), one
75 file is listed per line.
79 o = options.Options(optspec % spec_prefix, onabort=onabort)
81 o = options.Options(optspec % spec_prefix)
82 (opt, flags, extra) = o.parse(args)
84 # Handle order-sensitive options.
88 (option, parameter) = flag
89 if option in ('-F', '--classify'):
90 classification = 'all'
91 elif option == '--file-type':
92 classification = 'type'
93 elif option in ('-a', '--all'):
95 elif option in ('-A', '--almost-all'):
96 show_hidden = 'almost'
101 def item_line(item, name):
102 return item_info(item, name,
103 show_hash = opt.hash,
104 commit_hash=opt.commit_hash,
106 classification = classification,
107 numeric_ids = opt.numeric_ids,
108 human_readable = opt.human_readable)
110 repo = RemoteRepo(opt.remote) if opt.remote else LocalRepo()
113 for path in (extra or [default]):
116 resolved = vfs.lresolve(repo, path)
118 resolved = vfs.try_resolve(repo, path)
120 leaf_name, leaf_item = resolved[-1]
122 log('error: cannot access %r in %r\n'
123 % ('/'.join(name for name, item in resolved),
127 if not opt.directory and S_ISDIR(vfs.item_mode(leaf_item)):
128 items = vfs.contents(repo, leaf_item)
129 if show_hidden == 'all':
130 # Match non-bup "ls -a ... /".
131 parent = resolved[-2] if len(resolved) > 1 else resolved[0]
132 items = chain(items, (('..', parent[1]),))
133 for sub_name, sub_item in sorted(items, key=lambda x: x[0]):
134 if show_hidden != 'all' and sub_name == '.':
136 if sub_name.startswith('.') and \
137 show_hidden not in ('almost', 'all'):
140 sub_item = vfs.ensure_item_has_metadata(repo, sub_item,
143 sub_item = vfs.augment_item_meta(repo, sub_item,
145 line = item_line(sub_item, sub_name)
146 pending.append(line) if not opt.l and istty1 else print(line)
148 leaf_item = vfs.augment_item_meta(repo, leaf_item,
150 line = item_line(leaf_item, os.path.normpath(path))
151 pending.append(line) if not opt.l and istty1 else print(line)
152 except vfs.IOError as ex:
153 log('bup: %s\n' % ex)
157 sys.stdout.write(columnate(pending, ''))