Skip to content

Commit 005ec79

Browse files
AbrilRBSmemsharded
andcommitted
Cache result
--------- Co-authored-by: memsharded <[email protected]>
1 parent a4926c5 commit 005ec79

File tree

3 files changed

+69
-3
lines changed

3 files changed

+69
-3
lines changed

conan/internal/graph/graph_binaries.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,15 @@ def _find_existing_compatible_binaries(self, node, compatibles, remotes, update)
168168
self._compatible_found(conanfile, package_id, compatible_package)
169169
return
170170
if not should_update_reference(conanfile.ref, update):
171-
conanfile.output.info(f"Compatible configurations not found in cache, checking servers")
171+
remotes_to_check = self._filter_compat_remotes(node, remotes)
172+
conanfile.output.info("Compatible configurations not found in cache, "
173+
f"checking {len(remotes_to_check)} servers")
172174
for package_id, compatible_package in compatibles.items():
173175
conanfile.output.info(f"'{package_id}': "
174176
f"{conanfile.info.dump_diff(compatible_package)}")
175177
node._package_id = package_id # Modifying package id under the hood, FIXME
176178
node.binary = None # Invalidate it
177-
self._evaluate_download(node, remotes, update)
179+
self._evaluate_download(node, remotes_to_check, update)
178180
if node.binary == BINARY_DOWNLOAD:
179181
self._compatible_found(conanfile, package_id, compatible_package)
180182
return
@@ -199,6 +201,24 @@ def _find_build_compatible_binary(self, node, compatibles):
199201
node.binary = original_binary
200202
node._package_id = original_package_id
201203

204+
def _filter_compat_remotes(self, node, remotes):
205+
# For each node, check if the remote contains the recipe,
206+
# so that we can skip checking for packages in remotes that don't have the recipe
207+
# TODO: Cache this, but make sure to reset when changing remotes
208+
remotes_to_check = []
209+
for remote in remotes:
210+
try:
211+
self._remote_manager.get_recipe_revision_reference(node.ref, remote)
212+
remotes_to_check.append(remote)
213+
except NotFoundException:
214+
continue
215+
except ConanConnectionError:
216+
node.conanfile.output.error(f"Failed checking for recipe '{node.ref}' in remote "
217+
f"'{remote.name}': remote not available")
218+
raise
219+
220+
return remotes_to_check
221+
202222
def _evaluate_node(self, node, build_mode, remotes, update):
203223
assert node.binary is None, "Node.binary should be None"
204224
assert node.package_id is not None, "Node.package_id shouldn't be None"

conan/internal/rest/remote_manager.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,26 @@ def get_latest_package_reference(self, pref, remote, info=None) -> PkgReference:
285285

286286
def get_recipe_revision_reference(self, ref, remote) -> bool:
287287
assert ref.revision is not None, "recipe_exists needs a revision"
288-
return self._call_remote(remote, "get_recipe_revision_reference", ref)
288+
289+
cached_method = remote._caching.setdefault("get_recipe_revision_reference", {})
290+
try:
291+
result = cached_method[ref]
292+
except KeyError:
293+
try:
294+
result = self._call_remote(remote, "get_recipe_revision_reference", ref)
295+
cached_method[ref] = result
296+
return result
297+
except NotFoundException as e:
298+
# Let's avoid leaking memory by saving all the exception objects,
299+
# which translates to a ~2x memory increase. Now, it only saves the type and the
300+
# final message. For now, let's cache only the NotFoundException one.
301+
cached_method[ref] = self._ErrorMsg(str(e))
302+
raise e
303+
else:
304+
if isinstance(result, self._ErrorMsg):
305+
# Let's raise it
306+
raise NotFoundException(result.message)
307+
return result
289308

290309
def get_package_revision_reference(self, pref, remote) -> bool:
291310
assert pref.revision is not None, "get_package_revision_reference needs a revision"

test/integration/package_id/compatible_test.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,3 +724,30 @@ def libc_compat(conanfile):
724724
tc.run("install --requires=dep/1.0 -s=libc_version=3 -s=compiler.cppstd=14")
725725
assert f"dep/1.0: Found compatible package '{dep_package_id}': compiler.cppstd=17, " \
726726
f"libc_version=2" in tc.out
727+
728+
729+
def test_check_server_non_existing_recipes():
730+
c = TestClient(default_server_user=True)
731+
compatibles = textwrap.dedent("""\
732+
def compatibility(conanfile):
733+
return [{"settings": [("arch", v)]} for v in ("x86", "x86_64", "armv7", "armv8")]
734+
""")
735+
c.save_home({"extensions/plugins/compatibility/compatibility.py": compatibles})
736+
737+
conanfile = GenConanfile("dep", "0.1").with_settings("arch")
738+
c.save({"dep/conanfile.py": conanfile,
739+
"consumer/conanfile.py": GenConanfile().with_requires("dep/0.1")})
740+
741+
c.run(f"export dep")
742+
743+
c.run(f"install --requires=dep/0.1 -s arch=x86", assert_error=True)
744+
745+
assert "dep/0.1: Checking 3 compatible configurations" in c.out
746+
assert "dep/0.1: Compatible configurations not found in cache, checking 0 servers" in c.out
747+
748+
c.run(f"upload dep/0.1 -r=default -c")
749+
750+
c.run(f"install --requires=dep/0.1 -s arch=x86", assert_error=True)
751+
752+
assert "dep/0.1: Checking 3 compatible configurations" in c.out
753+
assert "dep/0.1: Compatible configurations not found in cache, checking 1 servers" in c.out

0 commit comments

Comments
 (0)