Exemple #1
0
class ConanFileMock(ConanFile):
    def __init__(self, shared=None, options=None, options_values=None):
        options = options or ""
        self.command = None
        self.path = None
        self.settings = None
        self.options = Options(PackageOptions.loads(options))
        if options_values:
            for var, value in options_values.items():
                self.options._data[var] = value
        self.deps_cpp_info = MockDepsCppInfo(
        )  # ("deps_cpp_info", "sysroot")("/path/to/sysroot")
        self.deps_cpp_info.sysroot = "/path/to/sysroot"
        self.output = TestBufferConanOutput()
        self.in_local_cache = False
        if shared is not None:
            self.options = namedtuple("options", "shared")(shared)
        self.should_configure = True
        self.should_build = True
        self.should_install = True
        self.should_test = True
        self.generators = []
        self.captured_env = {}
        self.deps_env_info = DepsEnvInfo()
        self.env_info = EnvInfo()
        self.deps_user_info = DepsUserInfo()
        self._conan_env_values = EnvValues()
        self.folders = Folders()
        self.folders.set_base_source(".")
        self.folders.set_base_build(".")
        self.folders.set_base_install("myinstallfolder")
        self.folders.set_base_generators(".")
        self._conan_user = None
        self._conan_channel = None
        self.environment_scripts = []

    def run(self, command, win_bash=False, subsystem=None, env=None):
        assert win_bash is False
        assert subsystem is None
        self.command = command
        self.path = os.environ["PATH"]
        self.captured_env = {key: value for key, value in os.environ.items()}
Exemple #2
0
    def __init__(self,
                 output,
                 runner,
                 display_name="",
                 user=None,
                 channel=None):
        # an output stream (writeln, info, warn error)
        self.output = ScopedOutput(display_name, output)
        self.display_name = display_name
        # something that can run commands, as os.sytem
        self._conan_runner = runner
        self._conan_user = user
        self._conan_channel = channel

        self.compatible_packages = []
        self._conan_using_build_profile = False
        self._conan_requester = None
        from conan.tools.env import Environment
        self.buildenv_info = Environment()
        self.runenv_info = Environment()
        # At the moment only for build_requires, others will be ignored
        self.conf_info = Conf()
        self._conan_buildenv = None  # The profile buildenv, will be assigned initialize()
        self._conan_node = None  # access to container Node object, to access info, context, deps...
        self._conan_new_cpp_info = None  # Will be calculated lazy in the getter
        self._conan_dependencies = None

        self.env_scripts = {}  # Accumulate the env scripts generated in order

        # layout() method related variables:
        self.folders = Folders()
        self.cpp = Infos()

        self.cpp.package.includedirs = ["include"]
        self.cpp.package.libdirs = ["lib"]
        self.cpp.package.bindirs = ["bin"]
        self.cpp.package.resdirs = ["res"]
        self.cpp.package.builddirs = [""]
        self.cpp.package.frameworkdirs = ["Frameworks"]
Exemple #3
0
class ConanFile(object):
    """ The base class for all package recipes
    """

    name = None
    version = None  # Any str, can be "1.1" or whatever
    url = None  # The URL where this File is located, as github, to collaborate in package
    # The license of the PACKAGE, just a shortcut, does not replace or
    # change the actual license of the source code
    license = None
    author = None  # Main maintainer/responsible for the package, any format
    description = None
    topics = None
    homepage = None
    build_policy = None
    short_paths = False
    apply_env = True  # Apply environment variables from requires deps_env_info and profiles
    exports = None
    exports_sources = None
    generators = ["txt"]
    revision_mode = "hash"

    # Vars to control the build steps (build(), package())
    should_configure = True
    should_build = True
    should_install = True
    should_test = True
    in_local_cache = True
    develop = False

    # Defaulting the reference fields
    default_channel = None
    default_user = None

    # Settings and Options
    settings = None
    options = None
    default_options = None

    provides = None
    deprecated = None

    # Folders
    folders = None
    patterns = None

    # Run in windows bash
    win_bash = 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)
        self.display_name = display_name
        # something that can run commands, as os.sytem
        self._conan_runner = runner
        self._conan_user = user
        self._conan_channel = channel

        self.compatible_packages = []
        self._conan_using_build_profile = False
        self._conan_requester = None

        self.buildenv_info = Environment(self)
        self.runenv_info = Environment(self)
        # At the moment only for build_requires, others will be ignored
        self.conf_info = Conf()
        self._conan_buildenv = None  # The profile buildenv, will be assigned initialize()
        self._conan_node = None  # access to container Node object, to access info, context, deps...
        self._conan_new_cpp_info = None  # Will be calculated lazy in the getter
        self._conan_dependencies = None

        self.env_scripts = {}  # Accumulate the env scripts generated in order

        # layout() method related variables:
        self.folders = Folders()
        self.patterns = Patterns()
        self.cpp = Infos()

        self.patterns.source.include = ["*.h", "*.hpp", "*.hxx"]
        self.patterns.source.lib = []
        self.patterns.source.bin = []

        self.patterns.build.include = ["*.h", "*.hpp", "*.hxx"]
        self.patterns.build.lib = ["*.so", "*.so.*", "*.a", "*.lib", "*.dylib"]
        self.patterns.build.bin = ["*.exe", "*.dll"]

        self.cpp.package.includedirs = ["include"]
        self.cpp.package.libdirs = ["lib"]
        self.cpp.package.bindirs = ["bin"]
        self.cpp.package.resdirs = ["res"]
        self.cpp.package.builddirs = [""]
        self.cpp.package.frameworkdirs = ["Frameworks"]

    @property
    def context(self):
        return self._conan_node.context

    @property
    def dependencies(self):
        # Caching it, this object is requested many times
        if self._conan_dependencies is None:
            self._conan_dependencies = ConanFileDependencies.from_node(
                self._conan_node)
        return self._conan_dependencies

    @property
    def ref(self):
        return self._conan_node.ref

    @property
    def pref(self):
        return self._conan_node.pref

    @property
    def buildenv(self):
        # Lazy computation of the package buildenv based on the profileone
        if not isinstance(self._conan_buildenv, Environment):
            # TODO: missing user/channel
            ref_str = "{}/{}".format(self.name, self.version)
            self._conan_buildenv = self._conan_buildenv.get_env(self, ref_str)
        return self._conan_buildenv

    def initialize(self, settings, env, buildenv=None):
        self._conan_buildenv = buildenv
        if isinstance(self.generators, str):
            self.generators = [self.generators]
        # User defined options
        self.options = create_options(self)
        self.requires = create_requirements(self)
        self.settings = create_settings(self, settings)

        conan_v2_error(
            "Setting 'cppstd' is deprecated in favor of 'compiler.cppstd',"
            " please update your recipe.", 'cppstd' in self.settings.fields)

        # needed variables to pack the project
        self.cpp_info = None  # Will be initialized at processing time
        self._conan_dep_cpp_info = None  # Will be initialized at processing time
        self.deps_cpp_info = DepsCppInfo()

        # environment variables declared in the package_info
        self.env_info = None  # Will be initialized at processing time
        self.deps_env_info = DepsEnvInfo()

        # user declared variables
        self.user_info = None
        # Keys are the package names (only 'host' if different contexts)
        self.deps_user_info = DepsUserInfo()

        # user specified env variables
        self._conan_env_values = env.copy()  # user specified -e

        if self.description is not None and not isinstance(
                self.description, six.string_types):
            raise ConanException("Recipe 'description' must be a string.")

        if not hasattr(self, "virtualbuildenv"
                       ):  # Allow the user to override it with True or False
            self.virtualbuildenv = True
        if not hasattr(self, "virtualrunenv"
                       ):  # Allow the user to override it with True or False
            self.virtualrunenv = True

    @property
    def new_cpp_info(self):
        if not self._conan_new_cpp_info:
            self._conan_new_cpp_info = from_old_cppinfo(self.cpp_info)
        return self._conan_new_cpp_info

    @property
    def source_folder(self):
        return self.folders.source_folder

    @source_folder.setter
    def source_folder(self, folder):
        self.folders.set_base_source(folder)

    @property
    def build_folder(self):
        return self.folders.build_folder

    @build_folder.setter
    def build_folder(self, folder):
        self.folders.set_base_build(folder)

    @property
    def package_folder(self):
        return self.folders.package_folder

    @package_folder.setter
    def package_folder(self, folder):
        self.folders.set_base_package(folder)

    @property
    def install_folder(self):
        # FIXME: Remove in 2.0, no self.install_folder
        return self.folders.base_install

    @install_folder.setter
    def install_folder(self, folder):
        # FIXME: Remove in 2.0, no self.install_folder
        self.folders.set_base_install(folder)

    @property
    def generators_folder(self):
        # FIXME: Remove in 2.0, no self.install_folder
        return self.folders.generators_folder if self.folders.generators else self.install_folder

    @property
    def imports_folder(self):
        return self.folders.imports_folder

    @imports_folder.setter
    def imports_folder(self, folder):
        self.folders.set_base_imports(folder)

    @property
    def env(self):
        """Apply the self.deps_env_info into a copy of self._conan_env_values (will prioritize the
        self._conan_env_values, user specified from profiles or -e first, then inherited)"""
        # Cannot be lazy cached, because it's called in configure node, and we still don't have
        # the deps_env_info objects available
        tmp_env_values = self._conan_env_values.copy()
        tmp_env_values.update(self.deps_env_info)
        ret, multiple = tmp_env_values.env_dicts(self.name, self.version,
                                                 self._conan_user,
                                                 self._conan_channel)
        ret.update(multiple)
        return ret

    @property
    def channel(self):
        if not self._conan_channel:
            _env_channel = os.getenv("CONAN_CHANNEL")
            conan_v2_error(
                "Environment variable 'CONAN_CHANNEL' is deprecated",
                _env_channel)
            self._conan_channel = _env_channel or self.default_channel
            if not self._conan_channel:
                raise ConanException(
                    "channel not defined, but self.channel is used in conanfile"
                )
        return self._conan_channel

    @property
    def user(self):
        if not self._conan_user:
            _env_username = os.getenv("CONAN_USERNAME")
            conan_v2_error(
                "Environment variable 'CONAN_USERNAME' is deprecated",
                _env_username)
            self._conan_user = _env_username or self.default_user
            if not self._conan_user:
                raise ConanException(
                    "user not defined, but self.user is used in conanfile")
        return self._conan_user

    def collect_libs(self, folder=None):
        conan_v2_error(
            "'self.collect_libs' is deprecated, use 'tools.collect_libs(self)' instead"
        )
        return tools.collect_libs(self, folder=folder)

    @property
    def build_policy_missing(self):
        return self.build_policy == "missing"

    @property
    def build_policy_always(self):
        return self.build_policy == "always"

    def source(self):
        pass

    def system_requirements(self):
        """ this method can be overwritten to implement logic for system package
        managers, as apt-get

        You can define self.global_system_requirements = True, if you want the installation
        to be for all packages (not depending on settings/options/requirements)
        """

    def config_options(self):
        """ modify options, probably conditioned to some settings. This call is executed
        before config_settings. E.g.
        if self.settings.os == "Windows":
            del self.options.shared  # shared/static not supported in win
        """

    def configure(self):
        """ modify settings, probably conditioned to some options. This call is executed
        after config_options. E.g.
        if self.options.header_only:
            self.settings.clear()
        This is also the place for conditional requirements
        """

    def build(self):
        """ build your project calling the desired build tools as done in the command line.
        E.g. self.run("cmake --build .") Or use the provided build helpers. E.g. cmake.build()
        """
        self.output.warn("This conanfile has no build step")

    def package(self):
        """ package the needed files from source and build folders.
        E.g. self.copy("*.h", src="src/includes", dst="includes")
        """
        self.output.warn("This conanfile has no package step")

    def package_info(self):
        """ define cpp_build_info, flags, etc
        """

    def run(self,
            command,
            output=True,
            cwd=None,
            win_bash=False,
            subsystem=None,
            msys_mingw=True,
            ignore_errors=False,
            run_environment=False,
            with_login=True,
            env=None):
        # NOTE: "self.win_bash" is the new parameter "win_bash" for Conan 2.0

        def _run(cmd, _env):
            # FIXME: run in windows bash is not using output
            if platform.system() == "Windows":
                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 conan.tools.microsoft.subsystems import run_in_windows_bash
                    return run_in_windows_bash(self,
                                               command=cmd,
                                               cwd=cwd,
                                               env=_env)
            if _env is None:
                _env = "conanbuild"
            wrapped_cmd = environment_wrap_command(self,
                                                   _env,
                                                   cmd,
                                                   cwd=self.generators_folder)
            return self._conan_runner(wrapped_cmd, output,
                                      os.path.abspath(RUN_LOG_NAME), cwd)

        if run_environment:
            # When using_build_profile the required environment is already applied through
            # 'conanfile.env' in the contextmanager 'get_env_context_manager'
            with tools.run_environment(
                    self) if not self._conan_using_build_profile else no_op():
                if OSInfo().is_macos and isinstance(command, string_types):
                    # Security policy on macOS clears this variable when executing /bin/sh. To
                    # keep its value, set it again inside the shell when running the command.
                    command = 'DYLD_LIBRARY_PATH="%s" DYLD_FRAMEWORK_PATH="%s" %s' % \
                              (os.environ.get('DYLD_LIBRARY_PATH', ''),
                               os.environ.get("DYLD_FRAMEWORK_PATH", ''),
                               command)
                retcode = _run(command, env)
        else:
            retcode = _run(command, env)

        if not ignore_errors and retcode != 0:
            raise ConanException("Error %d while executing %s" %
                                 (retcode, command))

        return retcode

    def package_id(self):
        """ modify the binary info, typically to narrow values
        e.g.: self.info.settings.compiler = "Any" => All compilers will generate same ID
        """

    def test(self):
        """ test the generated executable.
        E.g.  self.run("./example")
        """
        raise ConanException(
            "You need to create a method 'test' in your test/conanfile.py")

    def __repr__(self):
        return self.display_name