From 223ab0f4845299ea30f432adaef8b8df20aff6d5 Mon Sep 17 00:00:00 2001 From: Luis Martinez de Bartolome Izquierdo Date: Fri, 8 Jan 2021 16:38:05 +0100 Subject: [PATCH] Recipe Layouts: Step 0 (#8243) * Minimum changes * Fixed mock value install folder * litle review changes * Changed data structure * Clean code --- conans/model/conan_file.py | 38 ++++++++++++++++++++ conans/model/layout.py | 71 ++++++++++++++++++++++++++++++++++++++ conans/test/utils/mocks.py | 9 +++-- 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 conans/model/layout.py diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index ccd2652f631..67b46010768 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -11,6 +11,7 @@ from conans.errors import ConanException, ConanInvalidConfiguration from conans.model.build_info import DepsCppInfo from conans.model.env_info import DepsEnvInfo +from conans.model.layout import Layout from conans.model.options import Options, OptionsValues, PackageOptions from conans.model.requires import Requirements from conans.model.user_info import DepsUserInfo @@ -132,6 +133,9 @@ class ConanFile(object): provides = None deprecated = None + # layout + layout = None + def __init__(self, output, runner, display_name="", user=None, channel=None): # an output stream (writeln, info, warn error) self.output = ScopedOutput(display_name, output) @@ -144,6 +148,8 @@ def __init__(self, output, runner, display_name="", user=None, channel=None): self.compatible_packages = [] self._conan_using_build_profile = False + self.layout = Layout() + def initialize(self, settings, env): if isinstance(self.generators, str): self.generators = [self.generators] @@ -176,6 +182,38 @@ def initialize(self, settings, env): if self.description is not None and not isinstance(self.description, six.string_types): raise ConanException("Recipe 'description' must be a string.") + @property + def source_folder(self): + return self.layout.source_folder + + @source_folder.setter + def source_folder(self, folder): + self.layout.set_base_source_folder(folder) + + @property + def build_folder(self): + return self.layout.build_folder + + @build_folder.setter + def build_folder(self, folder): + self.layout.set_base_build_folder(folder) + + @property + def install_folder(self): + return self.layout.install_folder + + @install_folder.setter + def install_folder(self, folder): + self.layout.set_base_install_folder(folder) + + @property + def package_folder(self): + return self.layout.package_folder + + @package_folder.setter + def package_folder(self, folder): + self.layout.set_base_package_folder(folder) + @property def env(self): """Apply the self.deps_env_info into a copy of self._conan_env_values (will prioritize the diff --git a/conans/model/layout.py b/conans/model/layout.py new file mode 100644 index 00000000000..ee51a9de1d1 --- /dev/null +++ b/conans/model/layout.py @@ -0,0 +1,71 @@ +import os + + +class _LayoutEntry(object): + + def __init__(self): + self.folder = "" + + +class Layout(object): + def __init__(self): + + self._base_source_folder = None + self._base_build_folder = None + self._base_install_folder = None + self._base_package_folder = None + + self.install = _LayoutEntry() + self.source = _LayoutEntry() + self.build = _LayoutEntry() + self.package = _LayoutEntry() # Where the artifacts are installed + + def __repr__(self): + return str(self.__dict__) + + @property + def source_folder(self): + if self._base_source_folder is None: + return None + if not self.source.folder: + return self._base_source_folder + + return os.path.join(self._base_source_folder, self.source.folder) + + def set_base_source_folder(self, folder): + self._base_source_folder = folder + + @property + def build_folder(self): + if self._base_build_folder is None: + return None + if not self.build.folder: + return self._base_build_folder + return os.path.join(self._base_build_folder, self.build.folder) + + def set_base_build_folder(self, folder): + self._base_build_folder = folder + + @property + def install_folder(self): + if self._base_install_folder is None: + return self.build_folder # If None, default to build_folder (review) + if not self.install.folder: + return self._base_install_folder + + return os.path.join(self._base_install_folder, self.install.folder) + + def set_base_install_folder(self, folder): + self._base_install_folder = folder + + @property + def package_folder(self): + if self._base_package_folder is None: + return None + if not self.package.folder: + return self._base_package_folder + + return os.path.join(self._base_package_folder, self.package.folder) + + def set_base_package_folder(self, folder): + self._base_package_folder = folder diff --git a/conans/test/utils/mocks.py b/conans/test/utils/mocks.py index 9574398e6c9..da5295a2804 100644 --- a/conans/test/utils/mocks.py +++ b/conans/test/utils/mocks.py @@ -10,6 +10,7 @@ from conans.client.output import ConanOutput from conans.client.userio import UserIO from conans.model.env_info import DepsEnvInfo, EnvInfo, EnvValues +from conans.model.layout import Layout from conans.model.options import PackageOptions from conans.model.user_info import DepsUserInfo @@ -123,6 +124,7 @@ def deps(self): class MockConanfile(ConanFile): def __init__(self, settings, options=None, runner=None): + self.layout = Layout() self.deps_cpp_info = MockDepsCppInfo() self.settings = settings self.runner = runner @@ -137,6 +139,7 @@ def __init__(self, settings, options=None, runner=None): self.package_folder = None + def run(self, *args, **kwargs): if self.runner: kwargs["output"] = None @@ -149,7 +152,6 @@ def __init__(self, shared=None, options=None, options_values=None): options = options or "" self.command = None self.path = None - self.source_folder = self.build_folder = "." self.settings = None self.options = Options(PackageOptions.loads(options)) if options_values: @@ -159,7 +161,6 @@ def __init__(self, shared=None, options=None, options_values=None): self.deps_cpp_info.sysroot = "/path/to/sysroot" self.output = TestBufferConanOutput() self.in_local_cache = False - self.install_folder = "myinstallfolder" if shared is not None: self.options = namedtuple("options", "shared")(shared) self.should_configure = True @@ -172,6 +173,10 @@ def __init__(self, shared=None, options=None, options_values=None): self.env_info = EnvInfo() self.deps_user_info = DepsUserInfo() self._conan_env_values = EnvValues() + self.layout = Layout() + self.layout.set_base_source_folder(".") + self.layout.set_base_build_folder(".") + self.layout.set_base_install_folder("myinstallfolder") def run(self, command, win_bash=False, subsystem=None): assert win_bash is False