Repository: conan-io/conan
Pull request #16110 (2024-04-19 09:22:04)

Clarify which revisions are what in --update test
Changelog: Omit
Docs: TODO

I wanted to show this test as evidence for a support question, but realized the revisions are not clear on which are which - this gives them names and makes the behaviour a bit more clear :)

I want to modify the docs a bit to ensure this is a bit more clear

RubenRBS: This runs for me locally 🤔
Will double check in a bit

Patch:
diff --git a/conan/api/subapi/cache.py b/conan/api/subapi/cache.py
index 0875f6fb2..1fcb49219 100644
--- a/conan/api/subapi/cache.py
+++ b/conan/api/subapi/cache.py
@@ -155,6 +155,8 @@ class CacheAPI:
             tgz.close()
 
     def restore(self, path):
+        if not os.path.isfile(path):
+            raise ConanException(f"Restore archive doesn't exist in {path}")
         with open(path, mode='rb') as file_handler:
             the_tar = tarfile.open(fileobj=file_handler)
             fileobj = the_tar.extractfile("pkglist.json")
diff --git a/conan/cli/commands/version.py b/conan/cli/commands/version.py
index 507f0f7d1..b2509afef 100644
--- a/conan/cli/commands/version.py
+++ b/conan/cli/commands/version.py
@@ -12,10 +12,22 @@ def version(conan_api, parser, *args):
     Give information about the Conan client version.
     """
 
-    return {'version': str(conan_version),
+    return {
+            'version': str(conan_version),
+            'conan_path': sys.argv[0],
             'python': {
                 'version': platform.python_version().replace('\n', ''),
                 'sys_version': sys.version.replace('\n', ''),
+                'sys_executable': sys.executable,
+                'is_frozen': getattr(sys, 'frozen', False),
+                'architecture': platform.machine(),
+                },
+            'system': {
+                'version': platform.version(),
+                'platform': platform.platform(),
+                'system': platform.system(),
+                'release': platform.release(),
+                'cpu': platform.processor(),
                 }
             }
 
diff --git a/conan/internal/cache/db/packages_table.py b/conan/internal/cache/db/packages_table.py
index 7d093197b..a5ec13b7a 100644
--- a/conan/internal/cache/db/packages_table.py
+++ b/conan/internal/cache/db/packages_table.py
@@ -39,7 +39,7 @@ class PackagesDBTable(BaseDbTable):
             self.columns.prev: pref.revision,
         }
         where_expr = ' AND '.join(
-            [f'{k}="{v}" ' if v is not None else f'{k} IS NULL' for k, v in where_dict.items()])
+            [f"{k}='{v}' " if v is not None else f'{k} IS NULL' for k, v in where_dict.items()])
         return where_expr
 
     def _set_clause(self, pref: PkgReference, path=None, build_id=None):
@@ -52,7 +52,7 @@ class PackagesDBTable(BaseDbTable):
             self.columns.timestamp: pref.timestamp,
             self.columns.build_id: build_id,
         }
-        set_expr = ', '.join([f'{k} = "{v}"' for k, v in set_dict.items() if v is not None])
+        set_expr = ', '.join([f"{k} = '{v}'" for k, v in set_dict.items() if v is not None])
         return set_expr
 
     def get(self, pref: PkgReference):
@@ -107,7 +107,7 @@ class PackagesDBTable(BaseDbTable):
         where_clause = self._where_clause(pref)
         lru = timestamp_now()
         query = f"UPDATE {self.table_name} " \
-                f'SET {self.columns.lru} = "{lru}" ' \
+                f"SET {self.columns.lru} = '{lru}' " \
                 f"WHERE {where_clause};"
         with self.db_connection() as conn:
             conn.execute(query)
@@ -115,7 +115,7 @@ class PackagesDBTable(BaseDbTable):
     def remove_build_id(self, pref):
         where_clause = self._where_clause(pref)
         query = f"UPDATE {self.table_name} " \
-                f'SET {self.columns.build_id} = "null" ' \
+                f"SET {self.columns.build_id} = 'null' " \
                 f"WHERE {where_clause};"
         with self.db_connection() as conn:
             try:
@@ -126,8 +126,8 @@ class PackagesDBTable(BaseDbTable):
     def remove_recipe(self, ref: RecipeReference):
         # can't use the _where_clause, because that is an exact match on the package_id, etc
         query = f"DELETE FROM {self.table_name} " \
-                f'WHERE {self.columns.reference} = "{str(ref)}" ' \
-                f'AND {self.columns.rrev} = "{ref.revision}" '
+                f"WHERE {self.columns.reference} = '{str(ref)}' " \
+                f"AND {self.columns.rrev} = '{ref.revision}' "
         with self.db_connection() as conn:
             conn.execute(query)
 
@@ -141,7 +141,7 @@ class PackagesDBTable(BaseDbTable):
     def get_package_revisions_references(self, pref: PkgReference, only_latest_prev=False):
         assert pref.ref.revision, "To search package revisions you must provide a recipe revision."
         assert pref.package_id, "To search package revisions you must provide a package id."
-        check_prev = f'AND {self.columns.prev} = "{pref.revision}" ' if pref.revision else ''
+        check_prev = f"AND {self.columns.prev} = '{pref.revision}' " if pref.revision else ""
         if only_latest_prev:
             query = f'SELECT {self.columns.reference}, ' \
                     f'{self.columns.rrev}, ' \
@@ -152,17 +152,17 @@ class PackagesDBTable(BaseDbTable):
                     f'{self.columns.build_id}, ' \
                     f'{self.columns.lru} ' \
                     f'FROM {self.table_name} ' \
-                    f'WHERE {self.columns.rrev} = "{pref.ref.revision}" ' \
-                    f'AND {self.columns.reference} = "{str(pref.ref)}" ' \
-                    f'AND {self.columns.pkgid} = "{pref.package_id}" ' \
+                    f"WHERE {self.columns.rrev} = '{pref.ref.revision}' " \
+                    f"AND {self.columns.reference} = '{str(pref.ref)}' " \
+                    f"AND {self.columns.pkgid} = '{pref.package_id}' " \
                     f'{check_prev} ' \
                     f'AND {self.columns.prev} IS NOT NULL ' \
                     f'GROUP BY {self.columns.pkgid} '
         else:
             query = f'SELECT * FROM {self.table_name} ' \
-                    f'WHERE {self.columns.rrev} = "{pref.ref.revision}" ' \
-                    f'AND {self.columns.reference} = "{str(pref.ref)}" ' \
-                    f'AND {self.columns.pkgid} = "{pref.package_id}" ' \
+                    f"WHERE {self.columns.rrev} = '{pref.ref.revision}' " \
+                    f"AND {self.columns.reference} = '{str(pref.ref)}' " \
+                    f"AND {self.columns.pkgid} = '{pref.package_id}' " \
                     f'{check_prev} ' \
                     f'AND {self.columns.prev} IS NOT NULL ' \
                     f'ORDER BY {self.columns.timestamp} DESC'
@@ -185,13 +185,13 @@ class PackagesDBTable(BaseDbTable):
                     f'{self.columns.build_id}, ' \
                     f'{self.columns.lru} ' \
                     f'FROM {self.table_name} ' \
-                    f'WHERE {self.columns.rrev} = "{ref.revision}" ' \
-                    f'AND {self.columns.reference} = "{str(ref)}" ' \
+                    f"WHERE {self.columns.rrev} = '{ref.revision}' " \
+                    f"AND {self.columns.reference} = '{str(ref)}' " \
                     f'GROUP BY {self.columns.pkgid} '
         else:
             query = f'SELECT * FROM {self.table_name} ' \
-                    f'WHERE {self.columns.rrev} = "{ref.revision}" ' \
-                    f'AND {self.columns.reference} = "{str(ref)}" ' \
+                    f"WHERE {self.columns.rrev} = '{ref.revision}' " \
+                    f"AND {self.columns.reference} = '{str(ref)}' " \
                     f'AND {self.columns.prev} IS NOT NULL ' \
                     f'ORDER BY {self.columns.timestamp} DESC'
         with self.db_connection() as conn:
diff --git a/conan/internal/cache/db/recipes_table.py b/conan/internal/cache/db/recipes_table.py
index 38bbb3d2d..fe40ab567 100644
--- a/conan/internal/cache/db/recipes_table.py
+++ b/conan/internal/cache/db/recipes_table.py
@@ -33,7 +33,7 @@ class RecipesDBTable(BaseDbTable):
             self.columns.rrev: ref.revision,
         }
         where_expr = ' AND '.join(
-            [f'{k}="{v}" ' if v is not None else f'{k} IS NULL' for k, v in where_dict.items()])
+            [f"{k}='{v}' " if v is not None else f'{k} IS NULL' for k, v in where_dict.items()])
         return where_expr
 
     def create(self, path, ref: RecipeReference):
@@ -54,9 +54,9 @@ class RecipesDBTable(BaseDbTable):
         assert ref.revision is not None
         assert ref.timestamp is not None
         query = f"UPDATE {self.table_name} " \
-                f'SET {self.columns.timestamp} = "{ref.timestamp}" ' \
-                f'WHERE {self.columns.reference}="{str(ref)}" ' \
-                f'AND {self.columns.rrev} = "{ref.revision}" '
+                f"SET {self.columns.timestamp} = '{ref.timestamp}' " \
+                f"WHERE {self.columns.reference}='{str(ref)}' " \
+                f"AND {self.columns.rrev} = '{ref.revision}' "
         with self.db_connection() as conn:
             conn.execute(query)
 
@@ -66,7 +66,7 @@ class RecipesDBTable(BaseDbTable):
         where_clause = self._where_clause(ref)
         lru = timestamp_now()
         query = f"UPDATE {self.table_name} " \
-                f'SET {self.columns.lru} = "{lru}" ' \
+                f"SET {self.columns.lru} = '{lru}' " \
                 f"WHERE {where_clause};"
         with self.db_connection() as conn:
             conn.execute(query)
@@ -95,8 +95,8 @@ class RecipesDBTable(BaseDbTable):
 
     def get_recipe(self, ref: RecipeReference):
         query = f'SELECT * FROM {self.table_name} ' \
-                f'WHERE {self.columns.reference}="{str(ref)}" ' \
-                f'AND {self.columns.rrev} = "{ref.revision}" '
+                f"WHERE {self.columns.reference}='{str(ref)}' " \
+                f"AND {self.columns.rrev} = '{ref.revision}' "
         with self.db_connection() as conn:
             r = conn.execute(query)
             row = r.fetchone()
@@ -112,7 +112,7 @@ class RecipesDBTable(BaseDbTable):
                 f'MAX({self.columns.timestamp}), ' \
                 f'{self.columns.lru} ' \
                 f'FROM {self.table_name} ' \
-                f'WHERE {self.columns.reference} = "{str(ref)}" ' \
+                f"WHERE {self.columns.reference} = '{str(ref)}' " \
                 f'GROUP BY {self.columns.reference} '  # OTHERWISE IT FAILS THE MAX()
 
         with self.db_connection() as conn:
@@ -126,7 +126,7 @@ class RecipesDBTable(BaseDbTable):
     def get_recipe_revisions_references(self, ref: RecipeReference):
         assert ref.revision is None
         query = f'SELECT * FROM {self.table_name} ' \
-                f'WHERE {self.columns.reference} = "{str(ref)}" ' \
+                f"WHERE {self.columns.reference} = '{str(ref)}' " \
                 f'ORDER BY {self.columns.timestamp} DESC'
 
         with self.db_connection() as conn:
diff --git a/conans/client/store/localdb.py b/conans/client/store/localdb.py
index 9ae82f9eb..8525256b6 100644
--- a/conans/client/store/localdb.py
+++ b/conans/client/store/localdb.py
@@ -49,7 +49,7 @@ class LocalDB:
                 cursor = connection.cursor()
                 query = "DELETE FROM %s" % REMOTES_USER_TABLE
                 if remote_url:
-                    query += ' WHERE remote_url="{}"'.format(remote_url)
+                    query += " WHERE remote_url='{}'".format(remote_url)
                 cursor.execute(query)
                 try:
                     # https://github.com/ghaering/pysqlite/issues/109
@@ -74,7 +74,7 @@ class LocalDB:
         with self._connect() as connection:
             try:
                 statement = connection.cursor()
-                statement.execute('select user, token, refresh_token from %s where remote_url="%s"'
+                statement.execute("select user, token, refresh_token from %s where remote_url='%s'"
                                   % (REMOTES_USER_TABLE, remote_url))
                 rs = statement.fetchone()
                 if not rs:
diff --git a/conans/util/windows.py b/conans/util/windows.py
index 53cc89c39..89c1a2752 100644
--- a/conans/util/windows.py
+++ b/conans/util/windows.py
@@ -9,8 +9,7 @@ def conan_expand_user(path):
     if path[:1] != '~':
         return path
     # In win these variables should exist and point to user directory, which
-    # must exist. Using context to avoid permanent modification of os.environ
-    old_env = dict(os.environ)
+    # must exist.
     try:
         home = os.environ.get("HOME")
         # Problematic cases of wrong HOME variable
@@ -22,6 +21,6 @@ def conan_expand_user(path):
             del os.environ["HOME"]
         result = os.path.expanduser(path)
     finally:
-        os.environ.clear()
-        os.environ.update(old_env)
+        if home is not None:
+            os.environ["HOME"] = home
     return result


Test patch:
diff --git a/conans/test/conftest.py b/conans/test/conftest.py
index 080b111b5..07b35c85b 100644
--- a/conans/test/conftest.py
+++ b/conans/test/conftest.py
@@ -52,7 +52,7 @@ tools_locations = {
     'visual_studio': {"default": "15",
                       "15": {},
                       "16": {"disabled": True},
-                      "17": {"disabled": True}},
+                      "17": {}},
     'pkg_config': {
         "exe": "pkg-config",
         "default": "0.28",
diff --git a/conans/test/functional/test_profile_detect_api.py b/conans/test/functional/test_profile_detect_api.py
index 820e41599..b33d1cb30 100644
--- a/conans/test/functional/test_profile_detect_api.py
+++ b/conans/test/functional/test_profile_detect_api.py
@@ -8,6 +8,7 @@ from conans.test.utils.tools import TestClient
 
 
 class TestProfileDetectAPI:
+    @pytest.mark.skipif(platform.system() != "Windows", reason="Only for windows")
     @pytest.mark.tool("visual_studio", "17")
     def test_profile_detect_compiler(self):
 
diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py
index 1261ea731..2b0a03695 100644
--- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py
+++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain_win_clang.py
@@ -9,7 +9,6 @@ from conans.test.assets.cmake import gen_cmakelists
 from conans.test.assets.sources import gen_function_cpp, gen_function_c
 from conans.test.functional.utils import check_vs_runtime, check_exe_run
 from conans.test.utils.tools import TestClient
-from conans.util.env import environment_update
 
 
 @pytest.fixture
@@ -65,7 +64,7 @@ def client():
 
 
 @pytest.mark.tool("cmake")
-@pytest.mark.tool("clang", "13")
+@pytest.mark.tool("clang", "16")
 @pytest.mark.skipif(platform.system() != "Windows", reason="requires Win")
 class TestLLVMClang:
     """ External LLVM/clang, with different CMake generators
@@ -74,7 +73,7 @@ class TestLLVMClang:
 
     @pytest.mark.tool("mingw64")
     @pytest.mark.tool("visual_studio", "17")
-    @pytest.mark.tool("clang", "13")  # repeated, for priority over the mingw64 clang
+    @pytest.mark.tool("clang", "16")  # repeated, for priority over the mingw64 clang
     @pytest.mark.parametrize("runtime", ["static", "dynamic"])
     def test_clang_mingw(self, client, runtime):
         """ compiling with an LLVM-clang installed, which uses by default the
@@ -86,7 +85,7 @@ class TestLLVMClang:
         # clang compilations in Windows will use MinGW Makefiles by default
         assert 'cmake -G "MinGW Makefiles"' in client.out
         assert "GNU-like command-line" in client.out
-        assert "main __clang_major__13" in client.out
+        assert "main __clang_major__16" in client.out
         assert "main _MSC_VER193" in client.out
         assert "main _MSVC_LANG2014" in client.out
         assert "main _M_X64 defined" in client.out
@@ -107,7 +106,7 @@ class TestLLVMClang:
 
         assert 'cmake -G "{}"'.format(generator) in client.out
         assert "GNU-like command-line" in client.out
-        assert "main __clang_major__13" in client.out
+        assert "main __clang_major__16" in client.out
         assert "main _MSC_VER193" in client.out
         assert "main _MSVC_LANG2014" in client.out
         assert "main _M_X64 defined" in client.out
@@ -117,7 +116,7 @@ class TestLLVMClang:
         check_vs_runtime(cmd, client, "17", build_type="Release", static_runtime=False)
 
     @pytest.mark.tool("visual_studio", "16")
-    @pytest.mark.tool("clang", "13")  # repeated, for priority over the mingw64 clang
+    @pytest.mark.tool("clang", "16")  # repeated, for priority over the mingw64 clang
     def test_clang_cmake_runtime_version(self, client):
         generator = "Ninja"
         # Make sure that normal CMakeLists with verify=False works
@@ -129,7 +128,7 @@ class TestLLVMClang:
 
         assert 'cmake -G "{}"'.format(generator) in client.out
         assert "GNU-like command-line" in client.out
-        assert "main __clang_major__13" in client.out
+        assert "main __clang_major__16" in client.out
         # Check this! Clang compiler in Windows is reporting MSC_VER and MSVC_LANG!
         assert "main _MSC_VER192" in client.out
         assert "main _MSVC_LANG2017" in client.out
@@ -155,7 +154,8 @@ class TestVSClangCL:
                    '-c tools.cmake.cmaketoolchain:generator="{}"'.format(generator))
         assert 'cmake -G "{}"'.format(generator) in client.out
         assert "MSVC-like command-line" in client.out
-        assert "main __clang_major__17" in client.out
+        # My local is 17, but CI ClangCL still 16
+        assert "main __clang_major__16" in client.out
         # Check this! Clang compiler in Windows is reporting MSC_VER and MSVC_LANG!
         assert "main _MSC_VER193" in client.out
         assert "main _MSVC_LANG2017" in client.out
@@ -164,7 +164,7 @@ class TestVSClangCL:
         assert "-m64" not in client.out
         cmd = re.search(r"MYCMD=(.*)!", str(client.out)).group(1)
         cmd = cmd + ".exe"
-        check_vs_runtime(cmd, client, "16", build_type="Release", static_runtime=False)
+        check_vs_runtime(cmd, client, "17", build_type="Release", static_runtime=False)
 
 
 @pytest.mark.tool("cmake")
@@ -182,7 +182,7 @@ class TestMsysClang:
         # clang compilations in Windows will use MinGW Makefiles by default
         assert 'cmake -G "MinGW Makefiles"' in client.out
         # TODO: Version is still not controlled
-        assert "main __clang_major__14" in client.out
+        assert "main __clang_major__15" in client.out
         # Not using libstdc++
         assert "_GLIBCXX_USE_CXX11_ABI" not in client.out
         assert "main __cplusplus2014" in client.out
@@ -212,7 +212,7 @@ class TestMsysClang:
         # clang compilations in Windows will use MinGW Makefiles by default
         assert 'cmake -G "MinGW Makefiles"' in client.out
         # TODO: Version is still not controlled
-        assert "main __clang_major__14" in client.out
+        assert "main __clang_major__15" in client.out
         assert "main _GLIBCXX_USE_CXX11_ABI 0" in client.out
         assert "main __cplusplus2014" in client.out
         assert "main __GNUC__" in client.out
@@ -241,7 +241,7 @@ class TestMsysClang:
         client.run(f"create . --name=pkg --version=0.1 -pr=clang")
         # clang compilations in Windows will use MinGW Makefiles by default
         assert 'cmake -G "MinGW Makefiles"' in client.out
-        assert "main __clang_major__14" in client.out
+        assert "main __clang_major__15" in client.out
         assert "GLIBCXX" not in client.out
         assert "cplusplus" not in client.out
         assert "main __GNUC__" in client.out
@@ -260,27 +260,22 @@ class TestMsysClang:
 
 
 @pytest.mark.tool("cmake")
-@pytest.mark.tool("clang", "12")
+@pytest.mark.tool("ninja")
+@pytest.mark.tool("clang", "16")
 @pytest.mark.skipif(platform.system() != "Windows", reason="requires Win")
 def test_error_clang_cmake_ninja_custom_cxx(client):
-    with environment_update({"CXX": "/no/exist/clang++"}):
-        client.run("create . --name=pkg --version=0.1 -pr=clang -c tools.cmake.cmaketoolchain:generator=Ninja",
-                   assert_error=True)
-        assert 'Could not find compiler' in client.out
-        assert '/no/exist/clang++' in client.out
-
     clang_profile = textwrap.dedent("""
         [settings]
         os=Windows
         arch=x86_64
         build_type=Release
         compiler=clang
-        compiler.version=12
+        compiler.version=16
         [buildenv]
         CXX=/no/exist/clang++
         """)
     client.save({"clang":     clang_profile})
-    client.run("create . --name=pkg --version=0.1 -pr=clang -c tools.cmake.cmaketoolchain:generator=Ninja",
-               assert_error=True)
+    client.run("create . --name=pkg --version=0.1 -pr=clang "
+               "-c tools.cmake.cmaketoolchain:generator=Ninja", assert_error=True)
     assert 'Could not find compiler' in client.out
     assert '/no/exist/clang++' in client.out
diff --git a/conans/test/functional/toolchains/microsoft/test_msbuild.py b/conans/test/functional/toolchains/microsoft/test_msbuild.py
index fd90b06d3..104813008 100644
--- a/conans/test/functional/toolchains/microsoft/test_msbuild.py
+++ b/conans/test/functional/toolchains/microsoft/test_msbuild.py
@@ -426,7 +426,7 @@ class TestWin:
     def test_toolchain_win_vs2017(self, compiler, version, runtime, cppstd):
         self.check_toolchain_win(compiler, version, runtime, cppstd, ide_version=15)
 
-    @pytest.mark.tool("cmake", "3.21")
+    @pytest.mark.tool("cmake", "3.23")
     @pytest.mark.tool("visual_studio", "17")
     @pytest.mark.parametrize("compiler,version,runtime,cppstd",
                              [("msvc", "193", "static", "17")])
diff --git a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
index c71e536a5..5551f171c 100644
--- a/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
+++ b/conans/test/functional/toolchains/microsoft/test_msbuilddeps.py
@@ -713,7 +713,7 @@ def test_build_vs_project_with_a_vs2017():
 
 
 @pytest.mark.tool("visual_studio", "17")
-@pytest.mark.tool("cmake")
+@pytest.mark.tool("cmake", "3.23")
 @pytest.mark.skipif(platform.system() != "Windows", reason="Requires MSBuild")
 def test_build_vs_project_with_a_vs2022():
     check_build_vs_project_with_a("193")
@@ -782,10 +782,16 @@ def check_build_vs_project_with_a(vs_version):
     main_cpp = gen_function_cpp(name="main", includes=["hello"], calls=["hello"])
     files["MyProject/main.cpp"] = main_cpp
     files["conanfile.py"] = consumer
+    # INJECT PROPS FILES
     props = os.path.join(client.current_folder, "conandeps.props")
-    old = r'<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />'
-    new = old + '<Import Project="{props}" />'.format(props=props)
+    old = r'<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />'
+    new = old + f'<Import Project="{props}" />'
+    files["MyProject/MyProject.vcxproj"] = files["MyProject/MyProject.vcxproj"].replace(old, new)
+    old = r'<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />'
+    toolchain = os.path.join(client.current_folder, "conantoolchain.props")
+    new = f'<Import Project="{toolchain}" />' + old
     files["MyProject/MyProject.vcxproj"] = files["MyProject/MyProject.vcxproj"].replace(old, new)
+
     client.save(files, clean_first=True)
     client.run('build . -s compiler=msvc'
                ' -s compiler.version={vs_version}'.format(vs_version=vs_version))
@@ -803,7 +809,7 @@ def test_build_vs_project_with_test_requires_vs2017():
 
 
 @pytest.mark.tool("visual_studio", "17")
-@pytest.mark.tool("cmake")
+@pytest.mark.tool("cmake", "3.23")
 @pytest.mark.skipif(platform.system() != "Windows", reason="Requires MSBuild")
 def test_build_vs_project_with_test_requires_vs2022():
     check_build_vs_project_with_test_requires("193")
@@ -837,10 +843,17 @@ def check_build_vs_project_with_test_requires(vs_version):
     main_cpp = gen_function_cpp(name="main", includes=["mydep_pkg_team"], calls=["mydep_pkg_team"])
     files["MyProject/main.cpp"] = main_cpp
     files["conanfile.py"] = consumer
+
+    # INJECT PROPS FILES
     props = os.path.join(client.current_folder, "conandeps.props")
-    old = r'<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />'
-    new = old + '<Import Project="{props}" />'.format(props=props)
+    old = r'<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />'
+    new = old + f'<Import Project="{props}" />'
+    files["MyProject/MyProject.vcxproj"] = files["MyProject/MyProject.vcxproj"].replace(old, new)
+    old = r'<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />'
+    toolchain = os.path.join(client.current_folder, "conantoolchain.props")
+    new = f'<Import Project="{toolchain}" />' + old
     files["MyProject/MyProject.vcxproj"] = files["MyProject/MyProject.vcxproj"].replace(old, new)
+
     client.save(files, clean_first=True)
     client.run('build .  -s compiler.version={vs_version}'.format(vs_version=vs_version))
     client.run_command(r"x64\Release\MyProject.exe")
diff --git a/conans/test/functional/utils.py b/conans/test/functional/utils.py
index 611fb8bab..7d92a89d1 100644
--- a/conans/test/functional/utils.py
+++ b/conans/test/functional/utils.py
@@ -46,7 +46,8 @@ def check_vs_runtime(artifact, client, vs_version, build_type, architecture="amd
                     assert "libunwind.dll" not in client.out
                     assert "libc++.dll" not in client.out
                 else:
-                    assert "libunwind.dll" in client.out
+                    # Latest clangs from subsystems no longer depend on libunwind
+                    assert "libunwind.dll" not in client.out
                     assert "libc++.dll" in client.out
             else:
                 raise Exception("unknown {}".format(subsystem))
diff --git a/conans/test/integration/command_v2/test_cache_save_restore.py b/conans/test/integration/command_v2/test_cache_save_restore.py
index 046e0fb0e..2d5301b60 100644
--- a/conans/test/integration/command_v2/test_cache_save_restore.py
+++ b/conans/test/integration/command_v2/test_cache_save_restore.py
@@ -211,3 +211,9 @@ def test_cache_save_subfolder():
     c.run("export .")
     c.run("cache save * --file=subfolder/cache.tgz")
     assert os.path.exists(os.path.join(c.current_folder, "subfolder", "cache.tgz"))
+
+
+def test_error_restore_not_existing():
+    c = TestClient()
+    c.run("cache restore potato.tgz", assert_error=True)
+    assert "ERROR: Restore archive doesn't exist in " in c.out
diff --git a/conans/test/integration/command_v2/test_version.py b/conans/test/integration/command_v2/test_version.py
index 6ddc7aff1..3f397d105 100644
--- a/conans/test/integration/command_v2/test_version.py
+++ b/conans/test/integration/command_v2/test_version.py
@@ -21,8 +21,17 @@ def test_version_json():
     t.run("version --format=json")
     js = json.loads(t.stdout)
     assert js["version"] == __version__
+    assert js["conan_path"] == sys.argv[0]
     assert js["python"]["version"] == _python_version()
     assert js["python"]["sys_version"] == _sys_version()
+    assert js["python"]["sys_executable"] == sys.executable
+    assert js["python"]["is_frozen"] == getattr(sys, 'frozen', False)
+    assert js["python"]["architecture"] == platform.machine()
+    assert js["system"]["version"] == platform.version()
+    assert js["system"]["platform"] == platform.platform()
+    assert js["system"]["system"] == platform.system()
+    assert js["system"]["release"] == platform.release()
+    assert js["system"]["cpu"] == platform.processor()
 
 
 def test_version_text():
@@ -47,6 +56,16 @@ def test_version_raw():
 def _validate_text_output(output):
     lines = output.splitlines()
     assert f'version: {__version__}' in lines
+    assert f'conan_path: {sys.argv[0]}' in lines
     assert 'python' in lines
     assert f'  version: {_python_version()}' in lines
     assert f'  sys_version: {_sys_version()}' in lines
+    assert f'  sys_executable: {sys.executable}' in lines
+    assert f'  is_frozen: {getattr(sys, "frozen", False)}' in lines
+    assert f'  architecture: {platform.machine()}' in lines
+    assert 'system' in lines
+    assert f'  version: {platform.version()}' in lines
+    assert f'  platform: {platform.platform()}' in lines
+    assert f'  system: {platform.system()}' in lines
+    assert f'  release: {platform.release()}' in lines
+    assert f'  cpu: {platform.processor()}' in lines
diff --git a/conans/test/integration/export_sources_test.py b/conans/test/integration/export_sources_test.py
index 0b30d04e3..d68850b3b 100644
--- a/conans/test/integration/export_sources_test.py
+++ b/conans/test/integration/export_sources_test.py
@@ -17,7 +17,7 @@ def test_exports():
             version = "0.1"
             exports = "*.h"
         """)
-    c = TestClient()
+    c = TestClient(light=True)
     c.save({"conanfile.py": conanfile,
             "hello.h": "hello",
             "data.txt": "data"})
@@ -44,7 +44,7 @@ def test_exports_sources():
             version = "0.1"
             exports_sources = "*.h"
         """)
-    c = TestClient()
+    c = TestClient(light=True)
     c.save({"conanfile.py": conanfile,
             "hello.h": "hello",
             "data.txt": "data"})
@@ -64,9 +64,24 @@ def test_test_package_copied():
     """The exclusion of the test_package folder have been removed so now we test that indeed is
     exported"""
 
-    client = TestClient()
+    client = TestClient(light=True)
     conanfile = GenConanfile().with_exports("*").with_exports_sources("*")
     client.save({"conanfile.py": conanfile,
                  "test_package/foo.txt": "bar"})
     client.run("export . --name foo --version 1.0")
     assert "Copied 2 '.txt' file" in client.out
+
+
+def test_source_changes_generate_new_revisions():
+    tc = TestClient(light=True)
+    tc.save({"conanfile.py": GenConanfile("lib", "1.0").with_exports_sources("file.h"),
+             "file.h": "Hello World!"})
+
+    tc.run("export .")
+    exported_rev = tc.exported_recipe_revision()
+
+    tc.save({"file.h": "Bye World!"})
+    tc.run("export .")
+    exported_rev_new = tc.exported_recipe_revision()
+
+    assert exported_rev != exported_rev_new
diff --git a/conans/test/integration/py_requires/python_requires_test.py b/conans/test/integration/py_requires/python_requires_test.py
index 6aadeab9d..68cb2d1ee 100644
--- a/conans/test/integration/py_requires/python_requires_test.py
+++ b/conans/test/integration/py_requires/python_requires_test.py
@@ -27,7 +27,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         client.run("export . --name=base --version=1.1 --user=user --channel=testing")
 
     def test_reuse(self):
-        client = TestClient(default_server_user=True)
+        client = TestClient(light=True, default_server_user=True)
         self._define_base(client)
         reuse = textwrap.dedent("""
             from conan import ConanFile
@@ -50,9 +50,22 @@ class PyRequiresExtendTest(unittest.TestCase):
         client.run("remove * -c")
         client.run("download pkg/0.1@user/testing#latest:* -r default")
         self.assertIn(f"pkg/0.1@user/testing: Package installed {package_id}", client.out)
+        # But it's broken with a single download
+        client.run("install --requires=pkg/0.1@user/testing -nr", assert_error=True)
+        assert "Cannot resolve python_requires 'base/1.1@user/testing'" in client.out
+        # If pyrequires are expected, then first graph info -f=json and then get recipes from pkglist
+        client.run("remove * -c")
+        client.run("graph info --requires=pkg/0.1@user/testing -f=json", redirect_stdout="graph_info.json")
+        # We can even remove from the cache now (The pyrequires is already downloaded in the above step)
+        client.run("remove * -c")
+        client.run("list --graph=graph_info.json --graph-recipes=* -f=json", redirect_stdout="pkglist.json")
+        client.run("download --list=pkglist.json -r default")
+        assert "Downloading recipe 'base/1.1@user/testing" in client.out
+        client.run("install --requires=pkg/0.1@user/testing -nr")
+        self.assertIn("pkg/0.1@user/testing: My cool package_info!", client.out)
 
     def test_reuse_super(self):
-        client = TestClient(default_server_user=True)
+        client = TestClient(light=True, default_server_user=True)
         self._define_base(client)
         reuse = textwrap.dedent("""
                from conan import ConanFile
@@ -70,7 +83,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         assert "conanfile.py (pkg/0.1): MY OWN SOURCE" in client.out
 
     def test_reuse_dot(self):
-        client = TestClient(default_server_user=True)
+        client = TestClient(light=True, default_server_user=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             class MyConanfileBase(ConanFile):
@@ -90,7 +103,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("pkg/0.1@user/testing: My cool build!", client.out)
 
     def test_with_alias(self):
-        client = TestClient()
+        client = TestClient(light=True)
         self._define_base(client)
         client.alias("base/latest@user/testing", "base/1.1@user/testing")
 
@@ -108,7 +121,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         assert "python-requires 'alias' are not supported in Conan 2.0" in client.out
 
     def test_reuse_version_ranges(self):
-        client = TestClient()
+        client = TestClient(light=True)
         self._define_base(client)
 
         reuse = textwrap.dedent("""
@@ -127,7 +140,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("pkg/0.1@user/testing: My cool package_info!", client.out)
 
     def test_multiple_reuse(self):
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             class SourceBuild(ConanFile):
@@ -165,7 +178,7 @@ class PyRequiresExtendTest(unittest.TestCase):
 
     @staticmethod
     def test_transitive_access():
-        client = TestClient()
+        client = TestClient(light=True)
         client.save({"conanfile.py": GenConanfile()})
         client.run("export . --name=base --version=1.0 --user=user --channel=channel")
 
@@ -199,7 +212,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         assert "pkg/0.1@user/channel: Created package" in client.out
 
     def test_multiple_requires_error(self):
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             myvar = 123
@@ -248,7 +261,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("consumer/0.1@user/testing: PKG2F : 234", client.out)
 
     def test_local_import(self):
-        client = TestClient(default_server_user=True)
+        client = TestClient(light=True, default_server_user=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             import mydata
@@ -296,7 +309,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn(f"pkg/0.1@user/testing: Package installed {package_id}", client.out)
 
     def test_reuse_class_members(self):
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             class MyConanfileBase(ConanFile):
@@ -343,7 +356,7 @@ class PyRequiresExtendTest(unittest.TestCase):
 
     def test_reuse_system_requirements(self):
         # https://github.com/conan-io/conan/issues/7718
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
            from conan import ConanFile
            class MyConanfileBase(ConanFile):
@@ -363,7 +376,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("pkg/0.1@user/testing: My system_requirements pkg being called!", client.out)
 
     def test_reuse_requirements(self):
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
                    from conan import ConanFile
                    class MyConanfileBase(ConanFile):
@@ -462,7 +475,7 @@ class PyRequiresExtendTest(unittest.TestCase):
 
     def test_transitive_imports_conflicts(self):
         # https://github.com/conan-io/conan/issues/3874
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             import myhelper
@@ -502,7 +515,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("pkg/0.1@user/testing: MyOtherHelperOutput!", client.out)
 
     def test_update(self):
-        client = TestClient(default_server_user=True)
+        client = TestClient(light=True, default_server_user=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             somevar = 42
@@ -513,7 +526,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         client.run("export . --name=base --version=1.1 --user=user --channel=testing")
         client.run("upload * --confirm -r default")
 
-        client2 = TestClient(servers=client.servers, inputs=["user", "password"])
+        client2 = TestClient(light=True, servers=client.servers, inputs=["user", "password"])
         reuse = textwrap.dedent("""
             from conan import ConanFile
             class PkgTest(ConanFile):
@@ -539,7 +552,7 @@ class PyRequiresExtendTest(unittest.TestCase):
     def test_update_ranges(self):
         # Same as the above, but using a version range, and no --update
         # https://github.com/conan-io/conan/issues/4650#issuecomment-497464305
-        client = TestClient(default_server_user=True)
+        client = TestClient(light=True, default_server_user=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             somevar = 42
@@ -550,7 +563,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         client.run("export . --name=base --version=1.1 --user=user --channel=testing")
         client.run("upload * --confirm -r default")
 
-        client2 = TestClient(servers=client.servers, inputs=["user", "password"])
+        client2 = TestClient(light=True, servers=client.servers, inputs=["user", "password"])
         reuse = textwrap.dedent("""
             from conan import ConanFile
             class PkgTest(ConanFile):
@@ -574,7 +587,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("conanfile.py: PYTHON REQUIRE VAR 143", client2.out)
 
     def test_duplicate_pyreq(self):
-        t = TestClient()
+        t = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             class PyReq(ConanFile):
@@ -596,7 +609,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("The python_require 'pyreq' already exists", t.out)
 
     def test_local_build(self):
-        client = TestClient()
+        client = TestClient(light=True)
         client.save({"conanfile.py": "var=42\n" + str(GenConanfile())})
         client.run("export . --name=tool --version=0.1 --user=user --channel=channel")
         conanfile = textwrap.dedent("""
@@ -619,7 +632,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         client.run("export-pkg . --name=pkg1 --version=0.1 --user=user --channel=testing")
 
     def test_reuse_name_version(self):
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             from conan.tools.files import load
@@ -660,7 +673,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("mypkg/myversion: Pkg1 package: mypkg:myversion", client.out)
 
     def test_reuse_export_sources(self):
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             class MyConanfileBase(ConanFile):
@@ -718,7 +731,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("conanfile.py: Build: tool other: otherheader", client.out)
 
     def test_reuse_editable_exports(self):
-        client = TestClient()
+        client = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             class MyConanfileBase(ConanFile):
@@ -749,7 +762,7 @@ class PyRequiresExtendTest(unittest.TestCase):
                     self.output.info("Build: tool other: %s" % load(self, other_h))
             """)
 
-        client2 = TestClient(cache_folder=client.cache_folder)
+        client2 = TestClient(light=True, cache_folder=client.cache_folder)
         client2.save({"conanfile.py": conanfile,
                       "name.txt": "MyPkg",
                       "version.txt": "MyVersion"})
@@ -764,7 +777,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("conanfile.py: Build: tool other: otherheader", client2.out)
 
     def test_build_id(self):
-        client = TestClient(default_server_user=True)
+        client = TestClient(light=True, default_server_user=True)
         self._define_base(client)
         reuse = textwrap.dedent("""
             from conan import ConanFile
@@ -782,7 +795,7 @@ class PyRequiresExtendTest(unittest.TestCase):
         self.assertIn("pkg/0.1@user/testing: My cool package_info!", client.out)
 
     def test_options_errors(self):
-        c = TestClient()
+        c = TestClient(light=True)
         base = textwrap.dedent("""
             from conan import ConanFile
             class BaseConan:
@@ -822,7 +835,7 @@ class PyRequiresExtendTest(unittest.TestCase):
 
 def test_transitive_python_requires():
     # https://github.com/conan-io/conan/issues/8546
-    client = TestClient()
+    client = TestClient(light=True)
     conanfile = textwrap.dedent("""
         from conan import ConanFile
         myvar = 123
@@ -865,7 +878,7 @@ def test_transitive_python_requires():
 
 
 def test_transitive_diamond_python_requires():
-    client = TestClient()
+    client = TestClient(light=True)
     conanfile = textwrap.dedent("""
         from conan import ConanFile
         myvar = 123
@@ -939,7 +952,7 @@ def test_transitive_diamond_python_requires():
 class TestConflictPyRequires:
     # https://github.com/conan-io/conan/issues/15016
     def test_diamond_conflict_fixed(self):
-        c = TestClient()
+        c = TestClient(light=True)
 
         c.save({"tool/conanfile.py": GenConanfile("tool"),
                 "sub1/conanfile.py": GenConanfile("sub1", "1.0").with_python_requires("tool/1.0"),
@@ -953,7 +966,7 @@ class TestConflictPyRequires:
         assert "Conflict in py_requires tool/1.0 - tool/1.1" in c.out
 
     def test_diamond_conflict_ranges(self):
-        c = TestClient()
+        c = TestClient(light=True)
 
         c.save({"tool/conanfile.py": GenConanfile("tool"),
                 "sub1/conanfile.py": GenConanfile("sub1", "1.0").with_python_requires("tool/[*]"),
@@ -972,7 +985,7 @@ def test_multiple_reuse():
         # https://github.com/conan-io/conan/issues/11589
     """
 
-    c = TestClient()
+    c = TestClient(light=True)
     common = textwrap.dedent("""
         from conan import ConanFile
         def mycommon():
@@ -1023,7 +1036,7 @@ class TestTestPackagePythonRequire:
         """ test how to test_package a python_require
         """
 
-        c = TestClient()
+        c = TestClient(light=True)
         conanfile = textwrap.dedent("""
             from conan import ConanFile
             def mycommon():
@@ -1086,7 +1099,7 @@ class TestResolveRemote:
         """ a "conan export" command should work even when a python_requires
         is in the server
         """
-        c = TestClient(default_server_user=True)
+        c = TestClient(light=True, default_server_user=True)
         c.save({"common/conanfile.py": GenConanfile("tool", "0.1"),
                 "pkg/conanfile.py": GenConanfile("pkg", "0.1").with_python_requires("tool/0.1")})
         c.run("export common")
@@ -1110,7 +1123,7 @@ class TestResolveRemote:
     def test_missing_python_require_error(self):
         """ make sure the error is clear enough for users UX
         """
-        c = TestClient()
+        c = TestClient(light=True)
         c.save({"pkg/conanfile.py": GenConanfile("pkg", "0.1").with_python_requires("tool/0.1")})
         c.run("create pkg", assert_error=True)
         assert "Cannot resolve python_requires 'tool/0.1'" in c.out
@@ -1120,7 +1133,7 @@ class TestTransitiveExtend:
     # https://github.com/conan-io/conan/issues/10511
     # https://github.com/conan-io/conan/issues/10565
     def test_transitive_extend(self):
-        client = TestClient()
+        client = TestClient(light=True)
         company = textwrap.dedent("""
             from conan import ConanFile
             class CompanyConanFile(ConanFile):
@@ -1165,7 +1178,7 @@ class TestTransitiveExtend:
         assert "conanfile.py (consumer/1.0): Msg2:company!!!" in client.out
 
     def test_transitive_extend2(self):
-        client = TestClient()
+        client = TestClient(light=True)
         company = textwrap.dedent("""
             from conan import ConanFile
             class CompanyConanFile(ConanFile):
@@ -1220,7 +1233,7 @@ def test_multi_top_missing_from_remote():
     """
     https://github.com/conan-io/conan/issues/13656
     """
-    tc = TestClient(default_server_user=True)
+    tc = TestClient(light=True, default_server_user=True)
     tc.save({"conanfile.py": GenConanfile("base", "1.1")})
     tc.run("create . --user=user --channel=testing")
 
@@ -1248,7 +1261,7 @@ def test_transitive_range_not_found_in_cache():
     """
     https://github.com/conan-io/conan/issues/13761
     """
-    c = TestClient()
+    c = TestClient(light=True)
     c.save({"conanfile.py": GenConanfile("pr", "1.0")})
     c.run("create .")
 
@@ -1262,7 +1275,7 @@ def test_transitive_range_not_found_in_cache():
 
 
 def test_export_pkg():
-    c = TestClient()
+    c = TestClient(light=True)
     c.save({"conanfile.py": GenConanfile("pytool", "0.1").with_package_type("python-require")})
     c.run("export-pkg .", assert_error=True)
     assert "export-pkg can only be used for binaries, not for 'python-require'" in c.out
@@ -1273,7 +1286,7 @@ def test_export_pkg():
 
 
 def test_py_requires_override_method():
-    tc = TestClient()
+    tc = TestClient(light=True)
     pyreq = textwrap.dedent("""
         from conan import ConanFile
         class MyConanfileBase:
diff --git a/conans/test/integration/remote/multi_remote_test.py b/conans/test/integration/remote/multi_remote_test.py
index 0e40e9a59..515ad32dd 100644
--- a/conans/test/integration/remote/multi_remote_test.py
+++ b/conans/test/integration/remote/multi_remote_test.py
@@ -120,35 +120,37 @@ class MultiRemotesTest(unittest.TestCase):
         client = TestClient(servers=self.servers, inputs=2*["admin", "password"])
 
         self._create(client, "hello0", "0.0")
+        default_remote_rev = client.exported_recipe_revision()
         client.run("install --requires=hello0/0.0@lasote/stable --build missing")
+
         client.run("upload hello0/0.0@lasote/stable -r default")
         sleep(1)  # For timestamp and updates checks
         self._create(client, "hello0", "0.0", modifier=" ")
+        local_remote_rev = client.exported_recipe_revision()
         client.run("install --requires=hello0/0.0@lasote/stable --build missing")
+
         client.run("upload hello0/0.0@lasote/stable#latest -r local")
         client.run("remove '*' -c")
 
         client.run("install --requires=hello0/0.0@lasote/stable")
         # If we don't set a remote we find between all remotes and get the first match
-        self.assertIn("hello0/0.0@lasote/stable#20f1a1ed31481dfb59bdfd22f1aa1093 - Downloaded",
-                      client.out)
+        assert f"hello0/0.0@lasote/stable#{default_remote_rev} - Downloaded" in client.out
         client.run("install --requires=hello0/0.0@lasote/stable --update")
-        self.assertIn("hello0/0.0@lasote/stable#f49dd3f4009e57f521520364d8468757 - Updated",
-                      client.out)
+        assert f"hello0/0.0@lasote/stable#{local_remote_rev} - Updated" in client.out
 
         client.run("install --requires=hello0/0.0@lasote/stable --update -r default")
-        self.assertIn("hello0/0.0@lasote/stable#f49dd3f4009e57f521520364d8468757 - Newer",
+        self.assertIn(f"hello0/0.0@lasote/stable#{local_remote_rev} - Newer",
                       client.out)
 
         sleep(1)  # For timestamp and updates checks
         # Check that it really updates in case of newer package uploaded to the associated remote
         client_b = TestClient(servers=self.servers, inputs=3*["admin", "password"])
         self._create(client_b, "hello0", "0.0", modifier="  ")
+        new_local_remote_rev = client_b.exported_recipe_revision()
         client_b.run("install --requires=hello0/0.0@lasote/stable --build missing")
         client_b.run("upload hello0/0.0@lasote/stable -r local")
         client.run("install --requires=hello0/0.0@lasote/stable --update")
-        self.assertIn("hello0/0.0@lasote/stable#1169dcd60e44cc939d0b475693195bd4 - Updated",
-                      client.out)
+        assert f"hello0/0.0@lasote/stable#{new_local_remote_rev} - Updated" in client.out
 
 
 class MultiRemoteTest(unittest.TestCase):