From 688bcaa0e3ca3c67d44c9cf31862f3afc8124e71 Mon Sep 17 00:00:00 2001 From: Aman Sharma Date: Sat, 1 Jun 2019 17:10:59 +0530 Subject: [PATCH] Add info for link type and filesystem name (#1997) * Add info for link and filesystem type * Remove unnecessary `repo_dir` fixture * Add cache info * Classify `test_version.py` as functional test * Remove redundancy * Optimize some functions involved * Add pathlib2 to install_requires * Display fs type for cache directory * Use `dvc.utils.compat` to import Path * Remove redundancy in tests and make logs more descriptive --- dvc/command/version.py | 80 ++++++++++++++++++++++++++++-- setup.py | 1 + tests/func/test_version.py | 37 ++++++++++++++ tests/unit/command/test_version.py | 25 ---------- 4 files changed, 114 insertions(+), 29 deletions(-) create mode 100644 tests/func/test_version.py delete mode 100644 tests/unit/command/test_version.py diff --git a/dvc/command/version.py b/dvc/command/version.py index 7b17c8f53..34be52980 100644 --- a/dvc/command/version.py +++ b/dvc/command/version.py @@ -1,11 +1,18 @@ from __future__ import unicode_literals +import os +import psutil import platform import argparse import logging +import uuid +from dvc.utils.compat import Path +from dvc.repo import Repo from dvc.command.base import CmdBaseNoRepo, append_doc_link from dvc.version import __version__ +from dvc.exceptions import DvcException, NotDvcRepoError +from dvc.system import System logger = logging.getLogger(__name__) @@ -13,18 +20,83 @@ logger = logging.getLogger(__name__) class CmdVersion(CmdBaseNoRepo): def run(self): + dvc_version = __version__ + python_version = platform.python_version() + platform_type = platform.platform() + info = ( "DVC version: {dvc_version}\n" "Python version: {python_version}\n" - "Platform: {platform_type}" + "Platform: {platform_type}\n" ).format( - dvc_version=__version__, - python_version=platform.python_version(), - platform_type=platform.platform(), + dvc_version=dvc_version, + python_version=python_version, + platform_type=platform_type, + ) + + try: + repo = Repo() + root_directory = repo.root_dir + + info += ( + "Cache: {cache}\n" + "Filesystem type (cache directory): {fs_cache}\n" + ).format( + cache=self.get_linktype_support_info(repo), + fs_cache=self.get_fs_type(repo.cache.local.cache_dir), + ) + + except NotDvcRepoError: + root_directory = os.getcwd() + + info += ("Filesystem type (workspace): {fs_root}").format( + fs_root=self.get_fs_type(os.path.abspath(root_directory)) ) logger.info(info) return 0 + @staticmethod + def get_fs_type(path): + partition = { + Path(part.mountpoint): (part.fstype, part.device) + for part in psutil.disk_partitions() + } + for parent in list(Path(path).parents): + if parent in partition: + return partition[parent] + return ("unkown", "none") + + @staticmethod + def get_linktype_support_info(repo): + links = { + "reflink": System.reflink, + "hardlink": System.hardlink, + "symlink": System.symlink, + } + + fname = "." + str(uuid.uuid4()) + src = os.path.join(repo.cache.local.cache_dir, fname) + open(src, "w").close() + dst = os.path.join(repo.root_dir, fname) + + cache = [] + + for name, link in links.items(): + try: + link(src, dst) + os.unlink(dst) + supported = True + except DvcException: + supported = False + cache.append( + "{name} - {supported}".format( + name=name, supported=True if supported else False + ) + ) + os.remove(src) + + return ", ".join(cache) + def add_parser(subparsers, parent_parser): VERSION_HELP = "Show DVC version and system/environment informaion." diff --git a/setup.py b/setup.py index 6eda216c7..16011e881 100644 --- a/setup.py +++ b/setup.py @@ -60,6 +60,7 @@ install_requires = [ "humanize>=0.5.1", "dulwich>=0.19.11", "ruamel.yaml>=0.15.91", + "psutil==5.6.2", ] # Extra dependencies for remote integrations diff --git a/tests/func/test_version.py b/tests/func/test_version.py new file mode 100644 index 000000000..a9089c502 --- /dev/null +++ b/tests/func/test_version.py @@ -0,0 +1,37 @@ +import re + +from dvc.main import main + + +def test_info_in_repo(dvc_repo, caplog): + assert main(["version"]) == 0 + + assert re.search(re.compile(r"DVC version: \d+\.\d+\.\d+"), caplog.text) + assert re.search(re.compile(r"Python version: \d\.\d\.\d"), caplog.text) + assert re.search(re.compile(r"Platform: .*"), caplog.text) + assert re.search( + re.compile(r"Filesystem type \(cache directory\): .*"), caplog.text + ) + assert re.search( + re.compile(r"Filesystem type \(workspace\): .*"), caplog.text + ) + assert re.search( + re.compile(r"(Cache: (.*link - (True|False)(,\s)?){3})"), caplog.text + ) + + +def test_info_outside_of_repo(repo_dir, caplog): + assert main(["version"]) == 0 + + assert re.search(re.compile(r"DVC version: \d+\.\d+\.\d+"), caplog.text) + assert re.search(re.compile(r"Python version: \d\.\d\.\d"), caplog.text) + assert re.search(re.compile(r"Platform: .*"), caplog.text) + assert re.search( + re.compile(r"Filesystem type \(workspace\): .*"), caplog.text + ) + assert not re.search( + re.compile(r"Filesystem type \(cache directory\): .*"), caplog.text + ) + assert not re.search( + re.compile(r"(Cache: (.*link - (True|False)(,\s)?){3})"), caplog.text + ) diff --git a/tests/unit/command/test_version.py b/tests/unit/command/test_version.py deleted file mode 100644 index 57c9184b5..000000000 --- a/tests/unit/command/test_version.py +++ /dev/null @@ -1,25 +0,0 @@ -import re - -from dvc.command.version import CmdVersion -from dvc.cli import parse_args - - -def test_run_in_repo(repo_dir, dvc_repo): - cmd = CmdVersion(parse_args(["version"])) - ret = cmd.run_cmd() - assert ret == 0 - - -def test_run_outside_of_repo(repo_dir): - cmd = CmdVersion(parse_args(["version"])) - ret = cmd.run_cmd() - assert ret == 0 - - -def test_info(caplog): - cmd = CmdVersion(parse_args(["version"])) - cmd.run() - - assert re.search(re.compile(r"DVC version: \d+\.\d+\.\d+"), caplog.text) - assert re.search(re.compile(r"Python version: \d\.\d\.\d"), caplog.text) - assert re.search(re.compile(r"Platform: .*"), caplog.text)