Repository: conan-io/conan

Issue:
[Feature request] Can we WARN when a user changes `user_home_short` to same as `path`?
A colleague was working fine with Conan for weeks, then started getting the following error even for simple operations such as `conan search`:

```
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC>conan search
ERROR: Value provided for package version, '1' (type Version), is too short. Valid names must contain at least 2 characters.
```

I see similar https://github.com/conan-io/conan/issues/5606 -- is this the same issue?

Windows Server 2012 R2, conan 1.16.1

To help us debug your issue please explain:

- [x] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [x] I've specified the Conan version, operating system version and any tool that can be relevant.
- [x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.




Discussion:
Hi! I'm not sure what can be happening there, Conan has had always a limitation for all the components in a reference to be at least two characters in length.

The issue you are linking is related to recipes without user/channel. Older Conan client will raise an error because of the single `_` that is used to represent the ``None`` value in the filesystem.

Your colleague has a wrong reference in the cache, a reference has ``1`` as version and it is not supported by Conan, I don't know how it could have arrived at the Conan cache... I would love to know it if it is a Conan issue.

Meanwhile, to discover the offending package you can look for it by hand (list the versions of every package in the Conan cache: by default, they are inside ``~/.conan/data/<every-package>/``) or you can run a python script:

```python
import os

basedir = os.path.expanduser("~/.conan/data")  # Use the path to Conan cache
ret = []
for root, dirs, _ in os.walk(basedir):
    rel_path = os.path.relpath(root, basedir)
    if rel_path == ".":
        continue
    dir_split = rel_path.split(os.sep)
    if len(dir_split) == 2:
        if len(dir_split[1]) == 1:
            print("Offender: {}".format(dir_split))
        dirs[:] = []  # Stop iterate subdirs
```

Maybe, with the name of the package, you can know how it has arrived in the Conan cache. Thanks!
I think I figured out the colleague's issue.  He had his user_home_short set to same directory as his path:

```
[general]
user_home_short = f:\DevelopBp\<user>\.conan
[...]
[storage]
path = f:\DevelopBp\<user>\.conan
```



Is there something we could do to alert with clear logging when a user makes this mistake?
Ouch! It looks like something easy to add and can keep some headache away. 👍 
I would like to take a crack at this one if you don't mind.

At first glance it seems like either `conans/utils/windows.py` or `conans/utils/config_parser.py` (or somewhere that makes use of `ConfigParser`) would be the appropriate location to implement this check / warning. Does that seem correct?

This is my first attempt at contributing to an open source project, as such any and all feedback is welcome!

---

On second thought, the `storage_path` function on line 404 of `conans\client\conf\__init__.py` looks promising. 
Welcome @cctechwiz !!

I am having a look to see where would be the easiest location to implement this. There are very simple hacks, but I am going to propose what I think is the right solution aligned with the future design of Conan (where we want to get rid of environment variables for internal configuration)

1. Implement a property in the ``ConanClientConfigParser``, called ``short_paths_home``
This will be very similar to the ``default_package_id_mode`` property.

2. Add a check to that property, based on the ``self.filename``, using ``os.path.dirname()`` to get the folder location that contains the conan.conf file that is being parsed. That is the location of the conan cache. Raise an error (``ConanException``) if the ``short_paths_home`` is a subfolder of it

3. Call ``self.config.short_paths_home`` in the __init__ of ``ClientCache``, to ensure that the cache cannot be instantiated which such a broken configuration (I don't think this would be a warning, it is a very broken configuration)

You can test manually if you want, lets leave tests for later, lets see how it goes. Don't hesitate to ask if you have any question! Thanks!!

Resolving patch:
diff --git a/conans/client/cache/cache.py b/conans/client/cache/cache.py
--- a/conans/client/cache/cache.py
+++ b/conans/client/cache/cache.py
@@ -72,6 +72,8 @@ def __init__(self, cache_folder, output):
         self.editable_packages = EditablePackages(self.cache_folder)
         # paths
         self._store_folder = self.config.storage_path or self.cache_folder
+        # Just call it to make it raise in case of short_paths misconfiguration
+        self.config.short_paths_home
 
     def all_refs(self):
         subdirs = list_folder_subdirs(basedir=self._store_folder, level=4)
diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py
--- a/conans/client/conf/__init__.py
+++ b/conans/client/conf/__init__.py
@@ -400,6 +400,18 @@ def default_package_id_mode(self):
             return "semver_direct_mode"
         return default_package_id_mode
 
+    @property
+    def short_paths_home(self):
+        short_paths_home = get_env("CONAN_USER_HOME_SHORT")
+        if short_paths_home:
+            current_dir = os.path.dirname(self.filename)
+            if current_dir == os.path.commonprefix([current_dir, short_paths_home]):
+                raise ConanException("Short path home '{}' (defined by conan.conf variable "
+                                     "'user_home_short', or environment variable "
+                                     "'CONAN_USER_HOME_SHORT') cannot be a subdirectory of "
+                                     "the conan cache '{}'.".format(short_paths_home, current_dir))
+        return short_paths_home
+
     @property
     def storage_path(self):
         # Try with CONAN_STORAGE_PATH


Test patch:
diff --git a/conans/test/functional/command/config_test.py b/conans/test/functional/command/config_test.py
--- a/conans/test/functional/command/config_test.py
+++ b/conans/test/functional/command/config_test.py
@@ -1,6 +1,8 @@
 import os
 import unittest
+import six
 
+from conans.errors import ConanException
 from conans.test.utils.tools import TestClient
 from conans.util.files import load
 from conans.test.utils.test_files import temp_folder
@@ -107,6 +109,5 @@ def test_config_home_custom_home_dir(self):
     def test_config_home_short_home_dir(self):
         cache_folder = os.path.join(temp_folder(), "custom")
         with environment_append({"CONAN_USER_HOME_SHORT": cache_folder}):
-            client = TestClient(cache_folder=cache_folder)
-            client.run("config home")
-            self.assertIn(cache_folder, client.out)
+            with six.assertRaisesRegex(self, ConanException, "cannot be a subdirectory of the conan cache"):
+                TestClient(cache_folder=cache_folder)
diff --git a/conans/test/functional/command/info_folders_test.py b/conans/test/functional/command/info_folders_test.py
--- a/conans/test/functional/command/info_folders_test.py
+++ b/conans/test/functional/command/info_folders_test.py
@@ -114,13 +114,13 @@ def test_single_field(self):
     @unittest.skipIf(platform.system() != "Windows", "Needs windows for short_paths")
     def test_short_paths(self):
         cache_folder = temp_folder(False)
-        short_folder = os.path.join(cache_folder, ".cn")
+        short_folder = os.path.join(temp_folder(False), ".cn")
 
         with tools.environment_append({"CONAN_USER_HOME_SHORT": short_folder}):
             client = TestClient(cache_folder=cache_folder)
             client.save({CONANFILE: conanfile_py.replace("False", "True")})
             client.run("export . %s" % self.user_channel)
-            client.run("info %s --paths" % (self.reference1))
+            client.run("info %s --paths" % self.reference1)
             base_path = os.path.join("MyPackage", "0.1.0", "myUser", "testing")
             output = client.out
             self.assertIn(os.path.join(base_path, "export"), output)
@@ -135,7 +135,7 @@ def test_short_paths(self):
             # Ensure that the inner folders are not created (that could affect
             # pkg creation flow
             ref = ConanFileReference.loads(self.reference1)
-            id_ = re.search('ID:\s*([a-z0-9]*)', str(client.out)).group(1)
+            id_ = re.search(r'ID:\s*([a-z0-9]*)', str(client.out)).group(1)
             pref = PackageReference(ref, id_)
             for path in (client.cache.package_layout(ref, True).source(),
                          client.cache.package_layout(ref, True).build(pref),
@@ -156,7 +156,7 @@ def test_short_paths_home_set_acl(self):
                                       % os.path.splitdrive(cache_folder)[0])
         if "NTFS" not in str(out):
             return
-        short_folder = os.path.join(cache_folder, ".cnacls")
+        short_folder = os.path.join(temp_folder(False), ".cnacls")
 
         self.assertFalse(os.path.exists(short_folder), "short_folder: %s shouldn't exists"
                          % short_folder)
@@ -203,7 +203,7 @@ def test_direct_conanfile(self):
     def test_short_paths_folders(self):
         # https://github.com/conan-io/conan/issues/4612
         cache_folder = temp_folder(False)
-        short_folder = os.path.join(cache_folder, ".cn")
+        short_folder = os.path.join(temp_folder(False), ".cn")
 
         conanfile = dedent("""
             from conans import ConanFile
diff --git a/conans/test/functional/generators/virtualbuildenv_test.py b/conans/test/functional/generators/virtualbuildenv_test.py
--- a/conans/test/functional/generators/virtualbuildenv_test.py
+++ b/conans/test/functional/generators/virtualbuildenv_test.py
@@ -1,5 +1,6 @@
 import os
 import platform
+import textwrap
 import unittest
 
 from conans import load
@@ -45,15 +46,12 @@ def get_cmd(script_name):
             else:
                 return "bash -c 'source %s && env'" % script_name
 
-        conanfile = """
-from conans import ConanFile
-
-class TestConan(ConanFile):
-    name = "test"
-    version = "1.0"
-    settings = "os", "compiler", "arch", "build_type"
-    generators = "virtualbuildenv"
-"""
+        conanfile = textwrap.dedent("""
+            from conans import ConanFile
+            class TestConan(ConanFile):
+                settings = "os", "compiler", "arch", "build_type"
+                generators = "virtualbuildenv"
+            """)
         client = TestClient(path_with_spaces=False)
         client.save({"conanfile.py": conanfile})
         client.run("install .")