summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIikka Eklund <iikka.eklund@qt.io>2021-08-10 10:02:55 +0300
committerIikka Eklund <iikka.eklund@qt.io>2021-08-23 12:08:12 +0000
commitbb28fd84f30c20b4cb17a4683bd1aa390676f784 (patch)
treeaaa505050b35502866ffa00c46e7822d120b8581
parent45f3a86bc2868ee3a5d3f4f262543ac9d4435215 (diff)
Implement common base class for Qt leaf module recipes
Currently it looks that all the leaf module recipes are nearly identical so it makes sense to implement that logic in a base class. The base class is able to parse and declare the dependencies based on the information in the module's 'dependencies.yaml' file. Related unit tests added. One abstract method in the base class is needed for customization: - override_qt_requirements() - Sometimes it may be that the 'dependencies.yaml' does not provive correct Conan package requirements as that file maps to .git repo name granularity. We have Qt .git repos that will yield multiple Conan packages, e.g. qtscxml.git -> qtscxml, qtscxmlqml, qtstatemachine and qtstatemachineqml Task-number: QTQAINFRA-4519 Change-Id: I1a53226a3d54cdf9be9ee6f83263dd61bedbae27 Reviewed-by: Ievgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io> Reviewed-by: Toni Saario <toni.saario@qt.io>
-rw-r--r--conanfile.py98
-rw-r--r--test/__init__.py0
-rw-r--r--test/data/qt3d/dependencies.yaml10
-rw-r--r--test/data/qtbase/dependencies.yaml1
-rw-r--r--test/data/qtwebengine/dependencies.yaml16
-rw-r--r--test/test_conanfile.py51
6 files changed, 173 insertions, 3 deletions
diff --git a/conanfile.py b/conanfile.py
index 8e9e570..2f635f3 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -27,8 +27,11 @@
#############################################################################
from conans import ConanFile, tools
+from abc import ABCMeta, abstractmethod
import os
import re
+import yaml
+from functools import lru_cache
from pathlib import Path
from typing import List, Dict, Optional, Tuple, Callable
@@ -113,10 +116,99 @@ def package_info(conan_file: ConanFile):
setattr(conan_file.env_info, str(item.name) + "_DIR", str(item))
+@lru_cache(maxsize=8)
+def parse_qt_version_by_key(source_folder: Path, key: str) -> str:
+ with open(source_folder / ".cmake.conf") as f:
+ m = re.search(fr'{key} .*"(.*)"', f.read())
+ return m.group(1) if m else ""
+
+
+def parse_module_dependencies(source_folder: Path) -> List[str]:
+ with open(source_folder / "dependencies.yaml") as f:
+ dep_list = yaml.load(f, Loader=yaml.FullLoader)
+ return [d.split("/")[-1] for d in dep_list.get('dependencies', {}).keys()]
+
+
+class QtLeafModule(metaclass=ABCMeta):
+ """
+ A base class for leaf Qt module Conan recipes.
+
+ As most of the leaf modules are identical what comes to build steps those are implemented here
+ and the leaf classes can be extended with this.
+ """
+
+ revision_mode = "scm"
+
+ def set_version(self):
+ src_dir = Path(self.recipe_folder).resolve()
+ ver = parse_qt_version_by_key(src_dir, "QT_REPO_MODULE_VERSION")
+ prerelease = parse_qt_version_by_key(src_dir, "QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT")
+ self.version = ver + "-" + prerelease if prerelease else ver
+
+ def requirements(self):
+ src_dir = Path(self.recipe_folder).resolve()
+ ver = parse_qt_version_by_key(src_dir, "QT_REPO_MODULE_VERSION")
+ # check if the inheriting leaf module recipe wants to override requirements
+ # in 'dependencies.yaml'
+ requirements = self.override_qt_requirements()
+ if not requirements:
+ # if not then parse the requirements from the 'dependencies.yaml'
+ requirements = parse_module_dependencies(src_dir)
+ # all the Qt Conan packages follow the same versioning schema
+ for dep in requirements:
+ # will match latest prerelase of final major.minor.patch
+ self.requires(f"{dep}/[<={ver}, include_prerelease=True]@{self.user}/{self.channel}")
+
+ @abstractmethod
+ def override_qt_requirements(self) -> List[str]:
+ """
+ If the Qt leaf module requirements (dependencies) does not match the Qt's .git
+ repository naming then implement this method in the leaf module recipe class.
+ E.g. .
+
+ Example:
+ qtscxml.git -> qtscxml/<ver>@qt/everywhere, qtscxmlqml/, qtstatemachine/,
+ qtstatemachineqml/
+
+ qtfoo.git:
+ dependencies.yaml:
+ qtscxml # Note! Here the dep is using repo name granularity,
+ # not Conan package name!
+
+ If the qtfoo requires (depends) qtstatemachine Conan package in reality
+ (produced from qtscxml.git) it would not get that dependency but it would
+ get the qtscxml/<ver>@qt/everywhere instead, which is wrong. So the qtfoo
+ recipe needs to implement this method and return ['qtbase', 'qtscxml'].
+ """
+ return []
+
+ def build(self):
+ build_leaf_qt_module(self)
+
+ def package(self):
+ cmd = ["cmake", "--install", "."]
+ self.run(" ".join(cmd))
+
+ def package_info(self):
+ package_info(self)
+
+ def package_id(self):
+ self.info.requires.package_revision_mode()
+
+ def deploy(self):
+ self.copy("*") # copy from current package
+ if not os.environ.get("QT_CONAN_INSTALL_SKIP_DEPS"):
+ self.copy_deps("*") # copy from dependencies
+
+
class QtConanCommon(ConanFile):
name = "qt-conan-common"
- version = "6.2"
license = "LGPL-3.0+, GPL-2.0+, Commercial Qt License Agreement"
url = "https://www.qt.io"
- description = "Shared utilities for Qt recipies"
- revision_mode = "scm" if Path(Path(__file__).parent.resolve() / ".git").exists() else "hash"
+ description = "Shared functionality for Qt Conan package recipes"
+ revision_mode = "scm"
+
+ def set_version(self):
+ path = Path(__file__).parent.resolve()
+ full_version = parse_qt_version_by_key(path, "QT_REPO_MODULE_VERSION")
+ self.version = ".".join(full_version.split(".")[:2])
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/__init__.py
diff --git a/test/data/qt3d/dependencies.yaml b/test/data/qt3d/dependencies.yaml
new file mode 100644
index 0000000..23649de
--- /dev/null
+++ b/test/data/qt3d/dependencies.yaml
@@ -0,0 +1,10 @@
+dependencies:
+ ../qtbase:
+ ref: 2b2b3155d9f6ba1e4f859741468fbc47db09292b
+ required: true
+ ../qtdeclarative:
+ ref: 5a325943536721f4117576390c29807d930be3a1
+ required: false
+ ../qtshadertools:
+ ref: 7da9d5145f963137a53109f5ce7ba0ee79e47458
+ required: false
diff --git a/test/data/qtbase/dependencies.yaml b/test/data/qtbase/dependencies.yaml
new file mode 100644
index 0000000..c093387
--- /dev/null
+++ b/test/data/qtbase/dependencies.yaml
@@ -0,0 +1 @@
+dependencies: {}
diff --git a/test/data/qtwebengine/dependencies.yaml b/test/data/qtwebengine/dependencies.yaml
new file mode 100644
index 0000000..05c7784
--- /dev/null
+++ b/test/data/qtwebengine/dependencies.yaml
@@ -0,0 +1,16 @@
+dependencies:
+ ../qtdeclarative:
+ ref: 6c01e17a30531fcaeb44459978d6ba8a56aa225a
+ required: true
+ ../qtlocation:
+ ref: f14492bf1b161b2bce043c9284c151b52c5e2c17
+ required: false
+ ../qtquickcontrols2:
+ ref: 40e92d86a7601b06a83c5cbc44c85847d1cb46f7
+ required: false
+ ../qttools:
+ ref: a586947ecf6c70c362e1fadd601090dc3e069bb2
+ required: false
+ ../qtwebchannel:
+ ref: 1a07a2d364269dc6e140616cf0ec215549faf032
+ required: false
diff --git a/test/test_conanfile.py b/test/test_conanfile.py
new file mode 100644
index 0000000..c93c8a9
--- /dev/null
+++ b/test/test_conanfile.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the release tools of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+import unittest
+from ddt import ddt, data
+from pathlib import Path
+from conanfile import parse_module_dependencies
+
+
+@ddt
+class TestConanFile(unittest.TestCase):
+
+ @data(("data/qtwebengine", ["qtdeclarative", "qtlocation", "qtquickcontrols2", "qttools", "qtwebchannel"]),
+ ("data/qt3d", ["qtbase", "qtdeclarative", "qtshadertools"]),
+ ("data/qtbase", []))
+ def test_parse_module_dependencies(self, data: str) -> None:
+ test_data_path, expected_result = data
+ tmp = Path(Path(__file__).parent / test_data_path).resolve()
+ self.assertEqual(set(parse_module_dependencies(tmp)), set(expected_result))
+
+
+
+if __name__ == '__main__':
+ unittest.main()