Repository: conan-io/conan
Pull request #13141 (2023-02-16 10:16:02)

MesonToolchain: cl as default compiler in case of cross-build with Visual Studio in MesonToolchain
Changelog: (Feature):  Allow users to cross-build out of the box with Visual Studio recipes based on MesonToolchain
Docs: https://github.com/conan-io/docs/pull/XXXX

closes https://github.com/conan-io/conan/issues/13139

- [x] Refer to the issue that supports this Pull Request.
- [x] If the issue has missing info, explain the purpose/use case/pain/need that covers this Pull Request.
- [x] I've read the [Contributing guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [x] I've followed the PEP8 style guides for Python code.
- [ ] I've opened another PR in the Conan docs repo to the ``develop`` branch, documenting this one. 

<sup>**Note:** By default this PR will skip the slower tests and will use a limited set of python versions. Check [here](https://github.com/conan-io/conan/blob/develop/.github/PR_INCREASE_TESTING.md) how to increase the testing level by writing some tags in the current PR body text.</sup>



Patch:
diff --git a/conan/tools/_compilers.py b/conan/tools/_compilers.py
index fb976a469..8172bd6df 100644
--- a/conan/tools/_compilers.py
+++ b/conan/tools/_compilers.py
@@ -165,7 +165,7 @@ def build_type_flags(settings):
                      "MinSizeRel": ["-xO2", "-xspace"],
                      }.get(build_type, [])
             return flags
-    return ""
+    return []
 
 
 def use_win_mingw(conanfile):
diff --git a/conan/tools/files/__init__.py b/conan/tools/files/__init__.py
index 2517002f9..f47cd2bef 100644
--- a/conan/tools/files/__init__.py
+++ b/conan/tools/files/__init__.py
@@ -1,5 +1,6 @@
 from conan.tools.files.files import load, save, mkdir, rmdir, rm, ftp_download, download, get, \
-    rename, chdir, unzip, replace_in_file, collect_libs, check_md5, check_sha1, check_sha256
+    rename, chdir, unzip, replace_in_file, collect_libs, check_md5, check_sha1, check_sha256, \
+    move_folder_contents
 
 from conan.tools.files.patches import patch, apply_conandata_patches, export_conandata_patches
 from conan.tools.files.cpp_package import CppPackage
diff --git a/conan/tools/files/files.py b/conan/tools/files/files.py
index e46e02b2f..3a1d9cacd 100644
--- a/conan/tools/files/files.py
+++ b/conan/tools/files/files.py
@@ -543,19 +543,39 @@ def collect_libs(conanfile, folder=None):
     return result
 
 
-# TODO: Do NOT document this yet. It is unclear the interface, maybe should be split
-def swap_child_folder(parent_folder, child_folder):
-    """ replaces the current folder contents with the contents of one child folder. This
-    is used in the SCM monorepo flow, when it is necessary to use one subproject subfolder
-    to replace the whole cloned git repo
+def move_folder_contents(conanfile, src_folder, dst_folder):
+    """ replaces the dst_folder contents with the contents of the src_folder, which can be a
+    child folder of dst_folder. This is used in the SCM monorepo flow, when it is necessary
+    to use one subproject subfolder to replace the whole cloned git repo
+    /base-folder                       /base-folder
+        /pkg  (src folder)                 /other/<otherfiles>
+          /other/<otherfiles>              /pkg/<pkgfiles>
+          /pkg/<pkgfiles>                  <files>
+          <files>
+        /siblings
+        <siblingsfiles>
     """
-    for f in os.listdir(parent_folder):
-        if f != child_folder:
-            path = os.path.join(parent_folder, f)
-            if os.path.isfile(path):
-                os.remove(path)
+    # Remove potential "siblings" folders not wanted
+    src_folder_name = os.path.basename(src_folder)
+    for f in os.listdir(dst_folder):
+        if f != src_folder_name:  # FIXME: Only works for 1st level subfolder
+            dst = os.path.join(dst_folder, f)
+            if os.path.isfile(dst):
+                os.remove(dst)
             else:
-                _internal_rmdir(path)
-    child = os.path.join(parent_folder, child_folder)
-    for f in os.listdir(child):
-        shutil.move(os.path.join(child, f), os.path.join(parent_folder, f))
+                _internal_rmdir(dst)
+
+    # Move all the contents
+    for f in os.listdir(src_folder):
+        src = os.path.join(src_folder, f)
+        dst = os.path.join(dst_folder, f)
+        if not os.path.exists(dst):
+            shutil.move(src, dst_folder)
+        else:
+            for sub_src in os.listdir(src):
+                shutil.move(os.path.join(src, sub_src), dst)
+            _internal_rmdir(src)
+    try:
+        os.rmdir(src_folder)
+    except OSError:
+        pass
diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py
index dcb7d06f9..f71cc56b2 100644
--- a/conan/tools/meson/toolchain.py
+++ b/conan/tools/meson/toolchain.py
@@ -155,15 +155,15 @@ class MesonToolchain(object):
                 default_comp = "clang"
                 default_comp_cpp = "clang++"
         else:
-            if "Visual" in compiler or compiler == "msvc":
-                default_comp = "cl"
-                default_comp_cpp = "cl"
-            elif "clang" in compiler:
+            if "clang" in compiler:
                 default_comp = "clang"
                 default_comp_cpp = "clang++"
             elif compiler == "gcc":
                 default_comp = "gcc"
                 default_comp_cpp = "g++"
+        if "Visual" in compiler or compiler == "msvc":
+            default_comp = "cl"
+            default_comp_cpp = "cl"
 
         # Read configuration for compilers
         compilers_by_conf = self._conanfile.conf.get("tools.build:compiler_executables", default={},
diff --git a/conans/__init__.py b/conans/__init__.py
index 7458ba70e..d39bf7eb7 100644
--- a/conans/__init__.py
+++ b/conans/__init__.py
@@ -20,4 +20,4 @@ OAUTH_TOKEN = "oauth_token"
 SERVER_CAPABILITIES = [COMPLEX_SEARCH_CAPABILITY, REVISIONS]  # Server is always with revisions
 DEFAULT_REVISION_V1 = "0"
 
-__version__ = '1.59.0-dev'
+__version__ = '1.61.0-dev'
diff --git a/conans/client/cache/cache.py b/conans/client/cache/cache.py
index b827edb16..156580103 100644
--- a/conans/client/cache/cache.py
+++ b/conans/client/cache/cache.py
@@ -5,6 +5,7 @@ from collections import OrderedDict
 
 from jinja2 import Environment, select_autoescape, FileSystemLoader, ChoiceLoader, Template
 
+from conan import conan_version
 from conans.assets.templates import dict_loader
 from conans.client.cache.editable import EditablePackages
 from conans.client.cache.remote_registry import RemoteRegistry
@@ -173,7 +174,8 @@ class ClientCache(object):
                 distro = None
                 if platform.system() in ["Linux", "FreeBSD"]:
                     import distro
-                content = Template(text).render({"platform": platform, "os": os, "distro": distro})
+                content = Template(text).render({"platform": platform, "os": os, "distro": distro,
+                                                 "conan_version": conan_version})
                 self._new_config.loads(content)
         return self._new_config
 
diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py
index 7971b1feb..b3b71ee24 100644
--- a/conans/client/conf/__init__.py
+++ b/conans/client/conf/__init__.py
@@ -61,7 +61,7 @@ _t_default_settings_yml = Template(textwrap.dedent("""
         Macos:
             version: [None, "10.6", "10.7", "10.8", "10.9", "10.10", "10.11", "10.12", "10.13", "10.14", "10.15", "11.0", "12.0", "13.0"]
             sdk: [None, "macosx"]
-            sdk_version: [None, "10.13", "10.14", "10.15", "11.0", "11.1", "11.3", "12.0", "12.1", "12.3", "13.0"]
+            sdk_version: [None, "10.13", "10.14", "10.15", "11.0", "11.1", "11.3", "12.0", "12.1", "12.3", "13.0", "13.1"]
             subsystem:
                 None:
                 catalyst:
@@ -94,7 +94,8 @@ _t_default_settings_yml = Template(textwrap.dedent("""
                       "9", "9.1", "9.2", "9.3", "9.4", "9.5",
                       "10", "10.1", "10.2", "10.3", "10.4",
                       "11", "11.1", "11.2", "11.3",
-                      "12", "12.1", "12.2"]
+                      "12", "12.1", "12.2", "12.3",
+                      "13", "13.1"]
             libcxx: [libstdc++, libstdc++11]
             threads: [None, posix, win32]  # Windows MinGW
             exception: [None, dwarf2, sjlj, seh]  # Windows MinGW
diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py
index a9015d928..243d6e309 100644
--- a/conans/client/graph/graph_builder.py
+++ b/conans/client/graph/graph_builder.py
@@ -404,6 +404,18 @@ class DepsGraphBuilder(object):
 
     def _resolve_recipe(self, current_node, dep_graph, requirement, check_updates,
                         update, remotes, profile, graph_lock, original_ref=None):
+
+        ref = requirement.ref
+        if ref.version == "<host_version>":
+            if not requirement.build_require:
+                raise ConanException(f"{current_node.ref} uses '<host_version>' in requires, "
+                                     "it is only allowed in tool_requires")
+            transitive = current_node._public_deps.get(ref.name, context="host")
+            if transitive is None:
+                raise ConanException(
+                    f"{current_node.ref} require '{ref}': didn't find a matching host dependency")
+            requirement.ref = transitive.ref
+
         try:
             result = self._proxy.get_recipe(requirement.ref, check_updates, update,
                                             remotes, self._recorder)
diff --git a/conans/client/migrations_settings.py b/conans/client/migrations_settings.py
index 9da8dc597..bdfbcb31a 100644
--- a/conans/client/migrations_settings.py
+++ b/conans/client/migrations_settings.py
@@ -4343,3 +4343,162 @@ cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23]
 """
 
 settings_1_59_0 = settings_1_58_0
+
+settings_1_60_0 = """
+# Only for cross building, 'os_build/arch_build' is the system that runs Conan
+os_build: [Windows, WindowsStore, Linux, Macos, FreeBSD, SunOS, AIX, VxWorks]
+arch_build: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, sh4le, e2k-v2, e2k-v3, e2k-v4, e2k-v5, e2k-v6, e2k-v7]
+
+# Only for building cross compilation tools, 'os_target/arch_target' is the system for
+# which the tools generate code
+os_target: [Windows, Linux, Macos, Android, iOS, watchOS, tvOS, FreeBSD, SunOS, AIX, Arduino, Neutrino]
+arch_target: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, asm.js, wasm, sh4le, e2k-v2, e2k-v3, e2k-v4, e2k-v5, e2k-v6, e2k-v7, xtensalx6, xtensalx106, xtensalx7]
+
+# Rest of the settings are "host" settings:
+# - For native building/cross building: Where the library/program will run.
+# - For building cross compilation tools: Where the cross compiler will run.
+os:
+    Windows:
+        subsystem: [None, cygwin, msys, msys2, wsl]
+    WindowsStore:
+        version: ["8.1", "10.0"]
+    WindowsCE:
+        platform: ANY
+        version: ["5.0", "6.0", "7.0", "8.0"]
+    Linux:
+    iOS:
+        version: &ios_version
+                 ["7.0", "7.1", "8.0", "8.1", "8.2", "8.3", "9.0", "9.1", "9.2", "9.3", "10.0", "10.1", "10.2", "10.3",
+                  "11.0", "11.1", "11.2", "11.3", "11.4", "12.0", "12.1", "12.2", "12.3", "12.4",
+                  "13.0", "13.1", "13.2", "13.3", "13.4", "13.5", "13.6", "13.7",
+                  "14.0", "14.1", "14.2", "14.3", "14.4", "14.5", "14.6", "14.7", "14.8",
+                  "15.0", "15.1", "15.2", "15.3", "15.4", "15.5", "15.6", "16.0", "16.1"]
+        sdk: [None, "iphoneos", "iphonesimulator"]
+        sdk_version: [None, "11.3", "11.4", "12.0", "12.1", "12.2", "12.4",
+                      "13.0", "13.1", "13.2", "13.4", "13.5", "13.6", "13.7",
+                      "14.0", "14.1", "14.2", "14.3", "14.4", "14.5", "15.0", "15.2", "15.4", "15.5", "16.0", "16.1"]
+    watchOS:
+        version: ["4.0", "4.1", "4.2", "4.3", "5.0", "5.1", "5.2", "5.3", "6.0", "6.1", "6.2",
+                  "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "8.0", "8.1", "8.3", "8.4", "8.5", "8.6", "8.7", "9.0", "9.1"]
+        sdk: [None, "watchos", "watchsimulator"]
+        sdk_version: [None, "4.3", "5.0", "5.1", "5.2", "5.3", "6.0", "6.1", "6.2",
+                      "7.0", "7.1", "7.2", "7.4", "8.0", "8.0.1", "8.3", "8.5", "9.0", "9.1"]
+    tvOS:
+        version: ["11.0", "11.1", "11.2", "11.3", "11.4", "12.0", "12.1", "12.2", "12.3", "12.4",
+                  "13.0", "13.2", "13.3", "13.4", "14.0", "14.2", "14.3", "14.4", "14.5", "14.6", "14.7",
+                  "15.0", "15.1", "15.2", "15.3", "15.4", "15.5", "15.6", "16.0", "16.1"]
+        sdk: [None, "appletvos", "appletvsimulator"]
+        sdk_version: [None, "11.3", "11.4", "12.0", "12.1", "12.2", "12.4",
+                      "13.0", "13.1", "13.2", "13.4", "14.0", "14.2", "14.3", "14.5", "15.0", "15.2", "15.4", "16.0", "16.1"]
+    Macos:
+        version: [None, "10.6", "10.7", "10.8", "10.9", "10.10", "10.11", "10.12", "10.13", "10.14", "10.15", "11.0", "12.0", "13.0"]
+        sdk: [None, "macosx"]
+        sdk_version: [None, "10.13", "10.14", "10.15", "11.0", "11.1", "11.3", "12.0", "12.1", "12.3", "13.0", "13.1"]
+        subsystem:
+            None:
+            catalyst:
+                ios_version: *ios_version
+    Android:
+        api_level: ANY
+    FreeBSD:
+    SunOS:
+    AIX:
+    Arduino:
+        board: ANY
+    Emscripten:
+    Neutrino:
+        version: ["6.4", "6.5", "6.6", "7.0", "7.1"]
+    baremetal:
+    VxWorks:
+        version: ["7"]
+arch: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv4, armv4i, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, asm.js, wasm, sh4le, e2k-v2, e2k-v3, e2k-v4, e2k-v5, e2k-v6, e2k-v7, xtensalx6, xtensalx106, xtensalx7]
+compiler:
+    sun-cc:
+        version: ["5.10", "5.11", "5.12", "5.13", "5.14", "5.15"]
+        threads: [None, posix]
+        libcxx: [libCstd, libstdcxx, libstlport, libstdc++]
+    gcc: &gcc
+        version: ["4.1", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9",
+                  "5", "5.1", "5.2", "5.3", "5.4", "5.5",
+                  "6", "6.1", "6.2", "6.3", "6.4", "6.5",
+                  "7", "7.1", "7.2", "7.3", "7.4", "7.5",
+                  "8", "8.1", "8.2", "8.3", "8.4", "8.5",
+                  "9", "9.1", "9.2", "9.3", "9.4", "9.5",
+                  "10", "10.1", "10.2", "10.3", "10.4",
+                  "11", "11.1", "11.2", "11.3",
+                  "12", "12.1", "12.2", "12.3",
+                  "13", "13.1"]
+        libcxx: [libstdc++, libstdc++11]
+        threads: [None, posix, win32]  # Windows MinGW
+        exception: [None, dwarf2, sjlj, seh]  # Windows MinGW
+        cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23]
+    Visual Studio: &visual_studio
+        runtime: [MD, MT, MTd, MDd]
+        version: ["8", "9", "10", "11", "12", "14", "15", "16", "17"]
+        toolset: [None, v90, v100, v110, v110_xp, v120, v120_xp,
+                  v140, v140_xp, v140_clang_c2, LLVM-vs2012, LLVM-vs2012_xp,
+                  LLVM-vs2013, LLVM-vs2013_xp, LLVM-vs2014, LLVM-vs2014_xp,
+                  LLVM-vs2017, LLVM-vs2017_xp, v141, v141_xp, v141_clang_c2, v142,
+                  llvm, ClangCL, v143]
+        cppstd: [None, 14, 17, 20, 23]
+    msvc:
+        version: [170, 180, 190, 191, 192, 193]
+        update: [None, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+        runtime: [static, dynamic]
+        runtime_type: [Debug, Release]
+        cppstd: [98, 14, 17, 20, 23]
+        toolset: [None, v110_xp, v120_xp, v140_xp, v141_xp]
+    clang:
+        version: ["3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0",
+                  "5.0", "6.0", "7.0", "7.1",
+                  "8", "9", "10", "11", "12", "13", "14", "15", "16"]
+        libcxx: [None, libstdc++, libstdc++11, libc++, c++_shared, c++_static]
+        cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23]
+        runtime: [None, MD, MT, MTd, MDd, static, dynamic]
+        runtime_type: [None, Debug, Release]
+        runtime_version: [None, v140, v141, v142, v143]
+    apple-clang: &apple_clang
+        version: ["5.0", "5.1", "6.0", "6.1", "7.0", "7.3", "8.0", "8.1", "9.0", "9.1", "10.0", "11.0", "12.0", "13", "13.0", "13.1", "14", "14.0"]
+        libcxx: [libstdc++, libc++]
+        cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23]
+    intel:
+        version: ["11", "12", "13", "14", "15", "16", "17", "18", "19", "19.1"]
+        update: [None, ANY]
+        base:
+            gcc:
+                <<: *gcc
+                threads: [None]
+                exception: [None]
+            Visual Studio:
+                <<: *visual_studio
+            apple-clang:
+                <<: *apple_clang
+    intel-cc:
+        version: ["2021.1", "2021.2", "2021.3"]
+        update: [None, ANY]
+        mode: ["icx", "classic", "dpcpp"]
+        libcxx: [None, libstdc++, libstdc++11, libc++]
+        cppstd: [None, 98, gnu98, 03, gnu03, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23]
+        runtime: [None, static, dynamic]
+        runtime_type: [None, Debug, Release]
+    qcc:
+        version: ["4.4", "5.4", "8.3"]
+        libcxx: [cxx, gpp, cpp, cpp-ne, accp, acpp-ne, ecpp, ecpp-ne]
+        cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17]
+    mcst-lcc:
+        version: ["1.19", "1.20", "1.21", "1.22", "1.23", "1.24", "1.25"]
+        base:
+            gcc:
+                <<: *gcc
+                threads: [None]
+                exceptions: [None]
+
+build_type: [None, Debug, Release, RelWithDebInfo, MinSizeRel]
+
+
+cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23]  # Deprecated, use compiler.cppstd
+"""
+
+settings_1_60_1 = settings_1_60_0
+
+settings_1_61_0 = settings_1_60_1
diff --git a/conans/client/profile_loader.py b/conans/client/profile_loader.py
index b484f68af..669df4f1e 100644
--- a/conans/client/profile_loader.py
+++ b/conans/client/profile_loader.py
@@ -4,6 +4,7 @@ from collections import OrderedDict, defaultdict
 
 from jinja2 import Environment, FileSystemLoader
 
+from conan import conan_version
 from conan.tools.env.environment import ProfileEnvironment
 from conans.errors import ConanException, ConanV2Exception
 from conans.model.conf import ConfDefinition
@@ -124,7 +125,8 @@ def read_profile(profile_name, cwd, default_folder):
         base_path = os.path.dirname(profile_path)
         context = {"platform": platform,
                    "os": os,
-                   "profile_dir": base_path}
+                   "profile_dir": base_path,
+                   "conan_version": conan_version}
         rtemplate = Environment(loader=FileSystemLoader(base_path)).from_string(text)
         text = rtemplate.render(context)
 
diff --git a/conans/client/rest/rest_client_common.py b/conans/client/rest/rest_client_common.py
index c0fdb1237..da472a509 100644
--- a/conans/client/rest/rest_client_common.py
+++ b/conans/client/rest/rest_client_common.py
@@ -6,7 +6,7 @@ from conans.client.rest import response_to_str
 from conans.errors import (EXCEPTION_CODE_MAPPING, ConanException,
                            AuthenticationException, RecipeNotFoundException,
                            PackageNotFoundException)
-from conans.model.ref import ConanFileReference
+from conans.model.ref import ConanFileReference, get_reference_fields
 from conans.util.files import decode_text
 from conans.util.log import logger
 
@@ -242,12 +242,19 @@ class RestCommonMethods(object):
         """
         url = self.router.search(pattern, ignorecase)
         response = self.get_json(url)["results"]
+        result = []
         try:
-            return [ConanFileReference.loads(reference) for reference in response]
-        except TypeError as te:
+            for reference in response:
+                name, version, user, channel, revision = get_reference_fields(reference)
+                # In Conan 2.0 it is possible to have user and not channel, skip it
+                if user and not channel:
+                    continue
+                result.append(ConanFileReference.loads(reference))
+        except TypeError:
             raise ConanException("Unexpected response from server.\n"
                                  "URL: `{}`\n"
                                  "Expected an iterable, but got {}.".format(url, type(response)))
+        return result
 
     def search_packages(self, ref):
         """Client is filtering by the query"""
diff --git a/conans/client/rest/rest_client_v1.py b/conans/client/rest/rest_client_v1.py
index 03ac6e1a1..b284a3e93 100644
--- a/conans/client/rest/rest_client_v1.py
+++ b/conans/client/rest/rest_client_v1.py
@@ -210,6 +210,8 @@ class RestV1Methods(RestCommonMethods):
     def get_recipe(self, ref, dest_folder):
         urls = self._get_recipe_urls(ref)
         urls.pop(EXPORT_SOURCES_TGZ_NAME, None)
+        accepted_files = ["conanfile.py", "conan_export.tgz", "conanmanifest.txt"]
+        urls = {f: url for f, url in urls.items() if any(f.startswith(m) for m in accepted_files)}
         check_compressed_files(EXPORT_TGZ_NAME, urls)
         md5s = self.get_recipe_snapshot(ref) if self._config.download_cache else None
         zipped_files = self._download_files_to_folder(urls, dest_folder, md5s)
@@ -234,6 +236,8 @@ class RestV1Methods(RestCommonMethods):
 
     def get_package(self, pref, dest_folder):
         urls = self._get_package_urls(pref)
+        accepted_files = ["conaninfo.txt", "conan_package.tgz", "conanmanifest.txt"]
+        urls = {f: url for f, url in urls.items() if any(f.startswith(m) for m in accepted_files)}
         check_compressed_files(PACKAGE_TGZ_NAME, urls)
         md5s = self.get_package_snapshot(pref) if self._config.download_cache else None
         zipped_files = self._download_files_to_folder(urls, dest_folder, md5s)
diff --git a/conans/client/rest/rest_client_v2.py b/conans/client/rest/rest_client_v2.py
index 7ee31663b..d17a4f4fe 100644
--- a/conans/client/rest/rest_client_v2.py
+++ b/conans/client/rest/rest_client_v2.py
@@ -89,8 +89,8 @@ class RestV2Methods(RestCommonMethods):
         data = self._get_file_list_json(url)
         files = data["files"]
         check_compressed_files(EXPORT_TGZ_NAME, files)
-        if EXPORT_SOURCES_TGZ_NAME in files:
-            files.remove(EXPORT_SOURCES_TGZ_NAME)
+        accepted_files = ["conanfile.py", "conan_export.tgz", "conanmanifest.txt"]
+        files = [f for f in files if any(f.startswith(m) for m in accepted_files)]
 
         # If we didn't indicated reference, server got the latest, use absolute now, it's safer
         urls = {fn: self.router.recipe_file(ref, fn) for fn in files}
@@ -122,6 +122,8 @@ class RestV2Methods(RestCommonMethods):
         url = self.router.package_snapshot(pref)
         data = self._get_file_list_json(url)
         files = data["files"]
+        accepted_files = ["conaninfo.txt", "conan_package.tgz", "conanmanifest.txt"]
+        files = [f for f in files if any(f.startswith(m) for m in accepted_files)]
         check_compressed_files(PACKAGE_TGZ_NAME, files)
         # If we didn't indicated reference, server got the latest, use absolute now, it's safer
         urls = {fn: self.router.package_file(pref, fn) for fn in files}
diff --git a/conans/model/graph_lock.py b/conans/model/graph_lock.py
index 639ff292b..969b4556b 100644
--- a/conans/model/graph_lock.py
+++ b/conans/model/graph_lock.py
@@ -538,11 +538,12 @@ class GraphLock(object):
         else:
             locked_requires = locked_node.requires or []
 
-        refs = {self._nodes[id_].ref.name: (self._nodes[id_].ref, id_) for id_ in locked_requires}
+        refs = {(self._nodes[id_].ref.name, self._nodes[id_].context): (self._nodes[id_].ref, id_) for id_ in locked_requires}
 
         for require in requires:
             try:
-                locked_ref, locked_id = refs[require.ref.name]
+                context = require.build_require_context if build_requires else node.context
+                locked_ref, locked_id = refs[(require.ref.name, context)]
             except KeyError:
                 t = "Build-require" if build_requires else "Require"
                 msg = "%s '%s' cannot be found in lockfile" % (t, require.ref.name)
diff --git a/conans/model/ref.py b/conans/model/ref.py
index 8c58ee349..9361a68ef 100644
--- a/conans/model/ref.py
+++ b/conans/model/ref.py
@@ -79,7 +79,7 @@ def check_valid_ref(reference, strict_mode=True):
                 return False
             if "*" in reference:
                 ref = ConanFileReference.loads(reference, validate=True)
-                if "*" in ref.name or "*" in ref.user or "*" in ref.channel:
+                if "*" in ref.name or "*" in (ref.user or "") or "*" in (ref.channel or ""):
                     return False
                 if str(ref.version).startswith("["):  # It is a version range
                     return True
@@ -153,7 +153,7 @@ class ConanName(object):
     @staticmethod
     def validate_version(version, pkg_name):
         ConanName.validate_string(version)
-        if version == "*":
+        if version == "*" or version == "<host_version>":
             return
         if ConanName._validation_pattern.match(version) is None:
             if (
diff --git a/conans/search/search.py b/conans/search/search.py
index 71508ef7e..ecf2d6a31 100644
--- a/conans/search/search.py
+++ b/conans/search/search.py
@@ -94,13 +94,19 @@ def _evaluate(prop_name, prop_value, conan_vars_info):
 
 def search_recipes(cache, pattern=None, ignorecase=True):
     # Conan references in main storage
+    no_user_channel = False
     if pattern:
         if isinstance(pattern, ConanFileReference):
             pattern = repr(pattern)
+        if pattern.endswith("@"):  # packages without user/channel:
+            no_user_channel = True
+            pattern = pattern[:-1]
         pattern = translate(pattern)
         pattern = re.compile(pattern, re.IGNORECASE) if ignorecase else re.compile(pattern)
 
     refs = cache.all_refs()
+    if no_user_channel:
+        refs = [r for r in refs if r.user is None and r.channel is None]
     refs.extend(cache.editable_packages.edited_refs.keys())
     if pattern:
         refs = [r for r in refs if _partial_match(pattern, repr(r))]


Test patch:
diff --git a/conans/test/functional/editable/consume_header_only_test.py b/conans/test/functional/editable/consume_header_only_test.py
index 032e3c5be..f3b0f6699 100644
--- a/conans/test/functional/editable/consume_header_only_test.py
+++ b/conans/test/functional/editable/consume_header_only_test.py
@@ -1,6 +1,7 @@
 # coding=utf-8
 
 import os
+import platform
 import textwrap
 import unittest
 
@@ -9,6 +10,7 @@ from parameterized import parameterized
 
 from conans.model.editable_layout import DEFAULT_LAYOUT_FILE, LAYOUTS_FOLDER
 from conans.test.utils.tools import TestClient
+from conans.tools import replace_in_file
 from conans.util.files import save
 from conans.test.utils.test_files import temp_folder
 
@@ -145,7 +147,10 @@ int main() {
                      "src/main.cpp": main_cpp})
 
         # Build consumer project
-        client.run("create . pkg/0.0@user/testing")
+        # FIXME: this is a hack to force VS2017 for tests
+        settings = "-s compiler.version=15" if platform.system() == "Windows" else ""
+        
+        client.run(f"create . pkg/0.0@user/testing {settings}")
         self.assertIn("    MyLib/0.1@user/editable from user folder - Editable", client.out)
         self.assertIn("    MyLib/0.1@user/editable:"
                       "5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Editable", client.out)
@@ -165,7 +170,7 @@ int main() {
 
         # Modify editable and build again
         client_editable.update_hello_word(hello_word="EDITED")
-        client.run("create . pkg/0.0@user/testing")
+        client.run(f"create . pkg/0.0@user/testing {settings}")
         self.assertIn("Hello EDITED!", client.out)
         if use_repo_file:  # Repo file will override folders from cache
             self.assertIn("...using inrepo", client.out)
diff --git a/conans/test/functional/editable/consume_settings_and_options_test.py b/conans/test/functional/editable/consume_settings_and_options_test.py
index 45be8f185..5181c5732 100644
--- a/conans/test/functional/editable/consume_settings_and_options_test.py
+++ b/conans/test/functional/editable/consume_settings_and_options_test.py
@@ -2,6 +2,7 @@
 
 import itertools
 import os
+import platform
 import unittest
 
 import pytest
@@ -140,9 +141,12 @@ int main() {
                      "src/CMakeLists.txt": cmakelists,
                      "src/main.cpp": main_cpp})
 
+        # FIXME: this is a hack to force VS2017 for tests
+        settings = "-s compiler.version=15" if platform.system() == "Windows" else ""
+
         # Build consumer project
         client.run("create . pkg/0.0@user/testing "
-                   "-s build_type={} -o MyLib:shared={}".format(build_type, str(shared)))
+                   "-s build_type={} -o MyLib:shared={} {}".format(build_type, str(shared), settings))
         self.assertIn("    MyLib/0.1@user/editable from user folder - Editable", client.out)
         self.assertIn("Hello {}!".format(build_type), client.out)
         self.assertIn(" - options.shared: {}".format(shared), client.out)
diff --git a/conans/test/functional/tools/scm/test_git.py b/conans/test/functional/tools/scm/test_git.py
index 0b3d822a3..50ed2c56f 100644
--- a/conans/test/functional/tools/scm/test_git.py
+++ b/conans/test/functional/tools/scm/test_git.py
@@ -6,6 +6,8 @@ import textwrap
 import pytest
 import six
 
+from conans.test.assets.cmake import gen_cmakelists
+from conans.test.assets.sources import gen_function_cpp
 from conans.test.utils.scm import create_local_git_repo, git_add_changes_commit, git_create_bare_repo
 from conans.test.utils.test_files import temp_folder
 from conans.test.utils.tools import TestClient
@@ -484,8 +486,7 @@ class TestGitMonorepoSCMFlow:
         import os, shutil
         from conan import ConanFile
         from conan.tools.scm import Git
-        from conan.tools.files import load, update_conandata
-        from conan.tools.files.files import swap_child_folder
+        from conan.tools.files import load, update_conandata, move_folder_contents
 
         class Pkg(ConanFile):
             name = "{pkg}"
@@ -509,7 +510,8 @@ class TestGitMonorepoSCMFlow:
                 sources = self.conan_data["sources"]
                 git.clone(url=sources["url"], target=".")
                 git.checkout(commit=sources["commit"])
-                swap_child_folder(self.source_folder, sources["folder"])
+                move_folder_contents(self, os.path.join(self.source_folder, sources["folder"]),
+                                    self.source_folder)
 
             def build(self):
                 cmake = os.path.join(self.source_folder, "CMakeLists.txt")
@@ -558,6 +560,80 @@ class TestGitMonorepoSCMFlow:
         assert "pkg2/0.1: MYCMAKE-BUILD: mycmake2!" in c2.out
         assert "pkg2/0.1: MYFILE-BUILD: my2header!" in c2.out
 
+    @pytest.mark.tool_cmake
+    def test_exports_sources_common_code_layout(self):
+        """ This is a copy of test_exports_sources_common_code_layout in test_in_subfolder.py
+        but instead of using "exports", trying to implement it with Git features
+        """
+        c = TestClient()
+        conanfile = textwrap.dedent("""
+            import os
+            from conan import ConanFile
+            from conan.tools.cmake import cmake_layout, CMake
+            from conan.tools.files import load, copy, save, update_conandata, move_folder_contents
+            from conan.tools.scm import Git
+
+            class Pkg(ConanFile):
+                name = "pkg"
+                version = "0.1"
+                settings = "os", "compiler", "build_type", "arch"
+                generators = "CMakeToolchain"
+
+                def export(self):
+                    git = Git(self)
+                    scm_url, scm_commit = git.get_url_and_commit()
+                    update_conandata(self, {"sources": {"commit": scm_commit, "url": scm_url}})
+
+                def layout(self):
+                    self.folders.root = ".."
+                    self.folders.subproject = "pkg"
+                    cmake_layout(self)
+
+                def source(self):
+                    git = Git(self)
+                    sources = self.conan_data["sources"]
+                    git.clone(url=sources["url"], target=".")
+                    git.checkout(commit=sources["commit"])
+                    # Layout is pkg/pkg/<files> and pkg/common/<files>
+                    # Final we want is pkg/<files> and common/<files>
+                    # NOTE: This abs_path is IMPORTANT to avoid the trailing "."
+                    src_folder = os.path.abspath(self.source_folder)
+                    move_folder_contents(self, src_folder, os.path.dirname(src_folder))
+
+                def build(self):
+                    cmake = CMake(self)
+                    cmake.configure()
+                    cmake.build()
+                    self.run(os.path.join(self.cpp.build.bindirs[0], "myapp"))
+                """)
+        cmake_include = "include(${CMAKE_CURRENT_LIST_DIR}/../common/myutils.cmake)"
+        c.save({"pkg/conanfile.py": conanfile,
+                "pkg/app.cpp": gen_function_cpp(name="main", includes=["../common/myheader"],
+                                                preprocessor=["MYDEFINE"]),
+                "pkg/CMakeLists.txt": gen_cmakelists(appsources=["app.cpp"],
+                                                     custom_content=cmake_include),
+                "common/myutils.cmake": 'message(STATUS "MYUTILS.CMAKE!")',
+                "common/myheader.h": '#define MYDEFINE "MYDEFINEVALUE"'})
+        c.init_git_repo()
+
+        c.run("create pkg")
+        assert "MYUTILS.CMAKE!" in c.out
+        assert "main: Release!" in c.out
+        assert "MYDEFINE: MYDEFINEVALUE" in c.out
+
+        # Local flow
+        c.run("install pkg")
+        c.run("build pkg")
+        assert "MYUTILS.CMAKE!" in c.out
+        assert "main: Release!" in c.out
+        assert "MYDEFINE: MYDEFINEVALUE" in c.out
+
+        c.run("install pkg -s build_type=Debug")
+        c.run("build pkg")
+        assert "MYUTILS.CMAKE!" in c.out
+        assert "main: Debug!" in c.out
+        assert "MYDEFINE: MYDEFINEVALUE" in c.out
+
 
 class TestConanFileSubfolder:
     """verify that we can have a conanfile in a subfolder
diff --git a/conans/test/integration/build_requires/build_requires_test.py b/conans/test/integration/build_requires/build_requires_test.py
index 48579d651..7df07c4f9 100644
--- a/conans/test/integration/build_requires/build_requires_test.py
+++ b/conans/test/integration/build_requires/build_requires_test.py
@@ -1,7 +1,9 @@
+import json
 import os
 import textwrap
 import unittest
 
+import pytest
 from parameterized.parameterized import parameterized
 
 from conans.model.ref import ConanFileReference
@@ -527,3 +529,102 @@ def test_tool_requires_conanfile_txt():
     client.save({"conanfile.txt": consumer}, clean_first=True)
     client.run("install . --build=missing")
     assert "Applying build-requirement: build_req/1.0@test/test" in client.out
+
+
+class TestBuildTrackHost:
+
+    @pytest.mark.parametrize("build_profile", [False, True])
+    def test_overriden_host_version(self, build_profile):
+        """
+        Make the tool_requires follow the regular require with the expression "<host_version>"
+        """
+        c = TestClient()
+        pkg = textwrap.dedent("""
+            from conan import ConanFile
+            class ProtoBuf(ConanFile):
+                name = "pkg"
+                version = "0.1"
+                def requirements(self):
+                    self.requires("protobuf/1.0")
+                def build_requirements(self):
+                    self.tool_requires("protobuf/<host_version>")
+            """)
+        c.save({"protobuf/conanfile.py": GenConanfile("protobuf"),
+                "pkg/conanfile.py": pkg,
+                "app/conanfile.py": GenConanfile().with_requires("pkg/0.1")
+                                                  .with_requirement("protobuf/1.1", override=True)})
+        c.run("create protobuf 1.0@")
+        c.run("create protobuf 1.1@")
+        build_profile = "-pr:b default" if build_profile else ""
+        c.run(f"create pkg {build_profile}")
+        c.run(f"install pkg {build_profile}")  # make sure it doesn't crash
+        c.run(f"install app {build_profile}")
+        assert "protobuf/1.1" in c.out
+        assert "protobuf/1.0:" not in c.out
+
+        # verify locks work
+        c.run(f"lock create app/conanfile.py {build_profile}")
+        lock = c.load("conan.lock")
+        assert "protobuf/1.1" in lock
+        assert "protobuf/1.0" not in lock
+        # lock can be used
+        c.run(f"install app --lockfile=conan.lock")
+        assert "protobuf/1.1" in c.out
+        assert "protobuf/1.0:" not in c.out
+
+    @pytest.mark.parametrize("build_profile", [False, True])
+    def test_overriden_host_version_version_range(self, build_profile):
+        """
+        same as above, but using version ranges instead of overrides
+        """
+        build_profile = "-pr:b default" if build_profile else ""
+        c = TestClient()
+        c.save({"protobuf/conanfile.py": GenConanfile("protobuf"),
+                "pkg/conanfile.py": GenConanfile("pkg", "0.1").with_requirement("protobuf/[*]")
+               .with_build_requirement("protobuf/<host_version>"),
+                "app/conanfile.py": GenConanfile().with_requires("pkg/0.1")})
+        c.run("create protobuf 1.0@")
+        c.run(f"create pkg {build_profile}")
+        c.run(f"install pkg {build_profile}")  # make sure it doesn't crash
+        c.run(f"install app {build_profile}")
+        assert "protobuf/1.0" in c.out
+        assert "protobuf/1.1" not in c.out
+
+        c.run("create protobuf 1.1@")
+        c.run(f"install pkg {build_profile}")  # make sure it doesn't crash
+        c.run(f"install app {build_profile}")
+        assert "protobuf/1.1" in c.out
+        assert "protobuf/1.0" not in c.out
+
+        # verify locks work
+        c.run(f"lock create app/conanfile.py {build_profile}")
+        lock = c.load("conan.lock")
+        assert "protobuf/1.1" in lock
+        assert "protobuf/1.0" not in lock
+        # lock can be used
+        c.run("install app --lockfile=conan.lock")
+        assert "protobuf/1.1" in c.out
+        assert "protobuf/1.0:" not in c.out
+
+    @pytest.mark.parametrize("build_profile", [False, True])
+    def test_track_host_error_nothost(self, build_profile):
+        """
+        if no host requirement is defined, it will be an error
+        """
+        build_profile = "-pr:b default" if build_profile else ""
+        c = TestClient()
+        c.save({"conanfile.py":
+                GenConanfile("pkg").with_build_requirement("protobuf/<host_version>")})
+        c.run(f"install . {build_profile}", assert_error=True)
+        assert "'protobuf/<host_version>': didn't find a matching host dependency" in c.out
+
+    @pytest.mark.parametrize("build_profile", [False, True])
+    def test_track_host_error_wrong_context(self, build_profile):
+        """
+        it can only be used by tool_requires, not regular requires
+        """
+        build_profile = "-pr:b default" if build_profile else ""
+        c = TestClient()
+        c.save({"conanfile.py": GenConanfile("pkg").with_requirement("protobuf/<host_version>")})
+        c.run(f"install . {build_profile}", assert_error=True)
+        assert "uses '<host_version>' in requires" in c.out
diff --git a/conans/test/integration/command/search_test.py b/conans/test/integration/command/search_test.py
index 71e276fe8..4382e2ec3 100644
--- a/conans/test/integration/command/search_test.py
+++ b/conans/test/integration/command/search_test.py
@@ -1646,3 +1646,23 @@ def test_error_revision_search():
     c.run("config set general.revisions_enabled=1")
     c.run("search mozilla/1.0.0@ -r=default", assert_error=True)
     assert "ERROR: Recipe not found: 'mozilla/1.0.0'. [Remote: default]" in c.out
+
+
+def test_no_user_channel_error():
+    # https://github.com/conan-io/conan/issues/13170
+    c = TestClient(default_server_user=True)
+    c.save({"conanfile.py": GenConanfile("pkg")})
+    c.run("export . 1.0@")
+    c.run("export . 1.0@user/channel")
+    c.run("search *")
+    assert "pkg/1.0" in str(c.out).splitlines()
+    assert "pkg/1.0@user/channel" in c.out
+    c.run("search pkg/*@")
+    assert "pkg/1.0" in c.out
+    assert "user/channel" not in c.out
+
+    # The same underlying logic is used in upload
+    c.run("upload pkg/*@ -r=default -c")
+    assert "Uploading pkg/1.0 to remote 'default'" in c.out
+    assert "user/channel" not in c.out
+
diff --git a/conans/test/integration/configuration/conf/test_conf.py b/conans/test/integration/configuration/conf/test_conf.py
index 9310a156b..539eb6150 100644
--- a/conans/test/integration/configuration/conf/test_conf.py
+++ b/conans/test/integration/configuration/conf/test_conf.py
@@ -3,9 +3,9 @@ import platform
 import textwrap
 
 import pytest
-import six
 from mock import patch
 
+from conan import conan_version
 from conans.errors import ConanException
 from conans.util.files import save
 from conans.test.utils.tools import TestClient
@@ -180,10 +180,12 @@ def test_composition_conan_conf_different_data_types_by_cli_arg(client):
 def test_jinja_global_conf(client):
     save(client.cache.new_config_path, "user.mycompany:parallel = {{os.cpu_count()/2}}\n"
                                        "user.mycompany:other = {{platform.system()}}\n"
-                                       "user.mycompany:dist = {{distro.id() if distro else '42'}}\n")
+                                       "user.mycompany:dist = {{distro.id() if distro else '42'}}\n"
+                                       "user.conan:version = {{conan_version}}-{{conan_version>0.1}}")
     client.run("install .")
     assert "user.mycompany:parallel={}".format(os.cpu_count()/2) in client.out
     assert "user.mycompany:other={}".format(platform.system()) in client.out
+    assert f"user.conan:version={conan_version}-True" in client.out
     if platform.system() == "Linux":
         import distro
         assert "user.mycompany:dist={}".format(distro.id()) in client.out
diff --git a/conans/test/integration/configuration/test_profile_jinja.py b/conans/test/integration/configuration/test_profile_jinja.py
index 30aa9ee84..da1a72209 100644
--- a/conans/test/integration/configuration/test_profile_jinja.py
+++ b/conans/test/integration/configuration/test_profile_jinja.py
@@ -1,6 +1,7 @@
 import platform
 import textwrap
 
+from conan import conan_version
 from conans.client.tools import environment_append
 from conans.test.assets.genconanfile import GenConanfile
 from conans.test.utils.tools import TestClient
@@ -71,3 +72,19 @@ def test_profile_template_profile_dir():
                  "anysubfolder/toolchain.cmake": "MyToolchainCMake!!!"})
     client.run("install . -pr=anysubfolder/profile1.jinja")
     assert "conanfile.py: CONTENT: MyToolchainCMake!!!" in client.out
+
+
+def test_profile_version():
+    client = TestClient()
+    tpl1 = textwrap.dedent("""
+        [options]
+        *:myoption={{conan_version}}
+        *:myoption2={{conan_version<13 and conan_version>1.0}}
+        """)
+
+    client.save({"conanfile.py": GenConanfile(),
+                 "profile1.jinja": tpl1})
+    client.run("install . -pr=profile1.jinja")
+    assert f"*:myoption={conan_version}" in client.out
+    assert "*:myoption2=True" in client.out
+
diff --git a/conans/test/integration/export_sources_test.py b/conans/test/integration/export_sources_test.py
index 84982a63b..5f1e43aa9 100644
--- a/conans/test/integration/export_sources_test.py
+++ b/conans/test/integration/export_sources_test.py
@@ -143,7 +143,7 @@ class ExportsSourcesTest(unittest.TestCase):
         self.assertEqual(scan_folder(export_src_folder or self.export_sources_folder),
                          sorted(expected_src_exports))
 
-    def _check_export_installed_folder(self, mode, updated=False):
+    def _check_export_installed_folder(self, mode):
         """ Just installed, no EXPORT_SOURCES_DIR is present
         """
         if mode == "exports_sources":
@@ -156,8 +156,6 @@ class ExportsSourcesTest(unittest.TestCase):
             expected_exports = ['conanfile.py', 'conanmanifest.txt', "src/data.txt"]
         if mode == "overlap":
             expected_exports = ['conanfile.py', 'conanmanifest.txt', "src/data.txt", "src/hello.h"]
-        if updated:
-            expected_exports.append("license.txt")
 
         self.assertEqual(scan_folder(self.export_folder), sorted(expected_exports))
         self.assertFalse(os.path.exists(self.export_sources_folder))
@@ -376,15 +374,3 @@ class ExportsSourcesTest(unittest.TestCase):
         self.client.run("install Hello/0.1@lasote/testing --update")
         self.assertIn("Hello/0.1@lasote/testing: Already installed!", self.client.out)
         self._check_export_installed_folder(mode)
-
-        rev = self.server.server_store.get_last_revision(self.ref)
-        ref = self.ref.copy_with_rev(rev.revision)
-        server_path = self.server.server_store.export(ref)
-        save(os.path.join(server_path, "license.txt"), "mylicense")
-        manifest = FileTreeManifest.load(server_path)
-        manifest.time += 1
-        manifest.file_sums["license.txt"] = md5sum(os.path.join(server_path, "license.txt"))
-        manifest.save(server_path)
-
-        self.client.run("install Hello/0.1@lasote/testing --update")
-        self._check_export_installed_folder(mode, updated=True)
diff --git a/conans/test/integration/graph_lock/graph_lock_build_requires_test.py b/conans/test/integration/graph_lock/graph_lock_build_requires_test.py
index 5d86bf8e8..7f786f64a 100644
--- a/conans/test/integration/graph_lock/graph_lock_build_requires_test.py
+++ b/conans/test/integration/graph_lock/graph_lock_build_requires_test.py
@@ -2,6 +2,8 @@ import json
 import textwrap
 import unittest
 
+import pytest
+
 from conans.client.tools.env import environment_append
 from conans.test.utils.tools import TestClient, GenConanfile
 
@@ -266,3 +268,54 @@ class GraphLockBuildRequireTestCase(unittest.TestCase):
 
         client.run("create pkg/conanfile.py pkg/1.0@  --build=missing --lockfile=conan.lock")
         assert "pkg/1.0 (test package): Applying build-requirement: cmake/1.0" in client.out
+
+
+@pytest.mark.parametrize("test_requires", [True, False])
+def test_duplicated_build_host_require(test_requires):
+    c = TestClient()
+    if test_requires:
+        pkg = GenConanfile("pkg", "0.1").with_build_requirement("tool/[^4.0]",
+                                                                force_host_context=True)
+    else:
+        pkg = GenConanfile("pkg", "0.1").with_requirement("tool/[^4.0]")
+    c.save({"tool/conanfile.py": GenConanfile("tool"),
+            "pkg/conanfile.py": pkg,
+            "profile": "[tool_requires]\ntool/[^3.0]"})
+    c.run("create tool 3.0@")
+    c.run("create tool 4.0@")
+    c.run("install pkg -pr:b=default -pr:h=profile --build")
+    assert "tool/4.0 from local cache - Cache" in c.out
+    c.run("install pkg --lockfile=conan.lock")
+    assert "tool/4.0 from local cache - Cache" in c.out
+
+
+class TestTransitiveBuildRequires:
+    @pytest.fixture()
+    def client(self):
+        # https://github.com/conan-io/conan/issues/13899
+        client = TestClient()
+        client.save({"zlib/conanfile.py": GenConanfile("zlib", "1.0"),
+                     "cmake/conanfile.py": GenConanfile("cmake", "1.0").with_requires("zlib/1.0"),
+                     "pkg/conanfile.py": GenConanfile("pkg", "1.0").with_build_requires("cmake/1.0"),
+                     "consumer/conanfile.py": GenConanfile().with_requires("pkg/[>=1.0]"),
+                     })
+
+        client.run("export zlib")
+        client.run("export cmake")
+        client.run("export pkg")
+        client.run("lock create consumer/conanfile.py -pr:b=default --build "
+                   "--lockfile-out=conan.lock")
+        return client
+
+    def test_transitive_build_require(self, client):
+        # This used to crash, not anymore with the fix
+        client.run("install consumer/conanfile.py --build=missing --lockfile=conan.lock")
+        assert "zlib/1.0: Created package" in client.out
+        assert "cmake/1.0: Created package" in client.out
+        assert "pkg/1.0: Created package" in client.out
+
+    def test_transitive_build_require_intermediate(self, client):
+        # This used to crash, not anymore with the fix
+        client.run("install pkg/conanfile.py --build=missing --lockfile=conan.lock")
+        assert "zlib/1.0: Created package" in client.out
+        assert "cmake/1.0: Created package" in client.out
diff --git a/conans/test/integration/remote/rest_api_test.py b/conans/test/integration/remote/rest_api_test.py
index a37c6052a..122b1e358 100644
--- a/conans/test/integration/remote/rest_api_test.py
+++ b/conans/test/integration/remote/rest_api_test.py
@@ -135,7 +135,7 @@ class RestApiTest(unittest.TestCase):
         # Get the package
         tmp_dir = temp_folder()
         self.api.get_package(pref, tmp_dir)
-        self.assertIn("hello.cpp", os.listdir(tmp_dir))
+        self.assertNotIn("hello.cpp", os.listdir(tmp_dir))
 
     def test_get_package_info(self):
         # Upload a conans
@@ -174,7 +174,7 @@ class RestApiTest(unittest.TestCase):
             tmp = temp_folder()
             files = self.api.get_recipe(ref, tmp)
             self.assertIsNotNone(files)
-            self.assertTrue(os.path.exists(os.path.join(tmp, "file999.cpp")))
+            self.assertFalse(os.path.exists(os.path.join(tmp, "file999.cpp")))
 
     def test_search(self):
         # Upload a conan1
diff --git a/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py b/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py
index 4bc28f2fe..e8959920d 100644
--- a/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py
+++ b/conans/test/integration/toolchains/gnu/test_autotoolstoolchain.py
@@ -4,6 +4,7 @@ import textwrap
 
 from conans.test.assets.genconanfile import GenConanfile
 from conans.test.utils.tools import TestClient
+from conans.util.files import save, load
 
 
 def test_extra_flags_via_conf():
@@ -75,6 +76,7 @@ def test_linker_scripts_via_conf():
     else:
         assert 'export LDFLAGS="$LDFLAGS --flag5 --flag6 -T\'/linker/scripts/flash.ld\' -T\'/linker/scripts/extra_data.ld\'"' in toolchain
 
+
 def test_not_none_values():
 
     conanfile = textwrap.dedent("""
@@ -123,3 +125,15 @@ def test_set_prefix():
     conanbuild = client.load(os.path.join(client.current_folder, "build", "conan", "conanbuild.conf"))
     assert "--prefix=/somefolder" in conanbuild
     assert conanbuild.count("--prefix") == 1
+
+
+def test_unknown_compiler():
+    client = TestClient()
+    settings = load(client.cache.settings_path)
+    settings = settings.replace("gcc:", "xlc:\n    gcc:", 1)
+    save(client.cache.settings_path, settings)
+    client.save({"conanfile.py": GenConanfile().with_settings("compiler", "build_type")
+                                               .with_generator("AutotoolsToolchain")})
+    # this used to crash, because of build_type_flags in AutotoolsToolchain returning empty string
+    client.run("install . -s compiler=xlc")
+    assert "conanfile.py: Generator 'AutotoolsToolchain' calling 'generate()'" in client.out
diff --git a/conans/test/unittests/client/build/cmake_test.py b/conans/test/unittests/client/build/cmake_test.py
index 0ce900a29..f6e6e4df4 100644
--- a/conans/test/unittests/client/build/cmake_test.py
+++ b/conans/test/unittests/client/build/cmake_test.py
@@ -1384,46 +1384,47 @@ build_type: [ Release]
                            ("iOS", "7.0",),
                            ("watchOS", "4.0",),
                            ("tvOS", "11.0",)])
-    @mock.patch("platform.system", return_value="Darwin")
-    @mock.patch("conans.client.tools.apple.XCRun.sdk_path", return_value='/opt')
-    def test_cmake_system_version_osx(self, the_os, os_version, _, __):
-        settings = Settings.loads(get_default_settings_yml())
-        settings.os = the_os
-
-        # No version defined
-        conanfile = ConanFileMock()
-        conanfile.settings = settings
-        cmake = CMake(conanfile)
-        self.assertFalse("CMAKE_OSX_DEPLOYMENT_TARGET" in cmake.definitions)
-        if the_os == "Macos":
-            self.assertFalse("CMAKE_SYSTEM_NAME" in cmake.definitions)
-        else:
-            self.assertTrue("CMAKE_SYSTEM_NAME" in cmake.definitions)
-        self.assertFalse("CMAKE_SYSTEM_VERSION" in cmake.definitions)
-
-        # Version defined using Conan env variable
-        with tools.environment_append({"CONAN_CMAKE_SYSTEM_VERSION": "23"}):
-            conanfile = ConanFileMock()
-            conanfile.settings = settings
-            cmake = CMake(conanfile)
-            self.assertEqual(cmake.definitions["CMAKE_SYSTEM_VERSION"], "23")
-            self.assertEqual(cmake.definitions["CMAKE_OSX_DEPLOYMENT_TARGET"], "23")
+    def test_cmake_system_version_osx(self, the_os, os_version):
+        with mock.patch("platform.system", return_value="Darwin"):
+            with mock.patch("conans.client.tools.apple.XCRun.sdk_path", return_value='/opt'):
 
-        # Version defined in settings
-        settings.os.version = os_version
-        conanfile = ConanFileMock()
-        conanfile.settings = settings
-        cmake = CMake(conanfile)
-        self.assertEqual(cmake.definitions["CMAKE_SYSTEM_VERSION"], os_version)
-        self.assertEqual(cmake.definitions["CMAKE_OSX_DEPLOYMENT_TARGET"], os_version)
+                settings = Settings.loads(get_default_settings_yml())
+                settings.os = the_os
 
-        # Version defined in settings AND using Conan env variable
-        with tools.environment_append({"CONAN_CMAKE_SYSTEM_VERSION": "23"}):
-            conanfile = ConanFileMock()
-            conanfile.settings = settings
-            cmake = CMake(conanfile)
-            self.assertEqual(cmake.definitions["CMAKE_SYSTEM_VERSION"], "23")
-            self.assertEqual(cmake.definitions["CMAKE_OSX_DEPLOYMENT_TARGET"], "23")
+                # No version defined
+                conanfile = ConanFileMock()
+                conanfile.settings = settings
+                cmake = CMake(conanfile)
+                self.assertFalse("CMAKE_OSX_DEPLOYMENT_TARGET" in cmake.definitions)
+                if the_os == "Macos":
+                    self.assertFalse("CMAKE_SYSTEM_NAME" in cmake.definitions)
+                else:
+                    self.assertTrue("CMAKE_SYSTEM_NAME" in cmake.definitions)
+                self.assertFalse("CMAKE_SYSTEM_VERSION" in cmake.definitions)
+
+                # Version defined using Conan env variable
+                with tools.environment_append({"CONAN_CMAKE_SYSTEM_VERSION": "23"}):
+                    conanfile = ConanFileMock()
+                    conanfile.settings = settings
+                    cmake = CMake(conanfile)
+                    self.assertEqual(cmake.definitions["CMAKE_SYSTEM_VERSION"], "23")
+                    self.assertEqual(cmake.definitions["CMAKE_OSX_DEPLOYMENT_TARGET"], "23")
+
+                # Version defined in settings
+                settings.os.version = os_version
+                conanfile = ConanFileMock()
+                conanfile.settings = settings
+                cmake = CMake(conanfile)
+                self.assertEqual(cmake.definitions["CMAKE_SYSTEM_VERSION"], os_version)
+                self.assertEqual(cmake.definitions["CMAKE_OSX_DEPLOYMENT_TARGET"], os_version)
+
+                # Version defined in settings AND using Conan env variable
+                with tools.environment_append({"CONAN_CMAKE_SYSTEM_VERSION": "23"}):
+                    conanfile = ConanFileMock()
+                    conanfile.settings = settings
+                    cmake = CMake(conanfile)
+                    self.assertEqual(cmake.definitions["CMAKE_SYSTEM_VERSION"], "23")
+                    self.assertEqual(cmake.definitions["CMAKE_OSX_DEPLOYMENT_TARGET"], "23")
 
     @staticmethod
     def scape(args):
diff --git a/conans/test/unittests/util/xz_test.py b/conans/test/unittests/util/xz_test.py
index c31b0bcff..683c05a0d 100644
--- a/conans/test/unittests/util/xz_test.py
+++ b/conans/test/unittests/util/xz_test.py
@@ -21,66 +21,6 @@ from conans.util.files import load, save_files
 class XZTest(TestCase):
     output = TestBufferConanOutput()
 
-    def test_error_xz(self):
-        server = TestServer()
-        ref = ConanFileReference.loads("Pkg/0.1@user/channel")
-        ref = ref.copy_with_rev(DEFAULT_REVISION_V1)
-        export = server.server_store.export(ref)
-        server.server_store.update_last_revision(ref)
-        save_files(export, {"conanfile.py": "#",
-                            "conanmanifest.txt": "#",
-                            "conan_export.txz": "#"})
-        client = TestClient(servers={"default": server},
-                            users={"default": [("lasote", "mypass")]})
-        client.run("install Pkg/0.1@user/channel", assert_error=True)
-        self.assertIn("ERROR: This Conan version is not prepared to handle "
-                      "'conan_export.txz' file format", client.out)
-
-    def test_error_sources_xz(self):
-        server = TestServer()
-        ref = ConanFileReference.loads("Pkg/0.1@user/channel")
-        ref = ref.copy_with_rev(DEFAULT_REVISION_V1)
-        client = TestClient(servers={"default": server},
-                            users={"default": [("lasote", "mypass")]})
-        server.server_store.update_last_revision(ref)
-        export = server.server_store.export(ref)
-        conanfile = """from conans import ConanFile
-class Pkg(ConanFile):
-    exports_sources = "*"
-"""
-        save_files(export, {"conanfile.py": conanfile,
-                            "conanmanifest.txt": "1",
-                            "conan_sources.txz": "#"})
-        client.run("install Pkg/0.1@user/channel --build", assert_error=True)
-        self.assertIn("ERROR: This Conan version is not prepared to handle "
-                      "'conan_sources.txz' file format", client.out)
-
-    def test_error_package_xz(self):
-        server = TestServer()
-        ref = ConanFileReference.loads("Pkg/0.1@user/channel")
-        ref = ref.copy_with_rev(DEFAULT_REVISION_V1)
-        client = TestClient(servers={"default": server},
-                            users={"default": [("lasote", "mypass")]})
-        server.server_store.update_last_revision(ref)
-        export = server.server_store.export(ref)  # *1 the path can't be known before upload a revision
-        conanfile = """from conans import ConanFile
-class Pkg(ConanFile):
-    exports_sources = "*"
-"""
-        save_files(export, {"conanfile.py": conanfile,
-                            "conanmanifest.txt": "1"})
-        pref = PackageReference(ref, NO_SETTINGS_PACKAGE_ID, DEFAULT_REVISION_V1)
-        server.server_store.update_last_package_revision(pref.copy_with_revs(DEFAULT_REVISION_V1,
-                                                                             DEFAULT_REVISION_V1))
-
-        package = server.server_store.package(pref)
-        save_files(package, {"conaninfo.txt": "#",
-                             "conanmanifest.txt": "1",
-                             "conan_package.txz": "#"})
-        client.run("install Pkg/0.1@user/channel", assert_error=True)
-        self.assertIn("ERROR: This Conan version is not prepared to handle "
-                      "'conan_package.txz' file format", client.out)
-
     @pytest.mark.skipif(not six.PY3, reason="only Py3")
     def test(self):
         tmp_dir = temp_folder()
diff --git a/conans/test/utils/tools.py b/conans/test/utils/tools.py
index b9553bf24..38e407c15 100644
--- a/conans/test/utils/tools.py
+++ b/conans/test/utils/tools.py
@@ -1,5 +1,6 @@
 import json
 import os
+import platform
 import shlex
 import shutil
 import socket
@@ -333,6 +334,11 @@ def _copy_cache_folder(target_folder):
         cache.initialize_config()
         cache.registry.initialize_remotes()
         cache.initialize_default_profile()
+        # FIXME: this is a hack to force VS2017 for tests
+        if platform.system() == "Windows":
+            replace_in_file(os.path.join(master_folder, "profiles", "default"),
+                            "compiler.version=17", "compiler.version=15")
+
         cache.initialize_settings()
     shutil.copytree(master_folder, target_folder)