Files
dvc/dvc/command/diff.py
T
Puneetha Pai c31ec3038a diff: Add sort logic to sort diff ouput irrespective of output format… (#4459)
* diff: Add sort logic to sort diff ouput irrespective of output format(default/json/md)

* diff: test stub using actual value, not pass by reference for (dict)
2020-08-26 19:35:06 +03:00

182 lines
5.1 KiB
Python

import argparse
import json
import logging
import os
import colorama
from dvc.command.base import CmdBase, append_doc_link
from dvc.exceptions import DvcException
logger = logging.getLogger(__name__)
def _digest(checksum):
if isinstance(checksum, str):
return checksum[0:8]
return "{}..{}".format(checksum["old"][0:8], checksum["new"][0:8])
def _show_md(diff, show_hash=False):
from dvc.utils.diff import table
header = ["Status", "Hash", "Path"] if show_hash else ["Status", "Path"]
rows = []
for status in ["added", "deleted", "modified"]:
entries = diff.get(status, [])
if not entries:
continue
for entry in entries:
path = entry["path"]
if show_hash:
check_sum = _digest(entry.get("hash", ""))
rows.append([status, check_sum, path])
else:
rows.append([status, path])
return table(header, rows, True)
class CmdDiff(CmdBase):
@staticmethod
def _format(diff):
"""
Given a diff structure, generate a string of paths separated
by new lines and grouped together by their state.
A group's header is colored to enhance readability, for example:
Added:
another_file.txt
backup.tar
dir/
dir/1
An example of a diff formatted when entries contain hash:
Added:
d3b07384 foo
Modified:
c157a790..f98bf6f1 bar
If a group has no entries, it won't be included in the result.
At the bottom, include a summary with the number of files per state.
"""
colors = {
"added": colorama.Fore.GREEN,
"modified": colorama.Fore.YELLOW,
"deleted": colorama.Fore.RED,
}
summary = {}
groups = []
for state in ["added", "deleted", "modified"]:
summary[state] = 0
entries = diff[state]
if not entries:
continue
content = []
for entry in entries:
path = entry["path"]
checksum = entry.get("hash")
summary[state] += 1 if not path.endswith(os.sep) else 0
content.append(
"{space}{checksum}{separator}{path}".format(
space=" ",
checksum=_digest(checksum) if checksum else "",
separator=" " if checksum else "",
path=entry["path"],
)
)
groups.append(
"{color}{header}{nc}:\n{content}".format(
color=colors[state],
header=state.capitalize(),
nc=colorama.Fore.RESET,
content="\n".join(content),
)
)
groups.append(
"files summary: {added} added, {deleted} deleted,"
" {modified} modified".format_map(summary)
)
return "\n\n".join(groups)
def run(self):
try:
diff = self.repo.diff(self.args.a_rev, self.args.b_rev)
show_hash = self.args.show_hash
for key, entries in diff.items():
entries = sorted(entries, key=lambda entry: entry["path"])
if not show_hash:
for entry in entries:
del entry["hash"]
diff[key] = entries
if self.args.show_json:
logger.info(json.dumps(diff))
elif self.args.show_md:
logger.info(_show_md(diff, show_hash))
elif diff:
logger.info(self._format(diff))
except DvcException:
logger.exception("failed to get diff")
return 1
return 0
def add_parser(subparsers, parent_parser):
DIFF_DESCRIPTION = (
"Show added, modified, or deleted data between commits in the DVC"
" repository, or between a commit and the workspace."
)
diff_parser = subparsers.add_parser(
"diff",
parents=[parent_parser],
description=append_doc_link(DIFF_DESCRIPTION, "diff"),
help=DIFF_DESCRIPTION,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
diff_parser.add_argument(
"a_rev",
help="Old Git commit to compare (defaults to HEAD)",
nargs="?",
default="HEAD",
)
diff_parser.add_argument(
"b_rev",
help=("New Git commit to compare (defaults to the current workspace)"),
nargs="?",
)
diff_parser.add_argument(
"--show-json",
help="Format the output into a JSON",
action="store_true",
default=False,
)
diff_parser.add_argument(
"--show-hash",
help="Display hash value for each entry",
action="store_true",
default=False,
)
diff_parser.add_argument(
"--show-md",
help="Show tabulated output in the Markdown format (GFM).",
action="store_true",
default=False,
)
diff_parser.set_defaults(func=CmdDiff)