"""Common code for listing files from a bup repository."""
-from __future__ import print_function
+from __future__ import absolute_import
+from binascii import hexlify
from itertools import chain
-from stat import S_ISDIR, S_ISLNK
-import copy, locale, os.path, stat, sys, xstat
+from stat import S_ISDIR
+import os.path
+import posixpath
-from bup import metadata, options, vfs2 as vfs
+from bup import metadata, vfs, xstat
+from bup.compat import argv_bytes
+from bup.io import path_msg
from bup.options import Options
from bup.repo import LocalRepo, RemoteRepo
-from helpers import columnate, istty1, last, log
+from bup.helpers import columnate, istty1, log
def item_hash(item, tree_for_commit):
"""If the item is a Commit, return its commit oid, otherwise return
classification = None,
numeric_ids = False,
human_readable = False):
- """Return a string containing the information to display for the VFS
+ """Return bytes containing the information to display for the VFS
item. Classification may be "all", "type", or None.
"""
- result = ''
+ result = b''
if show_hash:
oid = item_hash(item, commit_hash)
- result += '%s ' % (oid.encode('hex') if oid
- else '0000000000000000000000000000000000000000')
+ result += b'%s ' % (hexlify(oid) if oid
+ else b'0000000000000000000000000000000000000000')
if long_fmt:
meta = item.meta.copy()
meta.path = name
# FIXME: need some way to track fake vs real meta items?
- result += metadata.summary_str(meta,
- numeric_ids=numeric_ids,
- classification=classification,
- human_readable=human_readable)
+ result += metadata.summary_bytes(meta,
+ numeric_ids=numeric_ids,
+ classification=classification,
+ human_readable=human_readable)
else:
result += name
if classification:
- result += xstat.classification_str(vfs.item_mode(item),
- classification == 'all')
+ cls = xstat.classification_str(vfs.item_mode(item),
+ classification == 'all')
+ result += cls.encode('ascii')
return result
n,numeric-ids list numeric IDs (user, group, etc.) rather than names
"""
-def opts_from_cmdline(args, onabort=None):
+def opts_from_cmdline(args, onabort=None, pwd=b'/'):
"""Parse ls command line arguments and return a dictionary of ls
options, agumented with "classification", "long_listing",
"paths", and "show_hidden".
"""
if onabort:
- opt, flags, extra = Options(optspec, onabort=onabort).parse(args)
+ opt, flags, extra = Options(optspec, onabort=onabort).parse_bytes(args)
else:
- opt, flags, extra = Options(optspec).parse(args)
+ opt, flags, extra = Options(optspec).parse_bytes(args)
- opt.paths = extra or ('/',)
+ opt.paths = [argv_bytes(x) for x in extra] or (pwd,)
opt.long_listing = opt.l
opt.classification = None
opt.show_hidden = None
opt.show_hidden = 'almost'
return opt
-def within_repo(repo, opt):
+def within_repo(repo, opt, out, pwd=b''):
if opt.commit_hash:
opt.hash = True
human_readable=opt.human_readable)
ret = 0
+ want_meta = bool(opt.long_listing or opt.classification)
pending = []
- for path in opt.paths:
+ last_n = len(opt.paths) - 1
+ for n, printpath in enumerate(opt.paths):
+ path = posixpath.join(pwd, printpath)
try:
+ if last_n > 0:
+ out.write(b'%s:\n' % printpath)
+
if opt.directory:
- resolved = vfs.lresolve(repo, path)
+ resolved = vfs.resolve(repo, path, follow=False)
else:
- resolved = vfs.try_resolve(repo, path)
+ resolved = vfs.try_resolve(repo, path, want_meta=want_meta)
leaf_name, leaf_item = resolved[-1]
if not leaf_item:
log('error: cannot access %r in %r\n'
- % ('/'.join(name for name, item in resolved),
- path))
+ % ('/'.join(path_msg(name) for name, item in resolved),
+ path_msg(path)))
ret = 1
continue
if not opt.directory and S_ISDIR(vfs.item_mode(leaf_item)):
- items = vfs.contents(repo, leaf_item)
+ items = vfs.contents(repo, leaf_item, want_meta=want_meta)
if opt.show_hidden == 'all':
# Match non-bup "ls -a ... /".
parent = resolved[-2] if len(resolved) > 1 else resolved[0]
- items = chain(items, (('..', parent[1]),))
+ items = chain(items, ((b'..', parent[1]),))
for sub_name, sub_item in sorted(items, key=lambda x: x[0]):
- if opt.show_hidden != 'all' and sub_name == '.':
+ if opt.show_hidden != 'all' and sub_name == b'.':
continue
- if sub_name.startswith('.') and \
+ if sub_name.startswith(b'.') and \
opt.show_hidden not in ('almost', 'all'):
continue
if opt.l:
sub_item = vfs.ensure_item_has_metadata(repo, sub_item,
include_size=True)
- else:
+ elif want_meta:
sub_item = vfs.augment_item_meta(repo, sub_item,
include_size=True)
line = item_line(sub_item, sub_name)
if not opt.long_listing and istty1:
pending.append(line)
else:
- print(line)
+ out.write(line)
+ out.write(b'\n')
else:
- leaf_item = vfs.augment_item_meta(repo, leaf_item,
- include_size=True)
+ if opt.long_listing:
+ leaf_item = vfs.augment_item_meta(repo, leaf_item,
+ include_size=True)
line = item_line(leaf_item, os.path.normpath(path))
if not opt.long_listing and istty1:
pending.append(line)
else:
- print(line)
+ out.write(line)
+ out.write(b'\n')
except vfs.IOError as ex:
log('bup: %s\n' % ex)
ret = 1
- if pending:
- sys.stdout.write(columnate(pending, ''))
+ if pending:
+ out.write(columnate(pending, b''))
+ pending = []
+
+ if n < last_n:
+ out.write(b'\n')
return ret
-def via_cmdline(args, onabort=None):
- """Output a listing of a file or directory in the bup repository.
+def via_cmdline(args, out=None, onabort=None):
+ """Write a listing of a file or directory in the bup repository to out.
When a long listing is not requested and stdout is attached to a
tty, the output is formatted in columns. When not attached to tty
file is listed per line.
"""
+ assert out
opt = opts_from_cmdline(args, onabort=onabort)
- return within_repo(RemoteRepo(opt.remote) if opt.remote else LocalRepo(),
- opt)
+ with RemoteRepo(argv_bytes(opt.remote)) if opt.remote \
+ else LocalRepo() as repo:
+ return within_repo(repo, opt, out)