Repository: conan-io/conan

Issue:
[bug] missing CMakeUserPresets.json
Conan 1.48.0 does not generate `CMakeUserPresets.json` if `conanfile.txt` used instead of `.py`.

Probably this is duplicate of #11172.

### Environment Details
  * Operating System: linux
  * Conan version: 1.48.0

### Steps to reproduce
```
cd "$(mktemp -d)"
conan new hello/0.1 -m=cmake_exe
rm conanfile.py
echo -e "[generators]\nCMakeToolchain" > conanfile.txt
mkdir build
(cd build && conan install ..)
tree "$(pwd)"
```

### Output
```
/tmp/tmp.6FdEpSMGTR
├── CMakeLists.txt
├── build
│   ├── CMakePresets.json
│   ├── conan.lock
│   ├── conan_toolchain.cmake
│   ├── conanbuildinfo.txt
│   ├── conaninfo.txt
│   └── graph_info.json
├── conanfile.txt
├── include
│   └── hello.h
├── src
│   ├── hello.cpp
│   └── main.cpp
└── test_package
    └── conanfile.py
```

Discussion:

Patch:
diff --git a/conan/tools/cmake/cmake.py b/conan/tools/cmake/cmake.py
index 3eea4a32c..b3d6535a5 100644
--- a/conan/tools/cmake/cmake.py
+++ b/conan/tools/cmake/cmake.py
@@ -122,7 +122,7 @@ class CMake(object):
         if cmd_line_args:
             args += ['--'] + cmd_line_args
 
-        arg_list = [args_to_string([bf]), build_config, args_to_string(args)]
+        arg_list = ['"{}"'.format(bf), build_config, args_to_string(args)]
         arg_list = " ".join(filter(None, arg_list))
         command = "%s --build %s" % (self._cmake_program, arg_list)
         self._conanfile.output.info("CMake command: %s" % command)
@@ -140,8 +140,8 @@ class CMake(object):
         is_multi = is_multi_configuration(self._generator)
         build_config = "--config {}".format(bt) if bt and is_multi else ""
 
-        pkg_folder = args_to_string([self._conanfile.package_folder.replace("\\", "/")])
-        build_folder = args_to_string([self._conanfile.build_folder])
+        pkg_folder = '"{}"'.format(self._conanfile.package_folder.replace("\\", "/"))
+        build_folder = '"{}"'.format(self._conanfile.build_folder)
         arg_list = ["--install", build_folder, build_config, "--prefix", pkg_folder]
         arg_list = " ".join(filter(None, arg_list))
         command = "%s %s" % (self._cmake_program, arg_list)
diff --git a/conan/tools/env/environment.py b/conan/tools/env/environment.py
index 88c008e92..b24792e5f 100644
--- a/conan/tools/env/environment.py
+++ b/conan/tools/env/environment.py
@@ -13,34 +13,36 @@ class _EnvVarPlaceHolder:
     pass
 
 
-def environment_wrap_command(env_filenames, cmd, subsystem=None, cwd=None):
-    assert env_filenames
+def environment_wrap_command(env_filenames, env_folder, cmd, subsystem=None,
+                             accepted_extensions=None):
+    if not env_filenames:
+        return cmd
     filenames = [env_filenames] if not isinstance(env_filenames, list) else env_filenames
     bats, shs, ps1s = [], [], []
 
-    cwd = cwd or os.getcwd()
-
+    accept = accepted_extensions or ("ps1", "bat", "sh")
+    # TODO: This implemantation is dirty, improve it
     for f in filenames:
-        f = f if os.path.isabs(f) else os.path.join(cwd, f)
+        f = f if os.path.isabs(f) else os.path.join(env_folder, f)
         if f.lower().endswith(".sh"):
-            if os.path.isfile(f):
+            if os.path.isfile(f) and "sh" in accept:
                 f = subsystem_path(subsystem, f)
                 shs.append(f)
         elif f.lower().endswith(".bat"):
-            if os.path.isfile(f):
+            if os.path.isfile(f) and "bat" in accept:
                 bats.append(f)
-        elif f.lower().endswith(".ps1"):
+        elif f.lower().endswith(".ps1") and "ps1" in accept:
             if os.path.isfile(f):
                 ps1s.append(f)
         else:  # Simple name like "conanrunenv"
             path_bat = "{}.bat".format(f)
             path_sh = "{}.sh".format(f)
             path_ps1 = "{}.ps1".format(f)
-            if os.path.isfile(path_bat):
+            if os.path.isfile(path_bat) and "bat" in accept:
                 bats.append(path_bat)
-            elif os.path.isfile(path_ps1):
+            if os.path.isfile(path_ps1) and "ps1" in accept:
                 ps1s.append(path_ps1)
-            elif os.path.isfile(path_sh):
+            if os.path.isfile(path_sh) and "sh" in accept:
                 path_sh = subsystem_path(subsystem, path_sh)
                 shs.append(path_sh)
 
diff --git a/conans/client/command.py b/conans/client/command.py
index 342cc6c48..9c1469ac8 100644
--- a/conans/client/command.py
+++ b/conans/client/command.py
@@ -7,8 +7,6 @@ import sys
 from argparse import ArgumentError
 from difflib import get_close_matches
 
-from six.moves import input as user_input
-
 from conans import __version__ as client_version
 from conans.client.cmd.frogarian import cmd_frogarian
 from conans.client.cmd.uploader import UPLOAD_POLICY_FORCE, \
@@ -2167,31 +2165,11 @@ class Command(object):
         version = sys.version_info
         if version.major == 2:
             self._out.writeln("*"*width, front=Color.BRIGHT_RED)
-            msg = textwrap.fill("Python 2 is deprecated as of 01/01/2020 and Conan has"
-                                " stopped supporting it officially. We strongly recommend"
-                                " you to use Python >= 3.5. Conan will completely stop"
-                                " working with Python 2 in the following releases", width)
+            msg = textwrap.fill("Python 2 support has been removed 30/05/2022 (1.49) because of "
+                                "security vulnerabilities. Please use Python >=3.6.", width)
             self._out.writeln(msg, front=Color.BRIGHT_RED)
             self._out.writeln("*"*width, front=Color.BRIGHT_RED)
-            if os.environ.get('USE_UNSUPPORTED_CONAN_WITH_PYTHON_2', 0):
-                # IMPORTANT: This environment variable is not a silver buller. Python 2 is currently
-                # deprecated and some libraries we use as dependencies have stopped supporting it.
-                # Conan might fail to run and we are no longer fixing errors related to Python 2.
-                self._out.writeln(textwrap.fill("Python 2 deprecation notice has been bypassed"
-                                                " by envvar 'USE_UNSUPPORTED_CONAN_WITH_PYTHON_2'",
-                                                width))
-            else:
-                msg = textwrap.fill("If you really need to run Conan with Python 2 in your"
-                                    " CI without this interactive input, please contact us"
-                                    " at info@conan.io", width)
-                self._out.writeln(msg, front=Color.BRIGHT_RED)
-                self._out.writeln("*" * width, front=Color.BRIGHT_RED)
-                self._out.write(textwrap.fill("Understood the risk, keep going [y/N]: ", width,
-                                              drop_whitespace=False), front=Color.BRIGHT_RED)
-                ret = user_input().lower()
-                if ret not in ["yes", "ye", "y"]:
-                    self._out.writeln(textwrap.fill("Wise choice. Stopping here!", width))
-                    sys.exit(0)
+            sys.exit(0)
         elif version.minor == 4:
             self._out.writeln("*"*width, front=Color.BRIGHT_RED)
             self._out.writeln(textwrap.fill("Python 3.4 support has been dropped. It is strongly "
diff --git a/conans/client/loader.py b/conans/client/loader.py
index db3679776..4fafe8197 100644
--- a/conans/client/loader.py
+++ b/conans/client/loader.py
@@ -3,10 +3,14 @@ import imp
 import inspect
 import os
 import sys
+import types
 import uuid
 
 import yaml
 
+from conan.tools.cmake import cmake_layout
+from conan.tools.google import bazel_layout
+from conan.tools.microsoft import vs_layout
 from conans.client.conf.required_version import validate_conan_version
 from conans.client.loader_txt import ConanFileTextLoader
 from conans.client.tools.files import chdir
@@ -304,9 +308,20 @@ class ConanFileLoader(object):
             if not hasattr(conanfile, "build_requires"):
                 conanfile.build_requires = []
             conanfile.build_requires.append(build_reference)
+        if parser.layout:
+            layout_method = {"cmake_layout": cmake_layout,
+                             "vs_layout": vs_layout,
+                             "bazel_layout": bazel_layout}.get(parser.layout)
+            if not layout_method:
+                raise ConanException("Unknown predefined layout '{}' declared in "
+                                     "conanfile.txt".format(parser.layout))
 
-        conanfile.generators = parser.generators
+            def layout(self):
+                layout_method(self)
+
+            conanfile.layout = types.MethodType(layout, conanfile)
 
+        conanfile.generators = parser.generators
         try:
             options = OptionsValues.loads(parser.options)
         except Exception:
diff --git a/conans/client/loader_txt.py b/conans/client/loader_txt.py
index 35ff52496..976e19dce 100644
--- a/conans/client/loader_txt.py
+++ b/conans/client/loader_txt.py
@@ -8,9 +8,19 @@ class ConanFileTextLoader(object):
     def __init__(self, input_text):
         # Prefer composition over inheritance, the __getattr__ was breaking things
         self._config_parser = ConfigParser(input_text,  ["requires", "generators", "options",
-                                                         "imports", "build_requires", "tool_requires"],
+                                                         "imports", "build_requires",
+                                                         "tool_requires", "layout"],
                                            parse_lines=True)
 
+    @property
+    def layout(self):
+        """returns the declared layout"""
+        tmp = [r.strip() for r in self._config_parser.layout.splitlines()]
+        if len(tmp) > 1:
+            raise ConanException("Only one layout can be declared in the [layout] section of "
+                                 "the conanfile.txt")
+        return tmp[0] if tmp else None
+
     @property
     def requirements(self):
         """returns a list of requires
diff --git a/conans/client/subsystems.py b/conans/client/subsystems.py
index 1ad488677..30cf824b1 100644
--- a/conans/client/subsystems.py
+++ b/conans/client/subsystems.py
@@ -1,3 +1,24 @@
+"""
+Potential scenarios:
+
+- Running from a Windows native "cmd"
+  - Targeting Windows native (os.subsystem = None)
+    - No need of bash (no conf at all)
+    - Need to build in bash (tools.microsoft.bash:subsystem=xxx,
+                             tools.microsoft.bash:path=<path>,
+                             conanfile.win_bash)
+    - Need to run (tests) in bash (tools.microsoft.bash:subsystem=xxx,
+                                   tools.microsoft.bash:path=<path>,
+                                   conanfile.win_bash_run)
+  - Targeting Subsystem (os.subsystem = msys2/cygwin)
+    - Always builds and runs in bash (tools.microsoft.bash:path)
+
+- Running from a subsytem terminal (tools.microsoft.bash:subsystem=xxx,
+                                    tools.microsoft.bash:path=None) NO ERROR mode for not specifying it? =CURRENT?
+  - Targeting Windows native (os.subsystem = None)
+  - Targeting Subsystem (os.subsystem = msys2/cygwin)
+
+"""
 import os
 import platform
 import re
@@ -13,30 +34,27 @@ WSL = 'wsl'  # Windows Subsystem for Linux
 SFU = 'sfu'  # Windows Services for UNIX
 
 
-def run_in_windows_bash(conanfile, command, cwd=None, env="conanbuild"):
+def command_env_wrapper(conanfile, command, envfiles, envfiles_folder):
+    from conan.tools.env.environment import environment_wrap_command
+    if platform.system() == "Windows" and conanfile.win_bash:  # New, Conan 2.0
+        wrapped_cmd = _windows_bash_wrapper(conanfile, command, envfiles, envfiles_folder)
+    else:
+        wrapped_cmd = environment_wrap_command(envfiles, envfiles_folder, command)
+    return wrapped_cmd
+
+
+def _windows_bash_wrapper(conanfile, command, env, envfiles_folder):
     from conan.tools.env import Environment
     from conan.tools.env.environment import environment_wrap_command
-    """ Will run a unix command inside a bash terminal It requires to have MSYS2, CYGWIN, or WSL"""
-    env_win = []
-    env_shell = []
-    if env:
-        if env == "conanbuild":
-            env_shell = ["conanbuild.sh"]
-            env_win = ["conanbuild.bat"]
-        else:
-            # Passing env invalidates the conanfile.environment_scripts
-            env_win = [env] if not isinstance(env, list) else env
-            env_shell = []
+    """ Will wrap a unix command inside a bash terminal It requires to have MSYS2, CYGWIN, or WSL"""
 
     subsystem = conanfile.conf.get("tools.microsoft.bash:subsystem")
     shell_path = conanfile.conf.get("tools.microsoft.bash:path")
-
-    if not platform.system() == "Windows":
-        raise ConanException("Command only for Windows operating system")
-
     if not subsystem or not shell_path:
-        raise ConanException("The config 'tools.microsoft.bash:subsystem' and 'tools.microsoft.bash:path' are "
+        raise ConanException("The config 'tools.microsoft.bash:subsystem' and "
+                             "'tools.microsoft.bash:path' are "
                              "needed to run commands in a Windows subsystem")
+    env = env or []
     if subsystem == MSYS2:
         # Configure MSYS2 to inherith the PATH
         msys2_mode_env = Environment()
@@ -45,39 +63,23 @@ def run_in_windows_bash(conanfile, command, cwd=None, env="conanbuild"):
         msys2_mode_env.define("MSYS2_PATH_TYPE", "inherit")
         path = os.path.join(conanfile.generators_folder, "msys2_mode.bat")
         msys2_mode_env.vars(conanfile, "build").save_bat(path)
-        env_win.append(path)
+        env.append(path)
 
-    # Needed to change to that dir inside the bash shell
     wrapped_shell = '"%s"' % shell_path if " " in shell_path else shell_path
-    if env_win:
-        wrapped_shell = environment_wrap_command(env_win, shell_path,
-                                                 cwd=conanfile.generators_folder)
-
-    cwd = cwd or os.getcwd()
-    if not os.path.isabs(cwd):
-        cwd = os.path.join(os.getcwd(), cwd)
-    cwd_inside = subsystem_path(subsystem, cwd)
-    wrapped_user_cmd = command
-    if env_shell:
-        # Wrapping the inside_command enable to prioritize our environment, otherwise /usr/bin go
-        # first and there could be commands that we want to skip
-        wrapped_user_cmd = environment_wrap_command(env_shell, command,
-                                                    cwd=conanfile.generators_folder)
-    inside_command = 'cd "{cwd_inside}" && ' \
-                     '{wrapped_user_cmd}'.format(cwd_inside=cwd_inside,
-                                                 wrapped_user_cmd=wrapped_user_cmd)
-
-    inside_command = escape_windows_cmd(inside_command)
-
-    final_command = 'cd "{cwd}" && {wrapped_shell} --login -c {inside_command}'.format(
-        cwd=cwd,
-        wrapped_shell=wrapped_shell,
-        inside_command=inside_command)
-    conanfile.output.info('Running in windows bash: %s' % final_command)
-    return conanfile._conan_runner(final_command, output=conanfile.output, subprocess=True)
-
-
-def escape_windows_cmd(command):
+    wrapped_shell = environment_wrap_command(env, envfiles_folder, wrapped_shell,
+                                             accepted_extensions=("bat", "ps1"))
+
+    # Wrapping the inside_command enable to prioritize our environment, otherwise /usr/bin go
+    # first and there could be commands that we want to skip
+    wrapped_user_cmd = environment_wrap_command(env, envfiles_folder, command,
+                                                accepted_extensions=("sh", ))
+    wrapped_user_cmd = _escape_windows_cmd(wrapped_user_cmd)
+
+    final_command = '{} -c {}'.format(wrapped_shell, wrapped_user_cmd)
+    return final_command
+
+
+def _escape_windows_cmd(command):
     """ To use in a regular windows cmd.exe
         1. Adds escapes so the argument can be unpacked by CommandLineToArgvW()
         2. Adds escapes for cmd.exe so the argument survives cmd.exe's substitutions.
@@ -89,6 +91,14 @@ def escape_windows_cmd(command):
 
 
 def deduce_subsystem(conanfile, scope):
+    """ used by:
+    - EnvVars: to decide if using :  ; as path separator, translate paths to subsystem
+               and decide to generate a .bat or .sh
+    - Autotools: to define the full abs path to the "configure" script
+    - GnuDeps: to map all the paths from dependencies
+    - Aggregation of envfiles: to map each aggregated path to the subsystem
+    - unix_path: util for recipes
+    """
     if scope.startswith("build"):
         if hasattr(conanfile, "settings_build"):
             the_os = conanfile.settings_build.get_safe("os")
diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py
index ab60a3c14..dbdcfe7eb 100644
--- a/conans/model/conan_file.py
+++ b/conans/model/conan_file.py
@@ -8,6 +8,7 @@ from six import string_types
 
 from conans.client import tools
 from conans.client.output import ScopedOutput
+from conans.client.subsystems import command_env_wrapper
 from conans.client.tools.env import environment_append, no_op, pythonpath
 from conans.client.tools.oss import OSInfo
 from conans.errors import ConanException, ConanInvalidConfiguration
@@ -387,14 +388,9 @@ class ConanFile(object):
                 if win_bash:
                     return tools.run_in_windows_bash(self, bashcmd=cmd, cwd=cwd, subsystem=subsystem,
                                                      msys_mingw=msys_mingw, with_login=with_login)
-                elif self.win_bash:  # New, Conan 2.0
-                    from conans.client.subsystems import run_in_windows_bash
-                    return run_in_windows_bash(self, command=cmd, cwd=cwd, env=_env)
-            from conan.tools.env.environment import environment_wrap_command
-            if env:
-                wrapped_cmd = environment_wrap_command(_env, cmd, cwd=self.generators_folder)
-            else:
-                wrapped_cmd = cmd
+            envfiles_folder = self.generators_folder or os.getcwd()
+            _env = [_env] if _env and isinstance(_env, str) else []
+            wrapped_cmd = command_env_wrapper(self, cmd, _env, envfiles_folder=envfiles_folder)
             return self._conan_runner(wrapped_cmd, output, os.path.abspath(RUN_LOG_NAME), cwd)
 
         if run_environment:
diff --git a/conans/requirements.txt b/conans/requirements.txt
index f63e78be8..d03ac1588 100644
--- a/conans/requirements.txt
+++ b/conans/requirements.txt
@@ -1,4 +1,3 @@
-PyJWT>=1.4.0, <2.0.0
 requests>=2.25, <3.0.0
 urllib3>=1.26.6, <1.27
 colorama>=0.3.3, <0.5.0
diff --git a/conans/requirements_server.txt b/conans/requirements_server.txt
index ec06879ee..f7a3f7ab0 100644
--- a/conans/requirements_server.txt
+++ b/conans/requirements_server.txt
@@ -1,3 +1,4 @@
 # Server
 bottle>=0.12.8, < 0.13
 pluginbase>=0.5
+PyJWT>=2.4.0, <3.0.0
diff --git a/conans/server/crypto/jwt/jwt_manager.py b/conans/server/crypto/jwt/jwt_manager.py
index 160def2a9..ba4f35bdc 100644
--- a/conans/server/crypto/jwt/jwt_manager.py
+++ b/conans/server/crypto/jwt/jwt_manager.py
@@ -1,4 +1,5 @@
 from datetime import datetime
+from calendar import timegm
 
 import jwt
 
@@ -20,7 +21,7 @@ class JWTManager(object):
         profile_fields = profile_fields or {}
 
         if self.expire_time:
-            profile_fields["exp"] = datetime.utcnow() + self.expire_time
+            profile_fields["exp"] = timegm((datetime.utcnow() + self.expire_time).timetuple())
 
         return jwt.encode(profile_fields, self.secret, algorithm="HS256")
 
diff --git a/conans/server/launcher.py b/conans/server/launcher.py
index c9f210c2a..e424b407b 100644
--- a/conans/server/launcher.py
+++ b/conans/server/launcher.py
@@ -1,5 +1,6 @@
 #!/usr/bin/python
 import os
+import sys
 
 from conans import SERVER_CAPABILITIES, REVISIONS
 from conans.paths import conan_expand_user
@@ -16,6 +17,8 @@ from conans.server.service.authorize import BasicAuthorizer, BasicAuthenticator
 
 class ServerLauncher(object):
     def __init__(self, force_migration=False, server_dir=None):
+        if sys.version_info.major == 2:
+            raise Exception("The conan_server needs Python>=3 for running")
         self.force_migration = force_migration
         if server_dir:
             user_folder = server_folder = server_dir
diff --git a/conans/server/service/v1/upload_download_service.py b/conans/server/service/v1/upload_download_service.py
index 7745591eb..5cbb97902 100644
--- a/conans/server/service/v1/upload_download_service.py
+++ b/conans/server/service/v1/upload_download_service.py
@@ -23,7 +23,7 @@ class FileUploadDownloadService(object):
             logger.debug("Get file: user=%s path=%s" % (user, filepath))
             file_path = os.path.normpath(os.path.join(self.base_store_folder, encoded_path))
             return file_path
-        except (jwt.ExpiredSignature, jwt.DecodeError, AttributeError):
+        except (jwt.ExpiredSignatureError, jwt.DecodeError, AttributeError):
             raise NotFoundException("File not found")
 
     def put_file(self, file_saver, abs_filepath, token, upload_size):
@@ -46,7 +46,7 @@ class FileUploadDownloadService(object):
                 os.remove(abs_filepath)
             file_saver.save(os.path.dirname(abs_filepath))
 
-        except (jwt.ExpiredSignature, jwt.DecodeError, AttributeError):
+        except (jwt.ExpiredSignatureError, jwt.DecodeError, AttributeError):
             raise NotFoundException("File not found")
 
     def _valid_path(self, filepath, encoded_path):
@@ -59,5 +59,3 @@ class FileUploadDownloadService(object):
             return True
         else:
             return False
-
-
diff --git a/conans/server/store/disk_adapter.py b/conans/server/store/disk_adapter.py
index 70ee863f4..5ccc0183f 100644
--- a/conans/server/store/disk_adapter.py
+++ b/conans/server/store/disk_adapter.py
@@ -4,7 +4,7 @@ import fasteners
 
 from conans.client.tools.env import no_op
 from conans.errors import NotFoundException
-from conans.util.files import decode_text, md5sum, path_exists, relative_dirs, rmdir
+from conans.util.files import md5sum, path_exists, relative_dirs, rmdir
 
 
 class ServerDiskAdapter(object):
@@ -33,7 +33,7 @@ class ServerDiskAdapter(object):
             url_path = url_path.replace("\\", "/")
             # FALTA SIZE DEL FICHERO PARA EL UPLOAD URL!
             signature = self.updown_auth_manager.get_token_for(url_path, user)
-            url = "%s/%s?signature=%s" % (self.base_url, url_path, decode_text(signature))
+            url = "%s/%s?signature=%s" % (self.base_url, url_path, signature)
             ret[filepath] = url
 
         return ret
@@ -51,7 +51,7 @@ class ServerDiskAdapter(object):
             url_path = url_path.replace("\\", "/")
             # FALTA SIZE DEL FICHERO PARA EL UPLOAD URL!
             signature = self.updown_auth_manager.get_token_for(url_path, user, filesize)
-            url = "%s/%s?signature=%s" % (self.base_url, url_path, decode_text(signature))
+            url = "%s/%s?signature=%s" % (self.base_url, url_path, signature)
             ret[filepath] = url
 
         return ret
diff --git a/setup.py b/setup.py
index c41d133d3..9162a0991 100644
--- a/setup.py
+++ b/setup.py
@@ -46,13 +46,13 @@ def load_version():
 
 def generate_long_description_file():
     this_directory = path.abspath(path.dirname(__file__))
-    with open(path.join(this_directory, 'README.rst'), encoding='utf-8') as f:
+    with open(path.join(this_directory, 'README.rst')) as f:
         long_description = f.read()
     return long_description
 
-
 setup(
     name='conan',
+    python_requires='>=3.6',
     # Versions should comply with PEP440.  For a discussion on single-sourcing
     # the version across setup.py and the project code, see
     # https://packaging.python.org/en/latest/single_source_version.html


Test patch:
diff --git a/conans/test/conftest.py b/conans/test/conftest.py
index ce8beaee2..ea39c11b2 100644
--- a/conans/test/conftest.py
+++ b/conans/test/conftest.py
@@ -76,7 +76,8 @@ tools_locations = {
         "3.23": {
             "path": {'Windows': 'C:/cmake/cmake-3.23.1-win64-x64/bin',
                      'Darwin': '/Users/jenkins/cmake/cmake-3.23.1/bin',
-                     'Linux': '/usr/share/cmake-3.23.1/bin'}
+                     # Not available in Linux
+                     'Linux': None}
         }
     },
     'ninja': {
@@ -188,6 +189,16 @@ def _get_tool(name, version):
                 _cached_tools[name][version] = False
                 return False
             tool_path = tool_version.get("path", {}).get(tool_platform)
+            # To allow to skip for a platform, we can put the path to None
+            # "cmake": { "3.23": {
+            #               "path": {'Windows': 'C:/cmake/cmake-3.23.1-win64-x64/bin',
+            #                        'Darwin': '/Users/jenkins/cmake/cmake-3.23.1/bin',
+            #                        'Linux': None}}
+            #          }
+            if tool_path is None:
+                _cached_tools[name][version] = False
+                return False
+
         else:
             if version is not None:  # if the version is specified, it should be in the conf
                 _cached_tools[name][version] = True
diff --git a/conans/test/functional/layout/test_editable_cmake.py b/conans/test/functional/layout/test_editable_cmake.py
index 380c54b44..8845f2816 100644
--- a/conans/test/functional/layout/test_editable_cmake.py
+++ b/conans/test/functional/layout/test_editable_cmake.py
@@ -113,12 +113,12 @@ def editable_cmake_exe(generator):
 
     def run_pkg(msg):
         # FIXME: This only works with ``--install-folder``, layout() will break this
-        cmd_release = environment_wrap_command("conanrunenv-release-x86_64",
-                                               "dep_app", cwd=c.current_folder)
+        cmd_release = environment_wrap_command("conanrunenv-release-x86_64", c.current_folder,
+                                               "dep_app",)
         c.run_command(cmd_release)
         assert "{}: Release!".format(msg) in c.out
-        cmd_release = environment_wrap_command("conanrunenv-debug-x86_64",
-                                               "dep_app", cwd=c.current_folder)
+        cmd_release = environment_wrap_command("conanrunenv-debug-x86_64", c.current_folder,
+                                               "dep_app", )
         c.run_command(cmd_release)
         assert "{}: Debug!".format(msg) in c.out
 
diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py
index 3859aabf6..fd07e609d 100644
--- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py
+++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py
@@ -788,3 +788,49 @@ def test_cmaketoolchain_sysroot():
     })
     client.run("create . app/1.0@")
     assert "sysroot: '{}'".format(output_fake_sysroot) in client.out
+
+
+# FIXME: DEVELOP2: @pytest.mark.tool("cmake", "3.23")
+@pytest.mark.tool_cmake(version="3.23")
+def test_cmake_presets_with_conanfile_txt():
+    c = TestClient()
+
+    # FIXME: DEVELOP 2: c.run("new cmake_exe -d name=foo -d version=1.0")
+    c.run("new foo/1.0 --template cmake_exe")
+    os.unlink(os.path.join(c.current_folder, "conanfile.py"))
+    c.save({"conanfile.txt": textwrap.dedent("""
+
+    [generators]
+    CMakeToolchain
+
+    [layout]
+    cmake_layout
+
+    """)})
+
+    c.run("install .")
+    c.run("install . -s build_type=Debug")
+    assert os.path.exists(os.path.join(c.current_folder, "CMakeUserPresets.json"))
+    presets_path = os.path.join(c.current_folder, "build", "generators", "CMakePresets.json")
+    assert os.path.exists(presets_path)
+
+    if platform.system() != "Windows":
+        c.run_command("cmake --preset Debug")
+        c.run_command("cmake --build --preset Debug")
+        c.run_command("./cmake-build-debug/foo")
+    else:
+        c.run_command("cmake --preset default")
+        c.run_command("cmake --build --preset Debug")
+        c.run_command("build\\Debug\\foo")
+
+    assert "Hello World Debug!" in c.out
+
+    if platform.system() != "Windows":
+        c.run_command("cmake --preset Release")
+        c.run_command("cmake --build --preset Release")
+        c.run_command("./cmake-build-release/foo")
+    else:
+        c.run_command("cmake --build --preset Release")
+        c.run_command("build\\Release\\foo")
+
+    assert "Hello World Release!" in c.out
diff --git a/conans/test/functional/toolchains/cmake/test_shared_cmake.py b/conans/test/functional/toolchains/cmake/test_shared_cmake.py
index 6b3b037b0..293d2d6e0 100644
--- a/conans/test/functional/toolchains/cmake/test_shared_cmake.py
+++ b/conans/test/functional/toolchains/cmake/test_shared_cmake.py
@@ -1,6 +1,5 @@
 from conan.tools.env.environment import environment_wrap_command
 from conans.test.assets.pkg_cmake import pkg_cmake, pkg_cmake_app, pkg_cmake_test
-from conans.test.utils.mocks import ConanFileMock
 from conans.test.utils.tools import TestClient
 
 
@@ -18,7 +17,7 @@ def test_shared_cmake_toolchain():
 
     client = TestClient(servers=client.servers, users=client.users)
     client.run("install app/0.1@ -o chat:shared=True -o hello:shared=True -g VirtualRunEnv")
-    command = environment_wrap_command("conanrun", "app", cwd=client.current_folder)
+    command = environment_wrap_command("conanrun", client.current_folder, "app")
 
     client.run_command(command)
     assert "main: Release!" in client.out
diff --git a/conans/test/functional/toolchains/gnu/autotools/test_basic.py b/conans/test/functional/toolchains/gnu/autotools/test_basic.py
index 3ef85610a..3d4a41f96 100644
--- a/conans/test/functional/toolchains/gnu/autotools/test_basic.py
+++ b/conans/test/functional/toolchains/gnu/autotools/test_basic.py
@@ -95,7 +95,7 @@ def build_windows_subsystem(profile, make_program):
     client.run("install . --profile=profile")
     cmd = environment_wrap_command(["conanbuildenv",
                                     "conanautotoolstoolchain",
-                                    "conanautotoolsdeps"], make_program, cwd=client.current_folder)
+                                    "conanautotoolsdeps"], client.current_folder, make_program)
     client.run_command(cmd)
     client.run_command("app")
     # TODO: fill compiler version when ready
diff --git a/conans/test/integration/environment/test_env.py b/conans/test/integration/environment/test_env.py
index f6d39692a..cfcd45cd1 100644
--- a/conans/test/integration/environment/test_env.py
+++ b/conans/test/integration/environment/test_env.py
@@ -103,16 +103,15 @@ def test_complete(client):
     client.run("install . -s:b os=Windows -s:h os=Linux --build=missing")
     # Run the BUILD environment
     if platform.system() == "Windows":
-        cmd = environment_wrap_command("conanbuildenv", "mycmake.bat",
-                                       cwd=client.current_folder)
+        cmd = environment_wrap_command("conanbuildenv", client.current_folder, "mycmake.bat")
         client.run_command(cmd)
         assert "MYCMAKE=Windows!!" in client.out
         assert "MYOPENSSL=Windows!!" in client.out
 
     # Run the RUN environment
     if platform.system() != "Windows":
-        cmd = environment_wrap_command("conanrunenv", "mygtest.sh && .{}myrunner.sh".format(os.sep),
-                                       cwd=client.current_folder)
+        cmd = environment_wrap_command("conanrunenv", client.current_folder,
+                                       "mygtest.sh && .{}myrunner.sh".format(os.sep))
         client.run_command(cmd)
         assert "MYGTEST=Linux!!" in client.out
         assert "MYGTESTVAR=MyGTestValueLinux!!" in client.out
@@ -204,8 +203,8 @@ def test_profile_buildenv():
     client.run("install . -pr=myprofile")
     # Run the BUILD environment
     ext = "bat" if platform.system() == "Windows" else "sh"  # TODO: Decide on logic .bat vs .sh
-    cmd = environment_wrap_command("conanbuildenv", "mycompiler.{}".format(ext),
-                                   cwd=client.current_folder)
+    cmd = environment_wrap_command("conanbuildenv", client.current_folder,
+                                   "mycompiler.{}".format(ext))
     client.run_command(cmd)
     assert "MYCOMPILER!!" in client.out
     assert "MYPATH=" in client.out
@@ -543,8 +542,8 @@ def test_massive_paths(num_deps):
     assert os.path.isfile(os.path.join(client.current_folder, "conanrunenv.ps1"))
     assert not os.path.isfile(os.path.join(client.current_folder, "conanrunenv.bat"))
     for i in range(num_deps):
-        cmd = environment_wrap_command("conanrunenv", "mycompiler{}.bat".format(i),
-                                       cwd=client.current_folder)
+        cmd = environment_wrap_command("conanrunenv", client.current_folder,
+                                       "mycompiler{}.bat".format(i))
         if num_deps > 50:  # to be safe if we change the "num_deps" number
             client.run_command(cmd, assert_error=True)
             assert "is not recognized as an internal" in client.out
@@ -558,8 +557,8 @@ def test_massive_paths(num_deps):
     assert not os.path.isfile(os.path.join(client.current_folder, "conanrunenv.ps1"))
     assert os.path.isfile(os.path.join(client.current_folder, "conanrunenv.bat"))
     for i in range(num_deps):
-        cmd = environment_wrap_command("conanrunenv", "mycompiler{}.bat".format(i),
-                                       cwd=client.current_folder)
+        cmd = environment_wrap_command("conanrunenv", client.current_folder,
+                                       "mycompiler{}.bat".format(i))
         if num_deps > 50:  # to be safe if we change the "num_deps" number
             client.run_command(cmd, assert_error=True)
             # This also fails, but without an error message (in my terminal, it kills the terminal!)
diff --git a/conans/test/integration/toolchains/env/test_virtualenv_winbash.py b/conans/test/integration/toolchains/env/test_virtualenv_winbash.py
index 4bd7abbac..e79fdbd0f 100644
--- a/conans/test/integration/toolchains/env/test_virtualenv_winbash.py
+++ b/conans/test/integration/toolchains/env/test_virtualenv_winbash.py
@@ -1,8 +1,6 @@
 import os
 import platform
-import textwrap
 
-import mock
 import pytest
 
 from conans.test.assets.genconanfile import GenConanfile
diff --git a/conans/test/unittests/client/conanfile_loader_test.py b/conans/test/unittests/client/conanfile_loader_test.py
index cd272d81f..61666f1a7 100644
--- a/conans/test/unittests/client/conanfile_loader_test.py
+++ b/conans/test/unittests/client/conanfile_loader_test.py
@@ -253,6 +253,34 @@ licenses, * -> ./licenses @ root_package=Pkg, folder=True, ignore_case=False, ex
                                    "Options should be specified as 'pkg:option=value'"):
             loader.load_conanfile_txt(file_path, create_profile())
 
+    def test_layout_not_predefined(self):
+        txt = textwrap.dedent("""
+                    [layout]
+                    missing
+                """)
+        tmp_dir = temp_folder()
+        file_path = os.path.join(tmp_dir, "conanfile.txt")
+        save(file_path, txt)
+        with pytest.raises(ConanException) as exc:
+            loader = ConanFileLoader(None, Mock(), None)
+            loader.load_conanfile_txt(file_path, create_profile())
+        assert "Unknown predefined layout 'missing'" in str(exc.value)
+
+    def test_layout_multiple(self):
+        txt = textwrap.dedent("""
+                    [layout]
+                    cmake_layout
+                    vs_layout
+                """)
+        tmp_dir = temp_folder()
+        file_path = os.path.join(tmp_dir, "conanfile.txt")
+        save(file_path, txt)
+        with pytest.raises(ConanException) as exc:
+            loader = ConanFileLoader(None, Mock(), None)
+            loader.load_conanfile_txt(file_path, create_profile())
+        assert "Only one layout can be declared in the [layout] section of the conanfile.txt" \
+               in str(exc.value)
+
 
 class ImportModuleLoaderTest(unittest.TestCase):
     @staticmethod
diff --git a/conans/test/unittests/server/crypto/jwt_test.py b/conans/test/unittests/server/crypto/jwt_test.py
index 5f8b07d3f..9c6b916a4 100644
--- a/conans/test/unittests/server/crypto/jwt_test.py
+++ b/conans/test/unittests/server/crypto/jwt_test.py
@@ -31,7 +31,7 @@ class JwtTest(unittest.TestCase):
 
         # Now wait 2 seconds and check if its valid now
         time.sleep(2)
-        self.assertRaises(jwt.ExpiredSignature, manager.get_profile, token)
+        self.assertRaises(jwt.ExpiredSignatureError, manager.get_profile, token)
 
     def test_jwt_credentials_manager(self):
         manager = JWTCredentialsManager(self.secret, self.expire_time)