Add option to show MD5 checksums in dvc ls (#10573)

This commit is contained in:
Pete Bachant
2024-10-21 16:32:03 +05:45
committed by GitHub
parent d22a68f7a8
commit d236667048
3 changed files with 129 additions and 22 deletions
+29 -6
View File
@@ -9,18 +9,25 @@ from dvc.ui import ui
logger = logger.getChild(__name__)
def _format_entry(entry, fmt):
def _format_entry(entry, fmt, with_size=True, with_md5=False):
from dvc.utils.humanize import naturalsize
ret = []
if with_size:
size = entry.get("size")
if size is None:
size = ""
else:
size = naturalsize(size)
return size, fmt(entry)
ret.append(size)
if with_md5:
md5 = entry.get("md5", "")
ret.append(md5)
ret.append(fmt(entry))
return ret
def show_entries(entries, with_color=False, with_size=False):
def show_entries(entries, with_color=False, with_size=False, with_md5=False):
if with_color:
ls_colors = LsColors()
fmt = ls_colors.format
@@ -29,8 +36,13 @@ def show_entries(entries, with_color=False, with_size=False):
def fmt(entry):
return entry["path"]
if with_size:
ui.table([_format_entry(entry, fmt) for entry in entries])
if with_size or with_md5:
ui.table(
[
_format_entry(entry, fmt, with_size=with_size, with_md5=with_md5)
for entry in entries
]
)
return
# NOTE: this is faster than ui.table for very large number of entries
@@ -55,7 +67,12 @@ class CmdList(CmdBaseNoRepo):
if self.args.json:
ui.write_json(entries)
elif entries:
show_entries(entries, with_color=True, with_size=self.args.size)
show_entries(
entries,
with_color=True,
with_size=self.args.size,
with_md5=self.args.show_hash,
)
return 0
except FileNotFoundError:
logger.exception("")
@@ -123,6 +140,12 @@ def add_parser(subparsers, parent_parser):
),
)
list_parser.add_argument("--size", action="store_true", help="Show sizes.")
list_parser.add_argument(
"--show-hash",
help="Display hash value for each item.",
action="store_true",
default=False,
)
list_parser.add_argument(
"path",
nargs="?",
+1
View File
@@ -110,6 +110,7 @@ def _ls(
"isdir": info["type"] == "directory",
"isexec": info.get("isexec", False),
"size": info.get("size"),
"md5": dvc_info.get("md5") or dvc_info.get("md5-dos2unix"),
}
return ret
+94 -11
View File
@@ -222,7 +222,12 @@ def test_ls_repo_with_missed_path_dvc_only(tmp_dir, dvc, scm):
tmp_dir.dvc_gen(DVC_STRUCTURE, commit="dvc")
with pytest.raises(FileNotFoundError):
Repo.ls(os.fspath(tmp_dir), path="missed_path", recursive=True, dvc_only=True)
Repo.ls(
os.fspath(tmp_dir),
path="missed_path",
recursive=True,
dvc_only=True,
)
def test_ls_repo_with_removed_dvc_dir(tmp_dir, dvc, scm):
@@ -467,20 +472,49 @@ def test_ls_granular(erepo_dir, M):
entries = Repo.ls(os.fspath(erepo_dir), os.path.join("dir", "subdir"))
assert entries == [
{"isout": True, "isdir": False, "isexec": False, "path": "bar", "size": 3},
{"isout": True, "isdir": False, "isexec": False, "path": "foo", "size": 3},
{
"isout": True,
"isdir": False,
"isexec": False,
"path": "bar",
"size": 3,
"md5": "37b51d194a7513e45b56f6524f2d51f2",
},
{
"isout": True,
"isdir": False,
"isexec": False,
"path": "foo",
"size": 3,
"md5": "acbd18db4cc2f85cedef654fccc4a4d8",
},
]
entries = Repo.ls(os.fspath(erepo_dir), "dir")
assert entries == [
{"isout": True, "isdir": False, "isexec": False, "path": "1", "size": 1},
{"isout": True, "isdir": False, "isexec": False, "path": "2", "size": 1},
{
"isout": True,
"isdir": False,
"isexec": False,
"path": "1",
"size": 1,
"md5": "c4ca4238a0b923820dcc509a6f75849b",
},
{
"isout": True,
"isdir": False,
"isexec": False,
"path": "2",
"size": 1,
"md5": "c81e728d9d4c2f636f067f89cc14862c",
},
{
"isout": True,
"isdir": True,
"isexec": False,
"path": "subdir",
"size": M.instance_of(int),
"md5": None,
},
]
@@ -506,14 +540,42 @@ def test_ls_target(erepo_dir, use_scm):
return Repo.ls(os.fspath(erepo_dir), path)
assert _ls(os.path.join("dir", "1")) == [
{"isout": isout, "isdir": False, "isexec": False, "path": "1", "size": 1}
{
"isout": isout,
"isdir": False,
"isexec": False,
"path": "1",
"size": 1,
"md5": "c4ca4238a0b923820dcc509a6f75849b" if not use_scm else None,
}
]
assert _ls(os.path.join("dir", "subdir", "foo")) == [
{"isout": isout, "isdir": False, "isexec": False, "path": "foo", "size": 3}
{
"isout": isout,
"isdir": False,
"isexec": False,
"path": "foo",
"size": 3,
"md5": "acbd18db4cc2f85cedef654fccc4a4d8" if not use_scm else None,
}
]
assert _ls(os.path.join("dir", "subdir")) == [
{"isdir": False, "isexec": 0, "isout": isout, "path": "bar", "size": 3},
{"isdir": False, "isexec": 0, "isout": isout, "path": "foo", "size": 3},
{
"isdir": False,
"isexec": 0,
"isout": isout,
"path": "bar",
"size": 3,
"md5": "37b51d194a7513e45b56f6524f2d51f2" if not use_scm else None,
},
{
"isdir": False,
"isexec": 0,
"isout": isout,
"path": "foo",
"size": 3,
"md5": "acbd18db4cc2f85cedef654fccc4a4d8" if not use_scm else None,
},
]
@@ -576,6 +638,7 @@ def test_broken_symlink(tmp_dir, dvc, M):
"isexec": False,
"path": ".dvcignore",
"size": M.instance_of(int),
"md5": None,
},
{
"isout": False,
@@ -583,6 +646,7 @@ def test_broken_symlink(tmp_dir, dvc, M):
"isexec": False,
"path": "link",
"size": 0,
"md5": None,
},
]
@@ -614,14 +678,23 @@ def test_ls_broken_dir(tmp_dir, dvc, M):
"isout": False,
"path": ".dvcignore",
"size": M.instance_of(int),
"md5": None,
},
{
"isdir": True,
"isexec": False,
"isout": True,
"path": "broken",
"size": 3,
"md5": "630bd47b538d2a513c7d267d07e0bc44.dir",
},
{"isdir": True, "isexec": False, "isout": True, "path": "broken", "size": 3},
{
"isdir": False,
"isexec": False,
"isout": False,
"path": "broken.dvc",
"size": M.instance_of(int),
"md5": None,
},
{
"isdir": True,
@@ -629,6 +702,7 @@ def test_ls_broken_dir(tmp_dir, dvc, M):
"isout": True,
"path": "dir",
"size": M.instance_of(int),
"md5": "91aaa9bb58b657d623ef143b195a67e4.dir",
},
{
"isdir": False,
@@ -636,14 +710,23 @@ def test_ls_broken_dir(tmp_dir, dvc, M):
"isout": False,
"path": "dir.dvc",
"size": M.instance_of(int),
"md5": None,
},
{
"isdir": False,
"isexec": False,
"isout": True,
"path": "foo",
"size": 3,
"md5": "acbd18db4cc2f85cedef654fccc4a4d8",
},
{"isdir": False, "isexec": False, "isout": True, "path": "foo", "size": 3},
{
"isdir": False,
"isexec": False,
"isout": False,
"path": "foo.dvc",
"size": M.instance_of(int),
"md5": None,
},
]