diff --git a/dvc/command/diff.py b/dvc/command/diff.py index df576c8df..7ec4f24f3 100644 --- a/dvc/command/diff.py +++ b/dvc/command/diff.py @@ -11,7 +11,9 @@ logger = logging.getLogger(__name__) class CmdDiff(CmdBase): def run(self): try: - self.repo.diff(self.args.a_ref, self.args.b_ref, self.args.target) + self.repo.diff( + self.args.a_ref, self.args.b_ref, target=self.args.target + ) except DvcException: logger.exception("failed to get 'diff {}'") return 1 diff --git a/dvc/repo/diff.py b/dvc/repo/diff.py index 9d3604e6c..2f709f401 100644 --- a/dvc/repo/diff.py +++ b/dvc/repo/diff.py @@ -7,6 +7,7 @@ from dvc.compat import fspath Diffable = collections.namedtuple("Diffable", "filename, checksum, size") Diffable.__doc__ = "Common interface for comparable entries." +Diffable._asdict = lambda x: {"checksum": x.checksum, "size": x.size} def diffable_from_output(output): @@ -18,6 +19,21 @@ def diffable_from_output(output): return Diffable(filename=str(output), checksum=output.checksum, size=size) +def compare_states(old, new): + if old and new: + try: + size = new["size"] - old["size"] + except KeyError: + size = "unknown" + return {"status": "modified", "size": size} + + if old and not new: + return {"status": "deleted", "size": old.get("size", "unknown")} + + if not old and new: + return {"status": "added", "size": new.get("size", "unknown")} + + @locked def diff(self, a_ref="HEAD", b_ref=None, *, target=None): """ @@ -44,10 +60,15 @@ def diff(self, a_ref="HEAD", b_ref=None, *, target=None): if not delta: return - old &= delta - new &= delta + result = {} - return { - "old": [entry._asdict() for entry in old], - "new": [entry._asdict() for entry in new], - } + for entry in delta: + result[entry.filename] = { + "old": entry._asdict() if entry in old else {}, + "new": entry._asdict() if entry in new else {}, + } + + for filename, entry in result.items(): + entry.update({"diff": compare_states(entry["old"], entry["new"])}) + + return result diff --git a/tests/func/test_diff.py b/tests/func/test_diff.py index e4662a471..4a26af369 100644 --- a/tests/func/test_diff.py +++ b/tests/func/test_diff.py @@ -11,14 +11,11 @@ def test_added(tmp_dir, scm, dvc): tmp_dir.dvc_gen("file", "text") result = { - "old": [], - "new": [ - { - "filename": "file", - "checksum": "1cb251ec0d568de6a929b520c4aed8d1", - "size": 4, - } - ], + "file": { + "old": {}, + "new": {"checksum": "1cb251ec0d568de6a929b520c4aed8d1", "size": 4}, + "diff": {"status": "added", "size": 4}, + } } assert result == dvc.diff() @@ -26,17 +23,14 @@ def test_added(tmp_dir, scm, dvc): def test_deleted(tmp_dir, scm, dvc): tmp_dir.dvc_gen("file", "text", commit="add file") - (tmp_dir / "file").unlink() + (tmp_dir / "file.dvc").unlink() result = { - "old": [ - { - "filename": "file", - "checksum": "1cb251ec0d568de6a929b520c4aed8d1", - "size": 4, - } - ], - "new": [], + "file": { + "old": {"checksum": "1cb251ec0d568de6a929b520c4aed8d1", "size": 4}, + "new": {}, + "diff": {"status": "deleted", "size": 4}, + } } assert result == dvc.diff() @@ -47,20 +41,11 @@ def test_modified(tmp_dir, scm, dvc): tmp_dir.dvc_gen("file", "second") result = { - "old": [ - { - "filename": "file", - "checksum": "8b04d5e3775d298e78455efc5ca404d5", - "size": 6, - } - ], - "new": [ - { - "filename": "file", - "checksum": "a9f0e61a137d86aa9db53465e0801612", - "size": 6, - } - ], + "file": { + "old": {"checksum": "8b04d5e3775d298e78455efc5ca404d5", "size": 6}, + "new": {}, + "diff": {"status": "deleted", "size": 6}, + } } assert result == dvc.diff()