mirror of
https://github.com/borgbackup/borg.git
synced 2024-12-25 01:06:50 +00:00
borg list --short, remove requirement for fakeroot, xfail a test
borg list --short just spills out the list of files / dirs - better for some tests and also useful on the commandline for interactive use. the tests previously needed fakeroot because in the test setup it always made calls to mknod and chown, which require (fake)root. now, the tests adapt to whether it detects (fake)root or not - to run the the tests completely, you still need fakeroot, but it won't fail all the archiver tests just due to failing test setup. also, a test not working correctly due to fakeroot was found: it should detect whether a read-only repo is usable, but it failed to do that because with (fake)root, there is no "read only" (at least not via taking away the w permission bits).
This commit is contained in:
parent
738ed5d91b
commit
608c0935e0
2 changed files with 74 additions and 35 deletions
|
@ -337,34 +337,38 @@ def do_list(self, args):
|
|||
repository = self.open_repository(args.src)
|
||||
manifest, key = Manifest.load(repository)
|
||||
if args.src.archive:
|
||||
tmap = {1: 'p', 2: 'c', 4: 'd', 6: 'b', 0o10: '-', 0o12: 'l', 0o14: 's'}
|
||||
archive = Archive(repository, key, manifest, args.src.archive)
|
||||
for item in archive.iter_items():
|
||||
type = tmap.get(item[b'mode'] // 4096, '?')
|
||||
mode = format_file_mode(item[b'mode'])
|
||||
size = 0
|
||||
if type == '-':
|
||||
if args.short:
|
||||
for item in archive.iter_items():
|
||||
print(remove_surrogates(item[b'path']))
|
||||
else:
|
||||
tmap = {1: 'p', 2: 'c', 4: 'd', 6: 'b', 0o10: '-', 0o12: 'l', 0o14: 's'}
|
||||
for item in archive.iter_items():
|
||||
type = tmap.get(item[b'mode'] // 4096, '?')
|
||||
mode = format_file_mode(item[b'mode'])
|
||||
size = 0
|
||||
if type == '-':
|
||||
try:
|
||||
size = sum(size for _, size, _ in item[b'chunks'])
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
size = sum(size for _, size, _ in item[b'chunks'])
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
mtime = datetime.fromtimestamp(bigint_to_int(item[b'mtime']) / 1e9)
|
||||
except ValueError:
|
||||
# likely a broken mtime and datetime did not want to go beyond year 9999
|
||||
mtime = datetime(9999, 12, 31, 23, 59, 59)
|
||||
if b'source' in item:
|
||||
if type == 'l':
|
||||
extra = ' -> %s' % item[b'source']
|
||||
mtime = datetime.fromtimestamp(bigint_to_int(item[b'mtime']) / 1e9)
|
||||
except ValueError:
|
||||
# likely a broken mtime and datetime did not want to go beyond year 9999
|
||||
mtime = datetime(9999, 12, 31, 23, 59, 59)
|
||||
if b'source' in item:
|
||||
if type == 'l':
|
||||
extra = ' -> %s' % item[b'source']
|
||||
else:
|
||||
type = 'h'
|
||||
extra = ' link to %s' % item[b'source']
|
||||
else:
|
||||
type = 'h'
|
||||
extra = ' link to %s' % item[b'source']
|
||||
else:
|
||||
extra = ''
|
||||
print('%s%s %-6s %-6s %8d %s %s%s' % (
|
||||
type, mode, item[b'user'] or item[b'uid'],
|
||||
item[b'group'] or item[b'gid'], size, format_time(mtime),
|
||||
remove_surrogates(item[b'path']), extra))
|
||||
extra = ''
|
||||
print('%s%s %-6s %-6s %8d %s %s%s' % (
|
||||
type, mode, item[b'user'] or item[b'uid'],
|
||||
item[b'group'] or item[b'gid'], size, format_time(mtime),
|
||||
remove_surrogates(item[b'path']), extra))
|
||||
else:
|
||||
for archive_info in manifest.list_archive_infos(sort_by='ts'):
|
||||
print(format_archive(archive_info))
|
||||
|
@ -766,6 +770,9 @@ def run(self, args=None):
|
|||
epilog=list_epilog,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
subparser.set_defaults(func=self.do_list)
|
||||
subparser.add_argument('--short', dest='short',
|
||||
action='store_true', default=False,
|
||||
help='only print file/directory names, nothing else')
|
||||
subparser.add_argument('src', metavar='REPOSITORY_OR_ARCHIVE', type=location_validator(),
|
||||
help='repository/archive to list contents of')
|
||||
mount_epilog = textwrap.dedent("""
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
from hashlib import sha256
|
||||
|
||||
from mock import patch
|
||||
import pytest
|
||||
|
||||
from .. import xattr
|
||||
from ..archive import Archive, ChunkBuffer, CHUNK_MAX_EXP
|
||||
|
@ -33,6 +34,12 @@
|
|||
|
||||
src_dir = os.path.join(os.getcwd(), os.path.dirname(__file__), '..')
|
||||
|
||||
# Python <= 3.2 raises OSError instead of PermissionError (See #164)
|
||||
try:
|
||||
PermissionError = PermissionError
|
||||
except NameError:
|
||||
PermissionError = OSError
|
||||
|
||||
|
||||
class changedir:
|
||||
def __init__(self, dir):
|
||||
|
@ -154,15 +161,8 @@ def create_test_files(self):
|
|||
self.create_regular_file('flagfile', size=1024)
|
||||
# Directory
|
||||
self.create_regular_file('dir2/file2', size=1024 * 80)
|
||||
# File owner
|
||||
os.chown('input/file1', 100, 200)
|
||||
# File mode
|
||||
os.chmod('input/file1', 0o7755)
|
||||
os.chmod('input/dir2', 0o555)
|
||||
# Block device
|
||||
os.mknod('input/bdev', 0o600 | stat.S_IFBLK, os.makedev(10, 20))
|
||||
# Char device
|
||||
os.mknod('input/cdev', 0o600 | stat.S_IFCHR, os.makedev(30, 40))
|
||||
# Hard link
|
||||
os.link(os.path.join(self.input_path, 'file1'),
|
||||
os.path.join(self.input_path, 'hardlink'))
|
||||
|
@ -180,20 +180,50 @@ def create_test_files(self):
|
|||
os.mkfifo(os.path.join(self.input_path, 'fifo1'))
|
||||
if has_lchflags:
|
||||
os.lchflags(os.path.join(self.input_path, 'flagfile'), stat.UF_NODUMP)
|
||||
try:
|
||||
# Block device
|
||||
os.mknod('input/bdev', 0o600 | stat.S_IFBLK, os.makedev(10, 20))
|
||||
# Char device
|
||||
os.mknod('input/cdev', 0o600 | stat.S_IFCHR, os.makedev(30, 40))
|
||||
# File mode
|
||||
os.chmod('input/dir2', 0o555) # if we take away write perms, we need root to remove contents
|
||||
# File owner
|
||||
os.chown('input/file1', 100, 200)
|
||||
have_root = True # we have (fake)root
|
||||
except PermissionError:
|
||||
have_root = False
|
||||
return have_root
|
||||
|
||||
def test_basic_functionality(self):
|
||||
self.create_test_files()
|
||||
have_root = self.create_test_files()
|
||||
self.cmd('init', self.repository_location)
|
||||
self.cmd('create', self.repository_location + '::test', 'input')
|
||||
self.cmd('create', '--stats', self.repository_location + '::test.2', 'input')
|
||||
with changedir('output'):
|
||||
self.cmd('extract', self.repository_location + '::test')
|
||||
self.assert_equal(len(self.cmd('list', self.repository_location).splitlines()), 2)
|
||||
item_count = 10 if has_lchflags else 11 # one file is UF_NODUMP
|
||||
self.assert_equal(len(self.cmd('list', self.repository_location + '::test').splitlines()), item_count)
|
||||
expected = [
|
||||
'input',
|
||||
'input/bdev',
|
||||
'input/cdev',
|
||||
'input/dir2',
|
||||
'input/dir2/file2',
|
||||
'input/empty',
|
||||
'input/fifo1',
|
||||
'input/file1',
|
||||
'input/flagfile',
|
||||
'input/hardlink',
|
||||
'input/link1',
|
||||
]
|
||||
if not have_root:
|
||||
# we could not create these device files without (fake)root
|
||||
expected.remove('input/bdev')
|
||||
expected.remove('input/cdev')
|
||||
if has_lchflags:
|
||||
# remove the file we did not backup, so input and output become equal
|
||||
expected.remove('input/flagfile') # this file is UF_NODUMP
|
||||
os.remove(os.path.join('input', 'flagfile'))
|
||||
self.assert_equal(self.cmd('list', '--short', self.repository_location + '::test').splitlines(), expected)
|
||||
self.assert_dirs_equal('input', 'output/input')
|
||||
info_output = self.cmd('info', self.repository_location + '::test')
|
||||
item_count = 3 if has_lchflags else 4 # one file is UF_NODUMP
|
||||
|
@ -436,6 +466,8 @@ def test_corrupted_repository(self):
|
|||
fd.write(b'XXXX')
|
||||
self.cmd('check', self.repository_location, exit_code=1)
|
||||
|
||||
# we currently need to be able to create a lock directory inside the repo:
|
||||
@pytest.mark.xfail(reason="we need to be able to create the lock directory inside the repo")
|
||||
def test_readonly_repository(self):
|
||||
self.cmd('init', self.repository_location)
|
||||
self.create_src_archive('test')
|
||||
|
|
Loading…
Reference in a new issue