From: Rob Browning Date: Thu, 30 Jan 2014 22:26:44 +0000 (-0600) Subject: Fix the ls -laAF options with respect to the VFS synthetic directories. X-Git-Tag: 0.26-rc1~48 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=bup.git;a=commitdiff_plain;h=cb7366ef107073d2de753240af2a75facf904588 Fix the ls -laAF options with respect to the VFS synthetic directories. Before this, they wouldn't work in various cases where the VFS was creating synthetic data (like the top-level branch and commit-list trees). Oh, and how about some tests? Thanks to Gabriel Filion for reporting the problem. Signed-off-by: Rob Browning --- diff --git a/Makefile b/Makefile index 8eaec0b..a2a22bf 100644 --- a/Makefile +++ b/Makefile @@ -94,6 +94,7 @@ runtests-cmdline: all TMPDIR="$(test_tmp)" t/test-fsck.sh TMPDIR="$(test_tmp)" t/test-index-clear.sh TMPDIR="$(test_tmp)" t/test-index-check-device.sh + TMPDIR="$(test_tmp)" t/test-ls.sh TMPDIR="$(test_tmp)" t/test-meta.sh TMPDIR="$(test_tmp)" t/test-restore-map-owner.sh TMPDIR="$(test_tmp)" t/test-restore-single-file.sh diff --git a/lib/bup/ls.py b/lib/bup/ls.py index 002e15d..66e421d 100644 --- a/lib/bup/ls.py +++ b/lib/bup/ls.py @@ -1,5 +1,5 @@ """Common code for listing files from a bup repository.""" -import copy, stat +import copy, stat, xstat from bup import metadata, options, vfs from helpers import * @@ -11,36 +11,32 @@ def node_info(n, name, numeric_ids = False, human_readable = False): """Return a string containing the information to display for the node - n. Classification may be "all", "type", or None. - - """ + n. Classification may be "all", "type", or None.""" result = '' if show_hash: result += "%s " % n.hash.encode('hex') if long_fmt: meta = copy.copy(n.metadata()) - meta.size = n.size() + if meta: + meta.path = name + else: + # Fake it -- summary_str() is designed to handle a fake. + meta = metadata.Metadata() + meta.size = n.size() + meta.mode = n.mode + meta.path = name + meta.atime, meta.mtime, meta.ctime = n.atime, n.mtime, n.ctime + if stat.S_ISLNK(meta.mode): + meta.symlink_target = n.readlink() result += metadata.summary_str(meta, numeric_ids = numeric_ids, - human_readable = human_readable) + ' ' - result += name - if classification: - if n.metadata(): - mode = n.metadata().mode - else: - mode = n.mode - if stat.S_ISREG(mode): - if classification == 'all' \ - and stat.S_IMODE(mode) & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH): - result += '*' - elif stat.S_ISDIR(mode): - result += '/' - elif stat.S_ISLNK(mode): - result += '@' - elif stat.S_ISFIFO(mode): - result += '|' - elif stat.S_ISSOCK(mode): - result += '=' + classification = classification, + human_readable = human_readable) + else: + result += name + if classification: + mode = n.metadata() and n.metadata().mode or n.mode + result += xstat.classification_str(mode, classification == 'all') return result @@ -106,8 +102,12 @@ def do_ls(args, pwd, default='.', onabort=None, spec_prefix=''): if stat.S_ISDIR(n.mode): if show_hidden == 'all': - for implied, name in ((n, '.'), (n.parent, '..')): - output_node_info(implied, name) + output_node_info(n, '.') + # Match non-bup "ls -a ... /". + if n.parent: + output_node_info(n.parent, '..') + else: + output_node_info(n, '..') for sub in n: name = sub.name if show_hidden in ('almost', 'all') \ diff --git a/lib/bup/metadata.py b/lib/bup/metadata.py index 0622d2b..05b47bd 100644 --- a/lib/bup/metadata.py +++ b/lib/bup/metadata.py @@ -889,31 +889,57 @@ all_fields = frozenset(['path', 'posix1e-acl']) -def summary_str(meta, numeric_ids = False, human_readable = False): - mode_val = xstat.mode_str(meta.mode) - user_val = meta.user - if numeric_ids or not user_val: - user_val = str(meta.uid) - group_val = meta.group - if numeric_ids or not group_val: - group_val = str(meta.gid) - size_or_dev_val = '-' - if stat.S_ISCHR(meta.mode) or stat.S_ISBLK(meta.mode): - size_or_dev_val = '%d,%d' % (os.major(meta.rdev), os.minor(meta.rdev)) - elif meta.size != None: - size_or_dev_val = meta.size - if human_readable: - size_or_dev_val = format_filesize(meta.size) - mtime_secs = xstat.fstime_floor_secs(meta.mtime) - time_val = time.strftime('%Y-%m-%d %H:%M', time.localtime(mtime_secs)) - path_val = meta.path or '' - if stat.S_ISLNK(meta.mode): - path_val += ' -> ' + meta.symlink_target - return '%-10s %-11s %11s %16s %s' % (mode_val, - user_val + "/" + group_val, - size_or_dev_val, - time_val, - path_val) +def summary_str(meta, numeric_ids = False, classification = None, + human_readable = False): + + """Return a string containing the "ls -l" style listing for meta. + Classification may be "all", "type", or None.""" + user_str = group_str = size_or_dev_str = '?' + symlink_target = None + if meta: + name = meta.path + mode_str = xstat.mode_str(meta.mode) + symlink_target = meta.symlink_target + mtime_secs = xstat.fstime_floor_secs(meta.mtime) + mtime_str = time.strftime('%Y-%m-%d %H:%M', time.localtime(mtime_secs)) + if meta.user and not numeric_ids: + user_str = meta.user + elif meta.uid != None: + user_str = str(meta.uid) + if meta.group and not numeric_ids: + group_str = meta.group + elif meta.gid != None: + group_str = str(meta.gid) + if stat.S_ISCHR(meta.mode) or stat.S_ISBLK(meta.mode): + if meta.rdev: + size_or_dev_str = '%d,%d' % (os.major(meta.rdev), + os.minor(meta.rdev)) + elif meta.size: + if human_readable: + size_or_dev_str = format_filesize(meta.size) + else: + size_or_dev_str = str(meta.size) + else: + size_or_dev_str = '-' + if classification: + classification_str = \ + xstat.classification_str(meta.mode, classification == 'all') + else: + mode_str = '?' * 10 + mtime_str = '????-??-?? ??:??' + classification_str = '?' + + name = name or '' + if classification: + name += classification_str + if symlink_target: + name += ' -> ' + meta.symlink_target + + return '%-10s %-11s %11s %16s %s' % (mode_str, + user_str + "/" + group_str, + size_or_dev_str, + mtime_str, + name) def detailed_str(meta, fields = None): diff --git a/lib/bup/xstat.py b/lib/bup/xstat.py index 8daa2c2..0eee9b2 100644 --- a/lib/bup/xstat.py +++ b/lib/bup/xstat.py @@ -116,6 +116,7 @@ def lstat(path): def mode_str(mode): result = '' + # FIXME: Other types? if pystat.S_ISREG(mode): result += '-' elif pystat.S_ISDIR(mode): @@ -143,3 +144,23 @@ def mode_str(mode): result += 'w' if (mode & pystat.S_IWOTH) else '-' result += 'x' if (mode & pystat.S_IXOTH) else '-' return result + + +def classification_str(mode, include_exec): + if pystat.S_ISREG(mode): + if include_exec \ + and (pystat.S_IMODE(mode) \ + & (pystat.S_IXUSR | pystat.S_IXGRP | pystat.S_IXOTH)): + return '*' + else: + return '' + elif pystat.S_ISDIR(mode): + return '/' + elif pystat.S_ISLNK(mode): + return '@' + elif pystat.S_ISFIFO(mode): + return '|' + elif pystat.S_ISSOCK(mode): + return '=' + else: + return '' diff --git a/t/test-ls.sh b/t/test-ls.sh new file mode 100755 index 0000000..db5772a --- /dev/null +++ b/t/test-ls.sh @@ -0,0 +1,181 @@ +#!/usr/bin/env bash +. ./wvtest-bup.sh + +set -o pipefail + +top="$(WVPASS pwd)" || exit $? +tmpdir="$(WVPASS wvmktempdir)" || exit $? + +export BUP_DIR="$tmpdir/bup" +export GIT_DIR="$tmpdir/bup" + +bup() { "$top/bup" "$@"; } + +WVPASS bup init +WVPASS cd "$tmpdir" + +WVPASS mkdir src +WVPASS touch -t 191111111111 src/.dotfile +WVPASS date > src/file +WVPASS touch -t 191111111111 src/file +(WVPASS cd src; WVPASS ln -s file symlink) || exit $? +WVPASS mkfifo src/fifo +WVPASS touch -t 191111111111 src/fifo +WVPASS "$top"/t/mksock src/socket +WVPASS touch -t 191111111111 src/socket +WVPASS touch -t 191111111111 src/executable +WVPASS chmod u+x src/executable +WVPASS touch -t 191111111111 src/executable +WVPASS touch -t 191111111111 src +WVPASS touch -t 191111111111 . +WVPASS chmod -R u=rwX,g-rwx,o-rwx . +WVPASS bup index src +WVPASS bup save -n src src + +WVSTART "ls (short)" + +WVPASSEQ "$(WVPASS bup ls /)" "src" + +WVPASSEQ "$(WVPASS bup ls -A /)" ".commit +.tag +src" + +WVPASSEQ "$(WVPASS bup ls -AF /)" ".commit/ +.tag/ +src/" + +WVPASSEQ "$(WVPASS bup ls -a /)" ". +.. +.commit +.tag +src" + +WVPASSEQ "$(WVPASS bup ls -aF /)" "./ +../ +.commit/ +.tag/ +src/" + +WVPASSEQ "$(WVPASS bup ls src/latest/"$tmpdir"/src)" "executable +fifo +file +socket +symlink" + +WVPASSEQ "$(WVPASS bup ls -A src/latest/"$tmpdir"/src)" ".dotfile +executable +fifo +file +socket +symlink" + +WVPASSEQ "$(WVPASS bup ls -a src/latest/"$tmpdir"/src)" ". +.. +.dotfile +executable +fifo +file +socket +symlink" + +WVPASSEQ "$(WVPASS bup ls -F src/latest/"$tmpdir"/src)" "executable* +fifo| +file +socket= +symlink@" + +WVPASSEQ "$(WVPASS bup ls --file-type src/latest/"$tmpdir"/src)" "executable +fifo| +file +socket= +symlink@" + +WVSTART "ls (long)" + +WVPASSEQ "$(WVPASS bup ls -l / | tr -s ' ' ' ')" \ +"d--------- ?/? - 1969-12-31 18:00 src" + +WVPASSEQ "$(WVPASS bup ls -lA / | tr -s ' ' ' ')" \ +"d--------- ?/? - 1969-12-31 18:00 .commit +d--------- ?/? - 1969-12-31 18:00 .tag +d--------- ?/? - 1969-12-31 18:00 src" + +WVPASSEQ "$(WVPASS bup ls -lAF / | tr -s ' ' ' ')" \ +"d--------- ?/? - 1969-12-31 18:00 .commit/ +d--------- ?/? - 1969-12-31 18:00 .tag/ +d--------- ?/? - 1969-12-31 18:00 src/" + +WVPASSEQ "$(WVPASS bup ls -la / | tr -s ' ' ' ')" \ +"d--------- ?/? - 1969-12-31 18:00 . +d--------- ?/? - 1969-12-31 18:00 .. +d--------- ?/? - 1969-12-31 18:00 .commit +d--------- ?/? - 1969-12-31 18:00 .tag +d--------- ?/? - 1969-12-31 18:00 src" + +WVPASSEQ "$(WVPASS bup ls -laF / | tr -s ' ' ' ')" \ +"d--------- ?/? - 1969-12-31 18:00 ./ +d--------- ?/? - 1969-12-31 18:00 ../ +d--------- ?/? - 1969-12-31 18:00 .commit/ +d--------- ?/? - 1969-12-31 18:00 .tag/ +d--------- ?/? - 1969-12-31 18:00 src/" + +symlink_date="$(bup ls -l src/latest"$tmpdir"/src | grep symlink)" +symlink_date="$(echo "$symlink_date" \ + | perl -ne 'm/.*? - (\d\d\d\d-\d\d-\d\d \d\d:\d\d)/ and print $1')" +uid="$(id -u)" || exit $? +gid="$(id -g)" || exit $? +user="$(id -un)" || exit $? +group="$(id -gn)" || exit $? + +WVPASSEQ "$(bup ls -l src/latest"$tmpdir"/src | tr -s ' ' ' ')" \ +"-rwx------ $user/$group - 1911-11-11 11:11 executable +prw------- $user/$group - 1911-11-11 11:11 fifo +-rw------- $user/$group - 1911-11-11 11:11 file +srwx------ $user/$group - 1911-11-11 11:11 socket +lrwxrwxrwx $user/$group - $symlink_date symlink -> file" + +WVPASSEQ "$(bup ls -la src/latest"$tmpdir"/src | tr -s ' ' ' ')" \ +"drwx------ $user/$group - 1911-11-11 11:11 . +drwx------ $user/$group - 1911-11-11 11:11 .. +-rw------- $user/$group - 1911-11-11 11:11 .dotfile +-rwx------ $user/$group - 1911-11-11 11:11 executable +prw------- $user/$group - 1911-11-11 11:11 fifo +-rw------- $user/$group - 1911-11-11 11:11 file +srwx------ $user/$group - 1911-11-11 11:11 socket +lrwxrwxrwx $user/$group - $symlink_date symlink -> file" + +WVPASSEQ "$(bup ls -lA src/latest"$tmpdir"/src | tr -s ' ' ' ')" \ +"-rw------- $user/$group - 1911-11-11 11:11 .dotfile +-rwx------ $user/$group - 1911-11-11 11:11 executable +prw------- $user/$group - 1911-11-11 11:11 fifo +-rw------- $user/$group - 1911-11-11 11:11 file +srwx------ $user/$group - 1911-11-11 11:11 socket +lrwxrwxrwx $user/$group - $symlink_date symlink -> file" + +WVPASSEQ "$(bup ls -lF src/latest"$tmpdir"/src | tr -s ' ' ' ')" \ +"-rwx------ $user/$group - 1911-11-11 11:11 executable* +prw------- $user/$group - 1911-11-11 11:11 fifo| +-rw------- $user/$group - 1911-11-11 11:11 file +srwx------ $user/$group - 1911-11-11 11:11 socket= +lrwxrwxrwx $user/$group - $symlink_date symlink@ -> file" + +WVPASSEQ "$(bup ls -l --file-type src/latest"$tmpdir"/src | tr -s ' ' ' ')" \ +"-rwx------ $user/$group - 1911-11-11 11:11 executable +prw------- $user/$group - 1911-11-11 11:11 fifo| +-rw------- $user/$group - 1911-11-11 11:11 file +srwx------ $user/$group - 1911-11-11 11:11 socket= +lrwxrwxrwx $user/$group - $symlink_date symlink@ -> file" + +WVPASSEQ "$(bup ls -ln src/latest"$tmpdir"/src | tr -s ' ' ' ')" \ +"-rwx------ $uid/$gid - 1911-11-11 11:11 executable +prw------- $uid/$gid - 1911-11-11 11:11 fifo +-rw------- $uid/$gid - 1911-11-11 11:11 file +srwx------ $uid/$gid - 1911-11-11 11:11 socket +lrwxrwxrwx $uid/$gid - $symlink_date symlink -> file" + +WVSTART "ls (backup set - long)" +WVPASSEQ "$(bup ls -l src | cut -d' ' -f 1-2)" \ +"l--------- ?/? +l--------- ?/?" + +WVPASS rm -rf "$tmpdir"