Files
dvc/dvc/command/diff.py
T

139 lines
4.9 KiB
Python

from __future__ import unicode_literals
import humanize
import inflect
import dvc.logger as logger
from dvc.exceptions import DvcException
from dvc.command.base import CmdBase
from dvc.utils.collections import compact
import dvc.repo.diff as diff
class CmdDiff(CmdBase):
def _print_size(self, size):
if size < 0:
change = "decreased by {}"
elif size > 0:
change = "increased by {}"
else:
change = "not changed"
natur_size = humanize.naturalsize(abs(size))
return change.format(natur_size)
def _show(self, diff_dct):
engine = inflect.engine()
msg = "dvc diff from {} to {}".format(
diff_dct[diff.DIFF_A_REF], diff_dct[diff.DIFF_B_REF]
)
if diff_dct.get(diff.DIFF_EQUAL):
logger.info(msg)
return
for dct in diff_dct[diff.DIFF_LIST]:
msg += "\n\ndiff for '{}'\n".format(dct[diff.DIFF_TARGET])
if dct.get(diff.DIFF_OLD_FILE):
msg += "-{} with md5 {}\n".format(
dct[diff.DIFF_OLD_FILE], dct[diff.DIFF_OLD_CHECKSUM]
)
if dct.get(diff.DIFF_NEW_FILE):
msg += "+{} with md5 {}\n".format(
dct[diff.DIFF_NEW_FILE], dct[diff.DIFF_NEW_CHECKSUM]
)
msg += "\n"
if dct[diff.DIFF_SIZE] != diff.DIFF_SIZE_UNKNOWN:
if dct.get("is_dir"):
msg += "{} {} not changed, ".format(
dct[diff.DIFF_IDENT],
engine.plural("file", dct[diff.DIFF_IDENT]),
)
msg += "{} {} modified, ".format(
dct[diff.DIFF_CHANGE],
engine.plural("file", dct[diff.DIFF_CHANGE]),
)
msg += "{} {} added, ".format(
dct[diff.DIFF_NEW],
engine.plural("file", dct[diff.DIFF_NEW]),
)
msg += "{} {} deleted, ".format(
dct[diff.DIFF_DEL],
engine.plural("file", dct[diff.DIFF_DEL]),
)
msg += "size was {}".format(
self._print_size(dct[diff.DIFF_SIZE])
)
else:
if (
dct.get(diff.DIFF_OLD_FILE)
and dct.get(diff.DIFF_NEW_FILE)
and dct[diff.DIFF_SIZE] == 0
):
msg += "file size was not changed"
elif dct.get(diff.DIFF_NEW_FILE):
msg += "added file with size {}".format(
humanize.naturalsize(dct[diff.DIFF_SIZE])
)
elif dct.get(diff.DIFF_OLD_FILE):
msg += "deleted file with size {}".format(
humanize.naturalsize(abs(dct[diff.DIFF_SIZE]))
)
else:
msg += "file was modified, file size {}".format(
self._print_size(dct[diff.DIFF_SIZE])
)
else:
msg += "size is ?"
logger.info(msg)
return msg
def run(self):
try:
msg = self.repo.diff(
self.args.a_ref, target=self.args.target, b_ref=self.args.b_ref
)
self._show(msg)
except DvcException:
msg = "failed to get 'diff {}'"
args = " ".join(
compact([self.args.target, self.args.a_ref, self.args.b_ref])
)
msg = msg.format(args)
logger.error(msg)
return 1
return 0
def add_parser(subparsers, parent_parser):
description = (
"Show diff of a data file or a directory that "
"is under DVC control. Some basic statistics "
"summary, how many files were deleted/changed."
)
help = "Show a diff of a DVC controlled data file or a directory."
diff_parser = subparsers.add_parser(
"diff", parents=[parent_parser], description=description, help=help
)
diff_parser.add_argument(
"-t",
"--target",
default=None,
help=(
"Source path to a data file or directory. Default None,"
"If not specified, compares all files and directories "
"that are under DVC control in the current working space."
),
)
diff_parser.add_argument(
"a_ref", help="Git reference from which diff calculates"
)
diff_parser.add_argument(
"b_ref",
help=(
"Git reference till which diff calculates, if omitted "
"diff shows the difference between current HEAD and a_ref"
),
nargs="?",
default=None,
)
diff_parser.set_defaults(func=CmdDiff)