From 61973a3e2253f3451fd3b30d625d58483f1fb969 Mon Sep 17 00:00:00 2001 From: William Douglas Date: Fri, 15 Mar 2024 13:38:04 -0700 Subject: [PATCH] Add handling for multiline find_package Previously support for cmake's find_package parsing was only able to handle single line entries. This change adds support for multiline versions and allows for module namespacing (currently qt6 and kf6 support is available). The change for cmake_modules shows this namespacing in use. Signed-off-by: William Douglas --- autospec/buildreq.py | 26 +++++++++++++++++++++++++- autospec/cmake_modules | 18 +++++++++++++++++- tests/test_buildreq.py | 27 ++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/autospec/buildreq.py b/autospec/buildreq.py index 719ea673..a7c35596 100644 --- a/autospec/buildreq.py +++ b/autospec/buildreq.py @@ -483,21 +483,45 @@ def parse_r_description(self, filename, packages): def set_build_req(self, config): """Add build requirements based on the build pattern.""" + def findpackage_parse_lines(self, fp_line, line_iter, cmake_modules): + """Parse find_package multiline segment of the line_iter.""" + qt6module = re.compile(r"^[^#]*find_package\(\s*\bQt6.*", re.I) + kf6module = re.compile(r"^[^#]*find_package\(\s*\bKF6.*", re.I) + ns = '' + if qt6module.search(fp_line): + ns = 'qt6' + elif kf6module.search(fp_line): + ns = 'kf6' + while True: + ln = next(line_iter).strip() + if not ln: + continue + modules = ln.strip(')').split(' ') + for module in modules: + if module: + if pkg := cmake_modules.get(f"{ns}.{module}"): + self.add_buildreq(pkg) + if ')' in ln: + break + def parse_cmake(self, filename, cmake_modules, conf32): """Scan a .cmake or CMakeLists.txt file for what's it's actually looking for.""" findpackage = re.compile(r"^[^#]*find_package\((\w+)\b.*\)", re.I) + findpackage_multiline = re.compile(r"^[^#]*find_package\((\w+)\b.*", re.I) pkgconfig = re.compile(r"^[^#]*pkg_check_modules\s*\(\w+ (.*)\)", re.I) pkg_search_modifiers = {'REQUIRED', 'QUIET', 'NO_CMAKE_PATH', 'NO_CMAKE_ENVIRONMENT_PATH', 'IMPORTED_TARGET'} extractword = re.compile(r'(?:"([^"]+)"|(\S+))(.*)') with util.open_auto(filename, "r") as f: - lines = f.readlines() + lines = iter(f.readlines()) for line in lines: if match := findpackage.search(line): module = match.group(1) if pkg := cmake_modules.get(module): self.add_buildreq(pkg) + elif findpackage_multiline.search(line): + self.findpackage_parse_lines(line, lines, cmake_modules) if match := pkgconfig.search(line): rest = match.group(1) diff --git a/autospec/cmake_modules b/autospec/cmake_modules index dea9aa2e..4830c1d8 100644 --- a/autospec/cmake_modules +++ b/autospec/cmake_modules @@ -346,7 +346,7 @@ Python3, python3-dev PythonInterp, python3 PythonLibs, python3-dev QGpgme, gpgme-dev gpgme-extras -QHelpGenerator, extra-cmake-modules qttools-dev +QHelpGenerator, extra-cmake-modules qt6tools-dev QMobipocket, kdegraphics-mobipocket-dev Qca-qt5, qca-qt5-dev Qt3DTests, qt6base-dev @@ -901,6 +901,19 @@ igsc, igsc-dev json-c, json-c-dev kColorPicker, kcolorpicker-dev kImageAnnotator, kimageannotator-dev +kf6.KIO, kio-dev +kf6.I18n, ki18n-dev +kf6.CoreAddons, kcoreaddons-dev +kf6.Config, kconfig-dev +kf6.Crash, kcrash-dev +kf6.DBusAddons, kdbusaddons-dev +kf6.Notifications, knotifications-dev +kf6.Runner, krunner-dev +kf6.Purpose, purpose-dev +kf6.FileMetaData, kfilemetadata-dev +kf6.JobWidgets, kjobwidgets-dev +kf6.Service, kservice-dev +kf6.StatusNotifierItem, kstatusnotifieritem-dev kim-api, kim-api-data leveldb, leveldb-dev libavif, libavif-dev @@ -926,6 +939,9 @@ pugixml, pugixml-dev pybind11, pypi(pybind11) qt5xdg, libqtxdg-data qt5xdgiconloader, libqtxdg-data +qt6.Gui, qt6base-dev +qt6.DBus, qt6base-dev +qt6.Widgets, qt6base-dev qtxdg-tools, qtxdg-tools-data rabbitmq-c, rabbitmq-c-dev realsense2, librealsense-dev diff --git a/tests/test_buildreq.py b/tests/test_buildreq.py index 016e7cb0..cde781cb 100644 --- a/tests/test_buildreq.py +++ b/tests/test_buildreq.py @@ -621,12 +621,30 @@ def test_parse_cmake_find_package(self): "valid": "valid", "valid_but_commented": "valid_but_commented", "different_name": "another_name", + "qt6.module1": "qt6module1", + "qt6.module2": "qt6module2", + "kf6.module3": "kf6module3", + "kf6.module4": "kf6module4", + ".module5": "namodule5", + ".module6": "namodule6" } content = ''' find_package(valid) #find_package(foo) # find_package(valid_but_commented) find_package(different_name) +find_package(Qt6 stuff +module1 +module2) +find_package(KF6 stuff +module3 +module4 +) +find_package(NOT_HANDLED_NAMESPACE stuff +module5 + +module6 +) ''' with tempfile.TemporaryDirectory() as tmpd: with open(os.path.join(tmpd, 'fname'), 'w') as f: @@ -634,7 +652,14 @@ def test_parse_cmake_find_package(self): self.reqs.parse_cmake(os.path.join(tmpd, 'fname'), cmake_modules, False) self.assertEqual(self.reqs.buildreqs, - set(['valid', 'another_name'])) + set(['valid', + 'another_name', + 'qt6module1', + 'qt6module2', + 'kf6module3', + 'kf6module4', + 'namodule5', + 'namodule6'])) def test_r_desc_field_begin(self): """Test parsing of the first R description field."""