Repository: conan-io/conan
Pull request #18009 (2025-03-24 21:53:09)

fix issue with update_policy=legacy and lockfiles
Changelog: Bugfix: Solve issue with ``update_policy=legacy`` and using lockfiles
Docs: Omit

Close https://github.com/conan-io/conan/issues/18006


Patch:
diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py
index 58b0d87dd..6a95733b4 100644
--- a/conan/tools/microsoft/msbuilddeps.py
+++ b/conan/tools/microsoft/msbuilddeps.py
@@ -336,9 +336,14 @@ class MSBuildDeps:
                 public_deps = []  # To store the xml dependencies/file names
                 for required_pkg, required_comp in comp_info.parsed_requires():
                     if required_pkg is not None:  # Points to a component of a different package
-                        if required_pkg in pkg_deps:  # The transitive dep might have been skipped
-                            public_deps.append(required_pkg if required_pkg == required_comp
-                                               else "{}_{}".format(required_pkg, required_comp))
+                        try:
+                            required = pkg_deps[required_pkg]
+                        except KeyError:  # The transitive dep might have been skipped
+                            required = None
+                        if required:  # The transitive dep might have been skipped
+                            required_name = required.ref.name
+                            public_deps.append(required_name if required_pkg == required_comp
+                                               else "{}_{}".format(required_name, required_comp))
                     else:  # Points to a component of same package
                         public_deps.append("{}_{}".format(dep_name, required_comp))
                 public_deps = [self._get_valid_xml_format(d) for d in public_deps]
diff --git a/conans/client/graph/proxy.py b/conans/client/graph/proxy.py
index 66a56c283..72b927516 100644
--- a/conans/client/graph/proxy.py
+++ b/conans/client/graph/proxy.py
@@ -106,7 +106,7 @@ class ConanProxy:
                 continue
             output.info(f"Checking remote: {remote.name}")
             try:
-                if self._legacy_update and need_update:
+                if self._legacy_update and need_update and reference.revision is None:
                     if not getattr(ConanProxy, "update_policy_legacy_warning", None):
                         ConanProxy.update_policy_legacy_warning = True
                         ConanOutput().warning("The 'core:update_policy' conf is deprecated and will "


Test patch:
diff --git a/test/integration/command/install/install_update_test.py b/test/integration/command/install/install_update_test.py
index 450d771be..18c238f92 100644
--- a/test/integration/command/install/install_update_test.py
+++ b/test/integration/command/install/install_update_test.py
@@ -233,3 +233,15 @@ class TestUpdateOldPolicy:
         c.run("remove * -c")
         c.run("graph info --requires=pkg/0.1 --update -cc core:update_policy=legacy")
         assert f"pkg/0.1#{rev2} - Downloaded (r1)" in c.out
+
+    def test_lockfile(self):
+        # https://github.com/conan-io/conan/issues/18006
+        c = TestClient(default_server_user=True, light=True)  # needs server to fail
+        c.save_home({"global.conf": "core:update_policy=legacy"})
+        c.save({"dep/conanfile.py": GenConanfile("dep", "0.1"),
+                "pkg/conanfile.py": GenConanfile("pkg", "0.1").with_python_requires("dep/0.1")})
+        c.run("create dep")
+        c.run("lock create pkg --lockfile-out base.lock --build=* --update")
+        c.run("lock create pkg --lockfile base.lock --lockfile-out full.lock --build=* --update")
+        # it doesn't crash
+        assert "Generated lockfile" in c.out
diff --git a/test/integration/graph/test_replace_requires.py b/test/integration/graph/test_replace_requires.py
index 4b832ebac..ef6e86bb4 100644
--- a/test/integration/graph/test_replace_requires.py
+++ b/test/integration/graph/test_replace_requires.py
@@ -418,14 +418,15 @@ class TestReplaceRequiresTransitiveGenerators:
             class App(ConanFile):
                 name = "app"
                 version = "0.1"
-                settings = "build_type"
+                settings = "build_type", "arch"
                 requires = "openssl/0.1", {zlib}
                 package_type = "application"
-                generators = "CMakeDeps", "PkgConfigDeps"
+                generators = "CMakeDeps", "PkgConfigDeps", "MSBuildDeps"
             """)
         profile = textwrap.dedent("""
             [settings]
             build_type = Release
+            arch=x86_64
 
             [replace_requires]
             zlib/0.1: zlib-ng/0.1
@@ -454,6 +455,13 @@ class TestReplaceRequiresTransitiveGenerators:
         assert "set_property(TARGET openssl::openssl APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
                '             "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
 
+        # checking MSBuildDeps
+        zlib_ng_props = c.load("app/conan_zlib-ng.props")
+        assert 'Project="conan_zlib-ng_release_x64.props"' in zlib_ng_props
+        props = c.load("app/conan_openssl_release_x64.props")
+        assert "<Import Condition=\"'$(conan_zlib-ng_props_imported)' != 'True'\"" \
+               " Project=\"conan_zlib-ng.props\"/>" in props
+
     @pytest.mark.parametrize("diamond", [True, False])
     def test_openssl_components(self, diamond):
         c = TestClient()
@@ -490,14 +498,15 @@ class TestReplaceRequiresTransitiveGenerators:
             class App(ConanFile):
                 name = "app"
                 version = "0.1"
-                settings = "build_type"
+                settings = "build_type", "arch"
                 requires = "openssl/0.1", {zlib}
                 package_type = "application"
-                generators = "CMakeDeps", "PkgConfigDeps"
+                generators = "CMakeDeps", "PkgConfigDeps", "MSBuildDeps"
             """)
         profile = textwrap.dedent("""
             [settings]
             build_type = Release
+            arch=x86_64
 
             [replace_requires]
             zlib/0.1: zlib-ng/0.1
@@ -526,6 +535,14 @@ class TestReplaceRequiresTransitiveGenerators:
         assert "set_property(TARGET openssl::crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
                '             "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
 
+        # checking MSBuildDeps
+        zlib_ng_props = c.load("app/conan_zlib-ng.props")
+        assert 'Project="conan_zlib-ng_release_x64.props"' in zlib_ng_props
+
+        props = c.load("app/conan_openssl_crypto_release_x64.props")
+        assert "<Import Condition=\"'$(conan_zlib-ng_props_imported)' != 'True'\"" \
+               " Project=\"conan_zlib-ng.props\"/>" in props
+
     @pytest.mark.parametrize("diamond", [True, False])
     @pytest.mark.parametrize("explicit_requires", [True, False])
     def test_zlib_components(self, diamond, explicit_requires):
@@ -565,14 +582,15 @@ class TestReplaceRequiresTransitiveGenerators:
             class App(ConanFile):
                 name = "app"
                 version = "0.1"
-                settings = "build_type"
+                settings = "build_type", "arch"
                 requires = "openssl/0.1", {zlib}
                 package_type = "application"
-                generators = "CMakeDeps", "PkgConfigDeps"
+                generators = "CMakeDeps", "PkgConfigDeps", "MSBuildDeps"
             """)
         profile = textwrap.dedent("""
             [settings]
             build_type = Release
+            arch = x86_64
 
             [replace_requires]
             zlib/0.1: zlib-ng/0.1
@@ -604,6 +622,15 @@ class TestReplaceRequiresTransitiveGenerators:
         assert "set_property(TARGET openssl::openssl APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
                '             "$<$<CONFIG:RELEASE>:zlib-ng::zlib-ng>")' in cmake
 
+        # checking MSBuildDeps
+        zlib_ng_props = c.load("app/conan_zlib-ng.props")
+        assert "<Import Condition=\"'$(conan_zlib-ng_myzlib_props_imported)' != 'True'\" " \
+               "Project=\"conan_zlib-ng_myzlib.props\"/" in zlib_ng_props
+
+        props = c.load("app/conan_openssl_release_x64.props")
+        assert "<Import Condition=\"'$(conan_zlib-ng_props_imported)' != 'True'\"" \
+               " Project=\"conan_zlib-ng.props\"/>" in props
+
     @pytest.mark.parametrize("diamond", [True, False])
     @pytest.mark.parametrize("package_requires", [False, True])
     def test_both_components(self, diamond, package_requires):
@@ -645,14 +672,15 @@ class TestReplaceRequiresTransitiveGenerators:
             class App(ConanFile):
                 name = "app"
                 version = "0.1"
-                settings = "build_type"
+                settings = "build_type", "arch"
                 requires = "openssl/0.1", {zlib}
                 package_type = "application"
-                generators = "CMakeDeps", "PkgConfigDeps"
+                generators = "CMakeDeps", "PkgConfigDeps", "MSBuildDeps"
             """)
         profile = textwrap.dedent("""
             [settings]
             build_type = Release
+            arch = x86_64
 
             [replace_requires]
             zlib/0.1: zlib-ng/0.1
@@ -687,3 +715,16 @@ class TestReplaceRequiresTransitiveGenerators:
         else:
             assert "set_property(TARGET openssl::crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
                    '             "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
+
+        # checking MSBuildDeps
+        zlib_ng_props = c.load("app/conan_zlib-ng.props")
+        assert "<Import Condition=\"'$(conan_zlib-ng_myzlib_props_imported)' != 'True'\" " \
+               "Project=\"conan_zlib-ng_myzlib.props\"/" in zlib_ng_props
+
+        props = c.load("app/conan_openssl_crypto_release_x64.props")
+        if package_requires:
+            assert "<Import Condition=\"'$(conan_zlib-ng_props_imported)' != 'True'\"" \
+                   " Project=\"conan_zlib-ng.props\"/>" in props
+        else:
+            assert "<Import Condition=\"'$(conan_zlib-ng_myzlib_props_imported)' != 'True'\"" \
+                   " Project=\"conan_zlib-ng_myzlib.props\"/>" in props