diff --git a/CHANGES.rst b/CHANGES.rst index 6ee0380..4243efe 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -15,6 +15,9 @@ New features Bug fixes and minor changes --------------------------- ++ `#81`_, `#82`_: `archive-tool ls` fails with :exc:`TypeError` if the + path of a file in the archive contains two consecutive blanks. + + `#75`_: Drop :class:`distutils.version.StrictVersion` deprecated since Python 3.10 in favour of our own helper :class:`archive.tools.Version` based on @@ -32,6 +35,8 @@ Internal changes .. _#76: https://github.com/RKrahl/archive-tools/issues/76 .. _#77: https://github.com/RKrahl/archive-tools/pull/77 .. _#80: https://github.com/RKrahl/archive-tools/pull/80 +.. _#81: https://github.com/RKrahl/archive-tools/issues/81 +.. _#82: https://github.com/RKrahl/archive-tools/pull/82 0.6 (2021-12-12) diff --git a/src/archive/cli/ls.py b/src/archive/cli/ls.py index c3d12cb..d41db19 100644 --- a/src/archive/cli/ls.py +++ b/src/archive/cli/ls.py @@ -11,7 +11,7 @@ def ls_ls_format(archive): l_ug = 0 l_s = 0 for fi in archive.manifest: - elems = tuple(str(fi).split(" ")) + elems = fi.as_str_tuple() l_ug = max(l_ug, len(elems[1])) l_s = max(l_s, len(elems[2])) items.append(elems) diff --git a/src/archive/manifest.py b/src/archive/manifest.py index 5d4310b..315ae89 100644 --- a/src/archive/manifest.py +++ b/src/archive/manifest.py @@ -119,7 +119,7 @@ def as_dict(self): d['target'] = str(self.target) return d - def __str__(self): + def as_str_tuple(self): m = stat.filemode(self.st_mode) ug = "%s/%s" % (self.uname or self.uid, self.gname or self.gid) s = str(self.size if self.type == 'f' else 0) @@ -129,7 +129,10 @@ def __str__(self): p = "%s -> %s" % (self.path, self.target) else: p = self.path - return "%s %s %s %s %s" % (m, ug, s, d, p) + return (m, ug, s, d, p) + + def __str__(self): + return "%s %s %s %s %s" % self.as_str_tuple() @classmethod def iterpaths(cls, paths, excludes): diff --git a/tests/test_04_cli_ls.py b/tests/test_04_cli_ls.py new file mode 100644 index 0000000..96ae3c7 --- /dev/null +++ b/tests/test_04_cli_ls.py @@ -0,0 +1,37 @@ +"""Test the ls subcommand in the command line tool. + +The general functioning is already tested in test_04_cli.py, we only +consider edge cases here. +""" + +from pathlib import Path +import stat +from tempfile import TemporaryFile +import pytest +from archive import Archive +from conftest import * + + +def test_cli_ls_blank_path(tmpdir): + """Test case: archive contains a file having blanks in the path. + Ref. Issue #81. + """ + testdata = [ + DataDir(Path("base"), 0o755), + DataFile(Path("base", "msg.txt"), 0o644), + DataContentFile(Path("base", "path with blanks.dat"), b"", 0o600), + ] + setup_testdata(tmpdir, testdata) + archive_path = tmpdir / "archive.tar" + Archive().create(archive_path, paths=[Path("base")], workdir=tmpdir) + with TemporaryFile(mode="w+t", dir=tmpdir) as f: + args = ["ls", str(archive_path)] + callscript("archive-tool.py", args, stdout=f) + f.seek(0) + for entry in sorted(testdata, key=lambda e: e.path): + line = f.readline().strip() + fields = line.split(maxsplit=5) + assert fields[0] == stat.filemode(entry.st_mode) + assert fields[5] == str(entry.path) + assert len(fields) == 6 + assert not f.readline()