Repository: iterative/dvc

Issue:
version: redesign output
Current `dvc version` output is ugly, we could definitely do better:

```
DVC version: 0.89.0+9e96dd
Python version: 3.7.0
Platform: Linux-4.15.0-88-generic-x86_64-with-debian-buster-sid
Binary: False
Package: None
Supported remotes: azure, gdrive, gs, hdfs, http, https, s3, ssh, oss
Cache: reflink - not supported, hardlink - supported, symlink - supported
Filesystem type (cache directory): ('ext4', '/dev/sda1')
Filesystem type (workspace): ('ext4', '/dev/sda1')
```

Related https://github.com/iterative/dvc/issues/3185 


Discussion:
maybe something like this yaml (btw need to look into possibly unifying analytics collection with this):
```
DVC: 0.89.0+9e96dd                                             
Python: 3.7.0                                                  
Platform: Linux-4.15.0-88-generic-x86_64-with-debian-buster-sid
Binary: False                                                  
Package: pip                                                   
Remotes:                                                       
  azure: supported                                             
  gdrive: supported                                            
  gs: supported                                                
  hdfs: supported                                              
  http: supported                                              
  https: supported                                             
  s3: not supported                                            
  ssh: supported                                               
  oss: supported                                               
Links:                                                         
  reflink: not supported                                       
  hardlink: supported                                          
  symlink: supported                                           
Cache:                                                         
  fs: ext4                                                     
  mnt: /dev/sda1                                               
Workspace:                                                     
  fs: ext4                                                     
  mnt: /dev/sda1                                               
```
easilly greppable and json-compatible.

Could also use some colors to highlight stuff 

Hi, Is there anyone working on this issue. if not then can I work on this issue?
@sahilbhosale63 Sure! Let's start by discussing the output format in this ticket, so that we are on the same page and then, once we agree, we could proceed implementing it in the code. Thank you! :pray: 
Yes, Let's start.
Can you please provide me with the path to the file where this code resides?
Hi @sahilbhosale63, version command is here: [dvc/command/version.py](https://github.com/iterative/dvc/blob/master/dvc/command/version.py).

@sahilbhosale63, it'd be great to see example output before implementing. What do you have in mind?

Also, feel free to discuss this here and/or [in chat](https://dvc.org/chat) on `#dev-talk` channel, we'll be happy to help you.
Currently I don't have any ideas in my mind. I think the output format suggested by @efiop will be the best fit. And surely I will try to modify the output format and according let you know if any idea looks good to me and after that we can have a discussion.
@sahilbhosale63 That was just a random suggestion, I admittedly didn't think about it too much. But that could be a good start and it definitely more informative than it is right now. If there are no other suggestions, please feel free to give it a shot.
![Screenshot from 2020-06-23 16-41-21](https://user-images.githubusercontent.com/21124445/85397663-942b0280-b571-11ea-9cb7-9d21706523b0.png)

This is the change which I have made. @efiop What do you think of it? Would you like to give any suggestions on this?
@sahilbhosale63 That looks good! Please feel free to submit a PR. Thank you! :pray: 
@sahilbhosale63, @efiop, I think we should try making the output format human-readable rather than longer. For me, and the team, the important use case of `dvc version` is to help/debug other users' issues. Making it longer only makes it cumbersome to share/read.

How about something like this:
```
DVC version: 0.89.0+9e96dd
---------------------------------------

Build Info: Python3.7 on Linux, installed via pip
Supports: All remotes and cache types
Repo: dvc + git, workspace with 'ext4' on '/dev/sda1'
Cache: ext4 on '/dev/sda1'
```

There's a room for improvement of ^ for sure. 


@skshetry Sure, that looks pretty good! @sahilbhosale63 would you be up for changing the output to that new format?
Sure @efiop, I will make the above change to a new format as suggested by @skshetry
can we do something with that ugly warning? can we embed it into the `Cache type: (no cache dir)`?
![Screenshot from 2020-06-24 12-21-06](https://user-images.githubusercontent.com/21124445/85511436-3c92a280-b616-11ea-952c-0e7dda70a715.png)

Here, the "**Supports**" and "**Cache**" lines highlighted in red in the above img should come in a single line under "Supports"as suggested by @skshetry. 

But the thing is some remotes or caches might not be supported in some systems. As in this case, **reflink is not supported**. So, here we can't just put the msg as "**Supports: All remotes and cache types**". 

So what should be done here?
@sahilbhosale63, most of the times, dvc will either support all of the remotes or any one of them (two or three if there's already some dependencies installed but rare). And, `http/https` are always supported by default.
So, we could optimize these for usual scenarios and make it a bit ugly for rare scenarios.

Also, I'm fine with the following:
```console
# Single remote:
Supports: gs remote, and hardlink/symlink cache types
# if it supports all remotes:
Supports: All remotes and reflink/hardlink/symlink cache types
# if it supports most of the remotes, but not all, we can make it a bit ugly as it is a rare scenario:
Supports: gs, azure, hdfs, azure, oss, ssh, gdrive remotes and reflink/hardlink/symlink cache types
```

As you can see, the last example is a bit lengthy. Also @sahilbhosale63, feel free to change the output format
wherever it does not make sense or if it could be improve further.

Thanks a lot for taking the task. :+1: 

![Screenshot from 2020-06-24 16-15-08](https://user-images.githubusercontent.com/21124445/85543449-b5eebd00-b637-11ea-8db7-166e18955d68.png)

I have made the required changes. The only think which I want to ask is there is a line break after the end of this line **"Supports: All remotes"** because of this line of code `logger.info("\n".join(info))`

The code adds a line break after every sentence but I don't want a line break after  **"Supports: All remotes"** so that the output would look like this **"Supports: All remotes and hardlink/ symlink cache types"** in a one single line.

So is there anyway we can achieve that in python??

@skshetry what should we do if we can't test for link type support?

I feel that we should not mix this information. Remotes are remotes, links are links - they are different, not related to each, so why do we show them in a single line?

Patch:
diff --git a/dvc/command/version.py b/dvc/command/version.py
--- a/dvc/command/version.py
+++ b/dvc/command/version.py
@@ -10,7 +10,7 @@
 from dvc.exceptions import DvcException, NotDvcRepoError
 from dvc.scm.base import SCMError
 from dvc.system import System
-from dvc.utils import is_binary, relpath
+from dvc.utils import relpath
 from dvc.utils.pkg import PKG
 from dvc.version import __version__
 
@@ -27,13 +27,18 @@ class CmdVersion(CmdBaseNoRepo):
     def run(self):
         from dvc.repo import Repo
 
+        package = PKG
+        if PKG is None:
+            package = ""
+        else:
+            package = f"({PKG})"
+
         info = [
-            f"DVC version: {__version__}",
-            f"Python version: {platform.python_version()}",
-            f"Platform: {platform.platform()}",
-            f"Binary: {is_binary()}",
-            f"Package: {PKG}",
-            f"Supported remotes: {self.get_supported_remotes()}",
+            f"DVC version: {__version__} {package}",
+            "---------------------------------",
+            f"Platform: Python {platform.python_version()} on "
+            f"{platform.platform()}",
+            f"Supports: {self.get_supported_remotes()}",
         ]
 
         try:
@@ -46,13 +51,13 @@ def run(self):
             # `dvc config cache.shared group`.
             if os.path.exists(repo.cache.local.cache_dir):
                 info.append(
-                    "Cache: {}".format(self.get_linktype_support_info(repo))
+                    "Cache types: {}".format(
+                        self.get_linktype_support_info(repo)
+                    )
                 )
                 if psutil:
                     fs_type = self.get_fs_type(repo.cache.local.cache_dir)
-                    info.append(
-                        f"Filesystem type (cache directory): {fs_type}"
-                    )
+                    info.append(f"Cache directory: {fs_type}")
             else:
                 logger.warning(
                     "Unable to detect supported link types, as cache "
@@ -68,11 +73,11 @@ def run(self):
             root_directory = os.getcwd()
             info.append("Repo: dvc, git (broken)")
         else:
-            info.append("Repo: {}".format(_get_dvc_repo_info(repo)))
+            if psutil:
+                fs_root = self.get_fs_type(os.path.abspath(root_directory))
+                info.append(f"Workspace directory: {fs_root}")
 
-        if psutil:
-            fs_root = self.get_fs_type(os.path.abspath(root_directory))
-            info.append(f"Filesystem type (workspace): {fs_root}")
+            info.append("Repo: {}".format(_get_dvc_repo_info(repo)))
 
         logger.info("\n".join(info))
         return 0
@@ -80,7 +85,7 @@ def run(self):
     @staticmethod
     def get_fs_type(path):
         partition = {
-            pathlib.Path(part.mountpoint): (part.fstype, part.device)
+            pathlib.Path(part.mountpoint): (part.fstype + " on " + part.device)
             for part in psutil.disk_partitions(all=True)
         }
 
@@ -115,7 +120,9 @@ def get_linktype_support_info(repo):
                 os.unlink(dst)
             except DvcException:
                 status = "not supported"
-            cache.append(f"{name} - {status}")
+
+            if status == "supported":
+                cache.append(name)
         os.remove(src)
 
         return ", ".join(cache)
@@ -129,6 +136,12 @@ def get_supported_remotes():
             if not tree_cls.get_missing_deps():
                 supported_remotes.append(tree_cls.scheme)
 
+        if len(supported_remotes) == len(TREES):
+            return "All remotes"
+
+        if len(supported_remotes) == 1:
+            return supported_remotes
+
         return ", ".join(supported_remotes)
 
 


Test patch:
diff --git a/tests/func/test_version.py b/tests/func/test_version.py
--- a/tests/func/test_version.py
+++ b/tests/func/test_version.py
@@ -16,15 +16,10 @@ def test_info_in_repo(scm_init, tmp_dir, caplog):
 
     assert main(["version"]) == 0
 
-    assert re.search(r"DVC version: \d+\.\d+\.\d+", caplog.text)
-    assert re.search(r"Python version: \d\.\d\.\d", caplog.text)
-    assert re.search(r"Platform: .*", caplog.text)
-    assert re.search(r"Binary: (True|False)", caplog.text)
-    assert re.search(r"Package: .*", caplog.text)
-    assert re.search(r"Supported remotes: .*", caplog.text)
-    assert re.search(
-        r"(Cache: (.*link - (not )?supported(,\s)?){3})", caplog.text
-    )
+    assert re.search(r"DVC version: \d+\.\d+\.\d+\+.*", caplog.text)
+    assert re.search(r"Platform: Python \d\.\d\.\d on .*", caplog.text)
+    assert re.search(r"Supports: .*", caplog.text)
+    assert re.search(r"Cache types: .*", caplog.text)
 
     if scm_init:
         assert "Repo: dvc, git" in caplog.text
@@ -58,26 +53,20 @@ def test_fs_info_in_repo(tmp_dir, dvc, caplog):
     os.mkdir(dvc.cache.local.cache_dir)
     assert main(["version"]) == 0
 
-    assert "Filesystem type (cache directory): " in caplog.text
-    assert "Filesystem type (workspace): " in caplog.text
+    assert re.search(r"Cache directory: .* on .*", caplog.text)
+    assert re.search(r"Workspace directory: .* on .*", caplog.text)
 
 
 def test_info_outside_of_repo(tmp_dir, caplog):
     assert main(["version"]) == 0
 
-    assert re.search(r"DVC version: \d+\.\d+\.\d+", caplog.text)
-    assert re.search(r"Python version: \d\.\d\.\d", caplog.text)
-    assert re.search(r"Platform: .*", caplog.text)
-    assert re.search(r"Binary: (True|False)", caplog.text)
-    assert re.search(r"Package: .*", caplog.text)
-    assert re.search(r"Supported remotes: .*", caplog.text)
-    assert not re.search(r"(Cache: (.*link - (not )?(,\s)?){3})", caplog.text)
+    assert re.search(r"DVC version: \d+\.\d+\.\d+\+.*", caplog.text)
+    assert re.search(r"Platform: Python \d\.\d\.\d on .*", caplog.text)
+    assert re.search(r"Supports: .*", caplog.text)
+    assert not re.search(r"Cache types: .*", caplog.text)
     assert "Repo:" not in caplog.text
 
 
 @pytest.mark.skipif(psutil is None, reason="No psutil.")
 def test_fs_info_outside_of_repo(tmp_dir, caplog):
     assert main(["version"]) == 0
-
-    assert "Filesystem type (cache directory): " not in caplog.text
-    assert "Filesystem type (workspace): " in caplog.text