Repository: conan-io/conan
Pull request #17883 (2025-03-03 12:15:55)

fix issues with local-recipes-index in presence of workspace home_folder
Changelog: Fix: Avoid workspace incorrectly defining a "local-recipes-index" auxiliary cache
Docs: Omit



Patch:
diff --git a/conan/api/conan_api.py b/conan/api/conan_api.py
index 8a518b21d..719c81fd9 100644
--- a/conan/api/conan_api.py
+++ b/conan/api/conan_api.py
@@ -32,6 +32,10 @@ class ConanAPI:
     not be created directly.
     """
     def __init__(self, cache_folder=None):
+        """
+        :param cache_folder: Conan cache/home folder. It will have less priority than the
+                             "home_folder" defined in a Workspace.
+        """
 
         version = sys.version_info
         if version.major == 2 or version.minor < 6:
diff --git a/conan/internal/conan_app.py b/conan/internal/conan_app.py
index 72196af08..e61dcb687 100644
--- a/conan/internal/conan_app.py
+++ b/conan/internal/conan_app.py
@@ -1,7 +1,9 @@
 import os
 
+from conan.internal.api.local.editable import EditablePackages
 from conan.internal.cache.cache import PkgCache
 from conan.internal.cache.home_paths import HomePaths
+from conan.internal.model.conf import ConfDefinition
 from conans.client.graph.proxy import ConanProxy
 from conans.client.graph.python_requires import PyRequireLoader
 from conans.client.graph.range_resolver import RangeResolver
@@ -69,3 +71,22 @@ class ConanApp(ConanBasicApp):
         conanfile_helpers = ConanFileHelpers(conan_api.remotes.requester, cmd_wrap, self.global_conf,
                                              self.cache, self.cache_folder)
         self.loader = ConanFileLoader(self.pyreq_loader, conanfile_helpers)
+
+
+class LocalRecipesIndexApp:
+    """
+    Simplified one, without full API, for the LocalRecipesIndex. Only publicly used fields are:
+    - cache
+    - loader (for the export phase of local-recipes-index)
+    The others are internally use by other collaborators
+    """
+    def __init__(self, cache_folder):
+        self.global_conf = ConfDefinition()
+        self.cache = PkgCache(cache_folder, self.global_conf)
+        self.remote_manager = RemoteManager(self.cache, auth_manager=None, home_folder=cache_folder)
+        editable_packages = EditablePackages()
+        self.proxy = ConanProxy(self, editable_packages)
+        self.range_resolver = RangeResolver(self, self.global_conf, editable_packages)
+        pyreq_loader = PyRequireLoader(self, self.global_conf)
+        helpers = ConanFileHelpers(None, CmdWrapper(""), self.global_conf, self.cache, cache_folder)
+        self.loader = ConanFileLoader(pyreq_loader, helpers)
diff --git a/conans/client/rest_client_local_recipe_index.py b/conans/client/rest_client_local_recipe_index.py
index 7ab87848a..3296a2fc1 100644
--- a/conans/client/rest_client_local_recipe_index.py
+++ b/conans/client/rest_client_local_recipe_index.py
@@ -65,11 +65,9 @@ class RestApiClientLocalRecipesIndex:
         local_recipes_index_path = os.path.join(local_recipes_index_path, ".conan")
         repo_folder = self._remote.url
 
-        from conan.internal.conan_app import ConanApp
-        from conan.api.conan_api import ConanAPI
-        conan_api = ConanAPI(local_recipes_index_path)
-        self._app = ConanApp(conan_api)
-        self._hook_manager = HookManager(HomePaths(conan_api.home_folder).hooks_path)
+        from conan.internal.conan_app import LocalRecipesIndexApp
+        self._app = LocalRecipesIndexApp(local_recipes_index_path)
+        self._hook_manager = HookManager(HomePaths(local_recipes_index_path).hooks_path)
         self._layout = _LocalRecipesIndexLayout(repo_folder)
 
     def call_method(self, method_name, *args, **kwargs):


Test patch:
diff --git a/test/integration/workspace/test_workspace.py b/test/integration/workspace/test_workspace.py
index 92eb9d1f7..2fabaf9a3 100644
--- a/test/integration/workspace/test_workspace.py
+++ b/test/integration/workspace/test_workspace.py
@@ -9,7 +9,7 @@ from conan.test.assets.genconanfile import GenConanfile
 from conan.test.utils.scm import create_local_git_repo
 from conan.test.utils.test_files import temp_folder
 from conan.test.utils.tools import TestClient
-from conans.util.files import save
+from conans.util.files import save, save_files
 
 WorkspaceAPI.TEST_ENABLED = "will_break_next"
 
@@ -499,7 +499,6 @@ class TestMeta:
                 "conanws.py": conanfilews})
         c.run("workspace add dep")
         c.run("workspace install -of=build")
-        print(c.out)
         files = os.listdir(os.path.join(c.current_folder, "build"))
         assert "conandeps.props" in files
 
@@ -524,3 +523,25 @@ class TestMeta:
         c.run("workspace add dep")
         c.run("workspace install", assert_error=True)
         assert "ERROR: Conanfile in conanws.py shouldn't have 'requires'" in c.out
+
+
+def test_workspace_with_local_recipes_index():
+    c3i_folder = temp_folder()
+    recipes_folder = os.path.join(c3i_folder, "recipes")
+    zlib_config = textwrap.dedent("""
+       versions:
+         "1.2.11":
+           folder: all
+       """)
+    save_files(recipes_folder, {"zlib/config.yml": zlib_config,
+                                "zlib/all/conanfile.py": str(GenConanfile("zlib")),
+                                "zlib/all/conandata.yml": ""})
+
+    c = TestClient(light=True)
+    c.save({"conanws.yml": 'home_folder: "deps"'})
+    c.run(f'remote add local "{c3i_folder}"')
+
+    c.run("list zlib/1.2.11#* -r=local")
+    assert "zlib/1.2.11" in c.out  # It doesn't crash
+    c.run("list zlib/1.2.11#*")
+    assert "zlib/1.2.11" not in c.out