dvc: include cache urls in info output. (#4848)

* dvc: include cache urls in info output.

Show cache urls for external and remote cache in the info output
to assist in diagnosis of issues.

Fixes #4574.

* Remove unnecessary constant check for generator expression.

* Add remotes and caches in version command for better diagnosis.

* Fix flaky unit test to be runtime independent by using regex search.

* Use Cache.by_scheme() for enumerating supported caches.

* Add get_cloud_schemes routine for retrieval of configured remote schemes.

Add tests for local remote and remote:// scheme for info.

* Cleanup unused code.

* info: refactor remote parsing

Co-authored-by: Ruslan Kuprieiev <[email protected]>
This commit is contained in:
Arun Mahapatra
2020-11-19 05:59:33 +02:00
committed by GitHub
co-authored by Ruslan Kuprieiev
parent 251a3269c2
commit 6324bd8a69
4 changed files with 67 additions and 9 deletions
+25 -1
View File
@@ -8,7 +8,7 @@ from dvc.exceptions import DvcException, NotDvcRepoError
from dvc.repo import Repo
from dvc.scm.base import SCMError
from dvc.system import System
from dvc.tree import TREES
from dvc.tree import TREES, get_tree_cls, get_tree_config
from dvc.utils import error_link
from dvc.utils.pkg import PKG
from dvc.version import __version__
@@ -50,6 +50,10 @@ def get_dvc_info():
else:
info.append("Cache types: " + error_link("no-dvc-cache"))
info.append(f"Caches: {_get_caches(repo.cache)}")
info.append(f"Remotes: {_get_remotes(repo.config)}")
except NotDvcRepoError:
pass
except SCMError:
@@ -63,6 +67,26 @@ def get_dvc_info():
return "\n".join(info)
def _get_caches(cache):
caches = (
cache_type
for cache_type, cache_instance in cache.by_scheme()
if cache_instance
)
# Caches will be always non-empty including the local cache
return ", ".join(caches)
def _get_remotes(config):
schemes = (
get_tree_cls(get_tree_config(config, name=remote)).scheme
for remote in config["remote"]
)
return ", ".join(schemes) or "None"
def _get_linktype_support_info(repo):
links = {
+8 -8
View File
@@ -32,23 +32,23 @@ TREES = [
]
def _get_tree(remote_conf):
def get_tree_cls(remote_conf):
for tree_cls in TREES:
if tree_cls.supported(remote_conf):
return tree_cls
return LocalTree
def _get_conf(repo, **kwargs):
def get_tree_config(config, **kwargs):
name = kwargs.get("name")
if name:
remote_conf = repo.config["remote"][name.lower()]
remote_conf = config["remote"][name.lower()]
else:
remote_conf = kwargs
return _resolve_remote_refs(repo, remote_conf)
return _resolve_remote_refs(config, remote_conf)
def _resolve_remote_refs(repo, remote_conf):
def _resolve_remote_refs(config, remote_conf):
# Support for cross referenced remotes.
# This will merge the settings, shadowing base ref with remote_conf.
# For example, having:
@@ -74,7 +74,7 @@ def _resolve_remote_refs(repo, remote_conf):
if parsed.scheme != "remote":
return remote_conf
base = _get_conf(repo, name=parsed.netloc)
base = get_tree_config(config, name=parsed.netloc)
url = posixpath.join(base["url"], parsed.path.lstrip("/"))
return {**base, **remote_conf, "url": url}
@@ -82,9 +82,9 @@ def _resolve_remote_refs(repo, remote_conf):
def get_cloud_tree(repo, **kwargs):
from dvc.config import SCHEMA, ConfigError, Invalid
remote_conf = _get_conf(repo, **kwargs)
remote_conf = get_tree_config(repo.config, **kwargs)
try:
remote_conf = SCHEMA["remote"][str](remote_conf)
except Invalid as exc:
raise ConfigError(str(exc)) from None
return _get_tree(remote_conf)(repo, remote_conf)
return get_tree_cls(remote_conf)(repo, remote_conf)
+2
View File
@@ -11,4 +11,6 @@ def test_(tmp_dir, dvc, scm, caplog):
assert re.search(f"Platform: {PYTHON_VERSION_REGEX} on .*", caplog.text)
assert re.search(r"Supports: .*", caplog.text)
assert re.search(r"Cache types: .*", caplog.text)
assert re.search(r"Caches: local", caplog.text)
assert re.search(r"Remotes: None", caplog.text)
assert "Repo: dvc, git" in caplog.text
+32
View File
@@ -53,6 +53,38 @@ def test_info_in_broken_git_repo(tmp_dir, dvc, scm, caplog):
assert "Repo: dvc, git (broken)" in dvc_info
def test_caches(tmp_dir, dvc, caplog):
tmp_dir.add_remote(
name="sshcache", url="ssh://example.com/path", default=False
)
with tmp_dir.dvc.config.edit() as conf:
conf["cache"]["ssh"] = "sshcache"
dvc_info = get_dvc_info()
# Order of cache types is runtime dependent
assert re.search("Caches: (local, ssh|ssh, local)", dvc_info)
def test_remotes_empty(tmp_dir, dvc, caplog):
# No remotes are configured
dvc_info = get_dvc_info()
assert "Remotes: None" in dvc_info
def test_remotes(tmp_dir, dvc, caplog):
tmp_dir.add_remote(name="server", url="ssh://localhost", default=False)
tmp_dir.add_remote(
name="r1", url="azure://example.com/path", default=False
)
tmp_dir.add_remote(name="r2", url="remote://server/path", default=False)
dvc_info = get_dvc_info()
assert re.search("Remotes: (ssh, azure|azure, ssh)", dvc_info)
@pytest.mark.skipif(psutil is None, reason="No psutil.")
def test_fs_info_in_repo(tmp_dir, dvc, caplog):
os.mkdir(dvc.cache.local.cache_dir)