Repository: iterative/dvc

Issue:
Local cache directory creation does not propagate the parent directory persmissions
**Please provide information about your setup**
* DVC >= 0.59
* Platform : Ubuntu 18.04 

Cache directory does not inherit their parent ownership settings, **if they are created by DVC**. For example, the directory created by dvc will lack write permissions for the user group. This can cause conflicts when using the share group option for multi-user access (iterative/dvc.org#497)

If the cache directory referenced by `dir = /myPath`  exists, there is no problem. The current workaround is to create beforehand the cache directory path with the right permissions

Thanks for helping  @efiop !


Discussion:
Discord context https://discordapp.com/channels/485586884165107732/563406153334128681/628897840839786496

Resolving patch:
diff --git a/dvc/command/version.py b/dvc/command/version.py
--- a/dvc/command/version.py
+++ b/dvc/command/version.py
@@ -48,9 +48,21 @@ def run(self):
             repo = Repo()
             root_directory = repo.root_dir
 
-            info += "Cache: {cache}\n".format(
-                cache=self.get_linktype_support_info(repo)
-            )
+            # cache_dir might not exist yet (e.g. after `dvc init`), and we
+            # can't auto-create it, as it might cause issues if the user
+            # later decides to enable shared cache mode with
+            # `dvc config cache.shared group`.
+            if os.path.exists(repo.cache.local.cache_dir):
+                info += "Cache: {cache}\n".format(
+                    cache=self.get_linktype_support_info(repo)
+                )
+            else:
+                logger.warning(
+                    "Unable to detect supported link types, as cache "
+                    "directory '{}' doesn't exist. It is usually auto-created "
+                    "by commands such as `dvc add/fetch/pull/run/import`, but "
+                    "you could create it manually to enable this check."
+                )
 
             if psutil:
                 info += (
diff --git a/dvc/remote/local.py b/dvc/remote/local.py
--- a/dvc/remote/local.py
+++ b/dvc/remote/local.py
@@ -69,9 +69,6 @@ def __init__(self, repo, config):
             cwd = config[Config.PRIVATE_CWD]
             cache_dir = os.path.abspath(os.path.join(cwd, cache_dir))
 
-        if cache_dir is not None and not os.path.exists(cache_dir):
-            os.mkdir(cache_dir)
-
         self.path_info = PathInfo(cache_dir) if cache_dir else None
         self._dir_info = {}
 


Test patch:
diff --git a/tests/func/test_add.py b/tests/func/test_add.py
--- a/tests/func/test_add.py
+++ b/tests/func/test_add.py
@@ -325,7 +325,7 @@ def test(self):
         ret = main(["add", self.FOO, "--no-commit"])
         self.assertEqual(ret, 0)
         self.assertTrue(os.path.isfile(self.FOO))
-        self.assertEqual(len(os.listdir(self.dvc.cache.local.cache_dir)), 0)
+        self.assertFalse(os.path.exists(self.dvc.cache.local.cache_dir))
 
         ret = main(["commit", self.FOO + ".dvc"])
         self.assertEqual(ret, 0)
diff --git a/tests/func/test_cache.py b/tests/func/test_cache.py
--- a/tests/func/test_cache.py
+++ b/tests/func/test_cache.py
@@ -1,7 +1,6 @@
 import os
 import stat
 import pytest
-import shutil
 import configobj
 
 from dvc.cache import Cache
@@ -66,7 +65,7 @@ def test(self):
         ret = main(["config", "cache.dir", cache_dir])
         self.assertEqual(ret, 0)
 
-        shutil.rmtree(".dvc/cache")
+        self.assertFalse(os.path.exists(self.dvc.cache.local.cache_dir))
 
         ret = main(["add", self.FOO])
         self.assertEqual(ret, 0)
@@ -101,7 +100,7 @@ def test(self):
             ret = main(["config", "cache.dir", cache_dir])
             self.assertEqual(ret, 0)
 
-            shutil.rmtree(os.path.join(".dvc", "cache"))
+            self.assertFalse(os.path.exists(os.path.join(".dvc", "cache")))
 
             with open("common", "w+") as fd:
                 fd.write("common")
diff --git a/tests/func/test_repro.py b/tests/func/test_repro.py
--- a/tests/func/test_repro.py
+++ b/tests/func/test_repro.py
@@ -1280,7 +1280,7 @@ def test(self):
         shutil.rmtree(self.dvc.cache.local.cache_dir)
         ret = main(["repro", self.file1_stage, "--no-commit"])
         self.assertEqual(ret, 0)
-        self.assertEqual(len(os.listdir(self.dvc.cache.local.cache_dir)), 0)
+        self.assertFalse(os.path.exists(self.dvc.cache.local.cache_dir))
 
 
 class TestReproAlreadyCached(TestRepro):
diff --git a/tests/func/test_run.py b/tests/func/test_run.py
--- a/tests/func/test_run.py
+++ b/tests/func/test_run.py
@@ -706,7 +706,7 @@ def test(self):
         )
         self.assertEqual(ret, 0)
         self.assertTrue(os.path.isfile(fname))
-        self.assertEqual(len(os.listdir(self.dvc.cache.local.cache_dir)), 0)
+        self.assertFalse(os.path.exists(self.dvc.cache.local.cache_dir))
 
         ret = main(["commit", fname + ".dvc"])
         self.assertEqual(ret, 0)
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
@@ -5,7 +5,11 @@
 from dvc.command.version import psutil
 
 
-def test_info_in_repo(dvc_repo, caplog):
+def test_info_in_repo(repo_dir, dvc_repo, caplog):
+    # adding a file so that dvc creates `.dvc/cache`, that is needed for proper
+    # supported link types check.
+    assert main(["add", repo_dir.FOO]) == 0
+
     assert main(["version"]) == 0
 
     assert re.search(re.compile(r"DVC version: \d+\.\d+\.\d+"), caplog.text)