push/pull/status -c: should warn on no checksum locally and remotely

This commit is contained in:
pared
2019-03-13 17:42:51 +01:00
parent 52cd26f93a
commit e1daa921ee
8 changed files with 130 additions and 27 deletions
+2 -1
View File
@@ -13,6 +13,7 @@ from dvc.exceptions import DvcException, ConfirmRemoveError
STATUS_OK = 1
STATUS_MISSING = 2
STATUS_NEW = 3
STATUS_DELETED = 4
@@ -20,7 +21,7 @@ STATUS_DELETED = 4
STATUS_MAP = {
# (local_exists, remote_exists)
(True, True): STATUS_OK,
(False, False): STATUS_OK,
(False, False): STATUS_MISSING,
(True, False): STATUS_NEW,
(False, True): STATUS_DELETED,
}
+34 -5
View File
@@ -13,7 +13,13 @@ from operator import itemgetter
import dvc.logger as logger
from dvc.system import System
from dvc.remote.base import RemoteBase, STATUS_MAP, STATUS_NEW, STATUS_DELETED
from dvc.remote.base import (
RemoteBase,
STATUS_MAP,
STATUS_NEW,
STATUS_DELETED,
STATUS_MISSING,
)
from dvc.utils import remove, move, copyfile, dict_md5, to_chunks, tmp_fname
from dvc.utils import LARGE_DIR_SIZE
from dvc.config import Config
@@ -590,13 +596,17 @@ class RemoteLOCAL(RemoteBase):
progress.finish_target(title)
for md5, info in ret.items():
info["status"] = STATUS_MAP[
(md5 in local_exists, md5 in remote_exists)
]
self._fill_statuses(ret, local_exists, remote_exists)
self._log_missing_caches(ret)
return ret
def _fill_statuses(self, checksum_info_dir, local_exists, remote_exists):
for md5, info in checksum_info_dir.items():
status = STATUS_MAP[(md5 in local_exists, md5 in remote_exists)]
info["status"] = status
def _get_chunks(self, download, remote, status_info, status, jobs):
title = "Analysing status."
@@ -710,3 +720,22 @@ class RemoteLOCAL(RemoteBase):
return not (mtime == cached_mtime and size == cached_size)
return True
def _log_missing_caches(self, checksum_info_dict):
missing_caches = [
(md5, info)
for md5, info in checksum_info_dict.items()
if info["status"] == STATUS_MISSING
]
if missing_caches:
missing_desc = "".join(
[
"\nname: {}, md5: {}".format(info["name"], md5)
for md5, info in missing_caches
]
)
msg = (
"Some of the cache files do not exist neither locally "
"nor on remote. Missing cache files: {}".format(missing_desc)
)
logger.warning(msg)
+2 -3
View File
@@ -1,7 +1,6 @@
from __future__ import unicode_literals
import os
from dvc.utils.compat import StringIO
import dvc
import time
@@ -21,7 +20,7 @@ from dvc.output.base import OutputAlreadyTrackedError
from dvc.repo import Repo as DvcRepo
from tests.basic_env import TestDvc
from tests.utils import spy, get_gitignore_content
from tests.utils import spy, reset_logger_error_output, get_gitignore_content
from tests.utils.logger import MockLoggerHandlers, ConsoleFontColorsRemover
@@ -410,7 +409,7 @@ class TestShouldPlaceStageInDataDirIfRepositoryBelowSymlink(TestDvc):
class TestShouldThrowProperExceptionOnCorruptedStageFile(TestDvc):
def test(self):
with MockLoggerHandlers(logger), ConsoleFontColorsRemover():
logger.handlers[1].stream = StringIO()
reset_logger_error_output()
ret = main(["add", self.FOO])
self.assertEqual(0, ret)
+68 -6
View File
@@ -13,7 +13,7 @@ from dvc.state import State
from mock import patch
from tests.utils.logger import MockLoggerHandlers, ConsoleFontColorsRemover
import dvc.logger as logger
from dvc.logger import logger
from dvc.utils.compat import str
from dvc.main import main
from dvc.config import Config
@@ -31,9 +31,12 @@ from dvc.remote.base import STATUS_OK, STATUS_NEW, STATUS_DELETED
from dvc.utils import file_md5, load_stage_file
from tests.basic_env import TestDvc
from tests.utils import spy
from tests.utils import (
spy,
reset_logger_standard_output,
reset_logger_error_output,
)
from dvc.utils.compat import StringIO
TEST_REMOTE = "upstream"
TEST_SECTION = 'remote "{}"'.format(TEST_REMOTE)
@@ -635,15 +638,15 @@ class TestWarnOnOutdatedStage(TestDvc):
with open(stage_file_path, "w") as stage_file:
yaml.dump(content, stage_file)
with MockLoggerHandlers(logger.logger):
logger.logger.handlers[0].stream = StringIO()
with MockLoggerHandlers(logger):
reset_logger_standard_output()
self.main(["status", "-c"])
self.assertIn(
"Warning: Output 'bar'(Stage: 'bar.dvc') is "
"missing version info. Cache for it will not be "
"collected. Use dvc repro to get your pipeline up to "
"date.",
logger.logger.handlers[0].stream.getvalue(),
logger.handlers[0].stream.getvalue(),
)
def test(self):
@@ -749,3 +752,62 @@ class TestCheckSumRecalculation(TestDvc):
ret = main(["run", "-d", self.FOO, "echo foo"])
self.assertEqual(ret, 0)
self.assertEqual(test_collect.mock.call_count, 1)
class TestShouldWarnOnNoChecksumInLocalAndRemoteCache(TestDvc):
def setUp(self):
super(TestShouldWarnOnNoChecksumInLocalAndRemoteCache, self).setUp()
cache_dir = self.mkdtemp()
ret = main(["add", self.FOO])
self.assertEqual(0, ret)
ret = main(["add", self.BAR])
self.assertEqual(0, ret)
# purge cache
shutil.rmtree(self.dvc.cache.local.cache_dir)
ret = main(["remote", "add", "remote_name", "-d", cache_dir])
self.assertEqual(0, ret)
checksum_foo = file_md5(self.FOO)[0]
checksum_bar = file_md5(self.BAR)[0]
self.message_header = (
"Some of the cache files do not exist neither locally "
"nor on remote. Missing cache files: \n"
)
self.message_bar_part = "\nname: {}, md5: {}\n".format(
self.BAR, checksum_bar
)
self.message_foo_part = "\nname: {}, md5: {}\n".format(
self.FOO, checksum_foo
)
def stderr_contains_message(self):
self.assertIn(
self.message_header, logger.handlers[1].stream.getvalue()
)
self.assertIn(
self.message_foo_part, logger.handlers[1].stream.getvalue()
)
self.assertIn(
self.message_bar_part, logger.handlers[1].stream.getvalue()
)
def test(self):
with ConsoleFontColorsRemover(), MockLoggerHandlers(logger):
reset_logger_error_output()
main(["push"])
self.stderr_contains_message()
reset_logger_error_output()
main(["pull"])
self.stderr_contains_message()
reset_logger_error_output()
main(["status", "-c"])
self.stderr_contains_message()
+2 -3
View File
@@ -9,11 +9,10 @@ from dvc.exceptions import DvcException
from dvc.main import main
from mock import patch, mock_open, call
from tests.basic_env import TestDvc
from tests.utils import reset_logger_error_output
from tests.utils.httpd import StaticFileServer
from tests.utils.logger import MockLoggerHandlers, ConsoleFontColorsRemover
from dvc.utils.compat import StringIO
class TestCmdImport(TestDvc):
def test(self):
@@ -52,7 +51,7 @@ class TestFailedImportMessage(TestDvc):
@patch("dvc.command.imp.urlparse")
def _test(self, imp_urlparse_patch):
with MockLoggerHandlers(logger.logger):
logger.logger.handlers[1].stream = StringIO()
reset_logger_error_output()
page_address = "http://somesite.com/file_name"
def dvc_exception(*args, **kwargs):
+3 -3
View File
@@ -5,7 +5,7 @@ import logging
import dvc.logger as logger
from dvc.command.base import CmdBase
from dvc.exceptions import DvcException
from dvc.utils.compat import StringIO
from tests.utils import reset_logger_error_output, reset_logger_standard_output
from tests.utils.logger import ConsoleFontColorsRemover
@@ -17,8 +17,8 @@ class TestLogger(TestCase):
logger.logging.StreamHandler(),
logger.logging.StreamHandler(),
]
logger.logger.handlers[0].stream = StringIO()
logger.logger.handlers[1].stream = StringIO()
reset_logger_standard_output()
reset_logger_error_output()
logger.set_default_level()
self.consoleColorRemover = ConsoleFontColorsRemover()
+6 -6
View File
@@ -7,7 +7,7 @@ from dvc.exceptions import DvcException, BadMetricError, NoMetricsError
from tests.basic_env import TestDvc
import dvc.logger as logger
from dvc.utils.compat import StringIO
from tests.utils import reset_logger_error_output, reset_logger_standard_output
from tests.utils.logger import MockLoggerHandlers
@@ -359,7 +359,7 @@ class TestMetricsCLI(TestMetrics):
self.assertEqual(ret, 0)
with MockLoggerHandlers(logger.logger):
logger.logger.handlers[1].stream = StringIO()
reset_logger_error_output()
ret = main(["metrics", "add", "metric.unknown", "-t", "unknown"])
self.assertEqual(ret, 1)
self.assertIn(
@@ -372,7 +372,7 @@ class TestMetricsCLI(TestMetrics):
ret = main(["metrics", "add", "metric.unknown", "-t", "raw"])
self.assertEqual(ret, 0)
logger.logger.handlers[0].stream = StringIO()
reset_logger_standard_output()
ret = main(["metrics", "show", "metric.unknown"])
self.assertEqual(ret, 0)
self.assertIn(
@@ -389,7 +389,7 @@ class TestMetricsCLI(TestMetrics):
self.assertEqual(ret, 0)
with MockLoggerHandlers(logger.logger):
logger.logger.handlers[1].stream = StringIO()
reset_logger_error_output()
ret = main(
["metrics", "modify", "metric.unknown", "-t", "unknown"]
)
@@ -404,7 +404,7 @@ class TestMetricsCLI(TestMetrics):
ret = main(["metrics", "modify", "metric.unknown", "-t", "CSV"])
self.assertEqual(ret, 0)
logger.logger.handlers[0].stream = StringIO()
reset_logger_standard_output()
ret = main(["metrics", "show", "metric.unknown"])
self.assertEqual(ret, 0)
self.assertIn(
@@ -421,7 +421,7 @@ class TestMetricsCLI(TestMetrics):
self.assertEqual(ret, 0)
with MockLoggerHandlers(logger.logger):
logger.logger.handlers[0].stream = StringIO()
reset_logger_standard_output()
ret = main(
[
"metrics",
+13
View File
@@ -2,6 +2,7 @@ import yaml
import os
from dvc.scm import Git
from dvc.utils.compat import StringIO
from mock import MagicMock
from contextlib import contextmanager
@@ -27,6 +28,18 @@ def load_stage_file(path):
return yaml.safe_load(fobj)
def reset_logger_error_output():
from dvc.logger import logger
logger.handlers[1].stream = StringIO()
def reset_logger_standard_output():
from dvc.logger import logger
logger.handlers[0].stream = StringIO()
@contextmanager
def cd(newdir):
prevdir = os.getcwd()