https://codeberg.org/interpeer/liberate.git
Raw File
Tip revision: 8b54e65d8419772e0721c969273aec91961c41f3 authored by Jens Finkhaeuser on 04 May 2023, 07:42:04 UTC
Migrate clone changes over from s3kr1t
Tip revision: 8b54e65
conanfile.py
import os
from conan import ConanFile
from conan.tools.meson import MesonToolchain, Meson
from conan.tools.layout import basic_layout
from conan.tools.files import copy
from conan.tools import scm

def get_meson_build(filename = 'meson.build'):
    if hasattr(get_meson_build, '__cache'):
        return getattr(get_meson_build, '__cache')

    try:
        import os
        from mesonbuild import mparser, mesonlib
        fn = os.path.join(os.getcwd(), filename)
        with open(fn, encoding='utf-8') as f:
            ast = mparser.Parser(f.read(), filename).parse()
            setattr(get_meson_build, '__cache', ast)
            return ast
    except:
        return None



def _recurse_ast_lines(lines, nodes):
    from mesonbuild import mparser
    for cur in lines:
        found = False
        for node_type, node_name in nodes:
            if isinstance(cur, node_type):
                # Match, but depending on node_type we may have some different
                # thing to do.
                if node_type == mparser.FunctionNode:
                    if cur.func_name == node_name:
                        found = True
                        yield cur
                elif node_type == mparser.MethodNode:
                    if cur.name == node_name:
                        found = True
                        yield cur
        if not found:
            if isinstance(cur, mparser.IfClauseNode):
                for ifb in cur.ifs:
                    for entry in _recurse_ast_lines(ifb.block.lines, nodes):
                        yield entry
                if isinstance(cur.elseblock, mparser.CodeBlockNode):
                    for entry in _recurse_ast_lines(cur.elseblock.lines, nodes):
                        yield entry
            elif isinstance(cur, mparser.AssignmentNode):
                for entry in _recurse_ast_lines([cur.value], nodes):
                    yield entry



def recurse_find(filename, nodes):
    ast = get_meson_build(filename)
    if ast is None:
        return
    for entry in _recurse_ast_lines(ast.lines, nodes):
        yield entry



def get_project(filename = 'meson.build'):
    from mesonbuild import mparser
    for node in recurse_find(filename, [(mparser.FunctionNode, 'project')]):
        return node
    return None



def get_repo(filename = 'meson.build'):
    from mesonbuild import mparser
    for node in recurse_find(filename, [(mparser.MethodNode, 'set_quoted')]):
        key, value = node.args.arguments
        if key.value.endswith('_PACKAGE_URL'):
            return value.value
    return None


def get_libs(filename = 'meson.build'):
    res = {
        'shared': [],
        'static': [],
        'both': [],
    }

    from mesonbuild import mparser
    nodes = [
        (mparser.FunctionNode, 'shared_library'),
        (mparser.FunctionNode, 'static_library'),
        (mparser.FunctionNode, 'library'),
    ]
    for node in recurse_find(filename, nodes):
        key = 'both'
        if node.func_name == 'shared_library':
            key = 'shared'
        elif node.func_name == 'static_library':
            key = 'static'
        res[key].append(node.args.arguments[0].value)
    return res


def get_author():
    try:
        with open('AUTHORS', 'r') as fh:
            return fh.readlines()[0].strip()
    except:
        return None


def get_package():
    proj = get_project()
    if proj is None:
        return None
    return proj.args.arguments[0].value


def get_version():
    proj = get_project()
    if proj is None:
        return None
    for key, value in proj.args.kwargs.items():
        if key.value != 'version':
            continue
        return value.value


def get_git_ref(conanfile):
    git = scm.Git(conanfile)
    return git.get_commit()[:8]


def get_full_version(conanfile):
    try:
        return f'{get_version()}+{get_git_ref(conanfile)}'
    except:
        return None


class Package(ConanFile):
    generators = ('PkgConfigDeps', 'CMakeDeps')
    settings = ('os', 'arch', 'compiler', 'build_type')

    name = get_package()

    url = get_repo()
    author = get_author()

    @property
    def description(self):
        return self.conan_data['description']

    @property
    def topics(self):
        return self.conan_data['topics']

    @property
    def license(self):
        return self.conan_data['license']

    @property
    def homepage(self):
        return self.conan_data['homepage']

    @property
    def version(self):
        if not hasattr(self, '__version') or not self.__version:
            self.__version = get_full_version(self)
        return self.__version

    @version.setter
    def version(self, value):
        print('setting to', value)
        self.__version = value

    # Binary configuration
    options = {'shared': [True, False]}
    default_options = {'shared': False}

    # Sources are located in the same place as this recipe, copy them to the recipe
    exports = (
        "LICENSE",
        "codemeta.json",
        "AUTHORS",
        "meson.build", # XXX Need this also here for project definitions
    )
    exports_sources = (
        "meson.build",
        "meson_options.txt",
        ".oclint",
        "build-config.h.in",
        "include/*",
        "lib/*",
        "vendor/*",
        "test/*",
        "examples/*",
        "subprojects/*.wrap",
    )

    def config_options(self):
        if self.settings.os == "Windows":
            del self.options.fPIC

    def build_requirements(self):
        self.tool_requires('pkgconf/[>=1.9]')

    def requirements(self):
        for req in self.conan_data.get('requires', []):
            self.requires(req)

    def layout(self):
        basic_layout(self)

    def generate(self):
        tc = MesonToolchain(self)
        tc.project_options['libdir'] = 'lib'
        tc.project_options['build_extras'] = 'false'
        tc.generate()

    def build(self):
        meson = Meson(self)
        meson.configure()
        meson.build()

    def package(self):
        meson = Meson(self)
        meson.install()

    def package_info(self):
        self.cpp_info.set_property("pkg_config_name", self.name)

        libs = get_libs()
        self.cpp_info.libs = []
        if self.options.shared:
            self.cpp_info.libs = list(set(libs['shared'] + libs['both']))
        else:
            self.cpp_info.libs = list(set(libs['static'] + libs['both']))



if __name__ == '__main__':
    package = get_package()
    version = get_full_version(None)
    print(f'Detected package: {package}-{version}')

    repo = get_repo()
    print(f'Detected repo:    {repo}')

    author = get_author()
    print(f'Detected author:  {author}')

    libs = get_libs()
    print('Detected libs:')
    for key, value in libs.items():
        print(f'  {key}:')
        for v in value:
            print(f'    {v}')
back to top