diff --git a/.gitmodules b/.gitmodules index 003f7ce..7eb5b57 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "tests/submodules/knut"] path = tests/submodules/knut url = https://github.com/KDAB/knut.git +[submodule "tests/submodules/kdutils"] + path = tests/submodules/kdutils + url = https://github.com/KDAB/kdutils.git diff --git a/releasing.toml b/releasing.toml index b1db288..6d541c3 100644 --- a/releasing.toml +++ b/releasing.toml @@ -95,6 +95,24 @@ signed_release = false homebrew = ["kdutils.rb"] main_branch = "main" +[project.KDUtils.dependencies.KDBindings] +fetchcontent_path = "cmake/dependencies.cmake" + +[project.KDUtils.dependencies.fmt] +fetchcontent_path = "cmake/dependencies.cmake" + +[project.KDUtils.dependencies.spdlog] +fetchcontent_path = "cmake/dependencies.cmake" + +[project.KDUtils.dependencies.whereami] +fetchcontent_path = "cmake/dependencies.cmake" + +[project.KDUtils.dependencies.mio] +fetchcontent_path = "cmake/dependencies.cmake" + +[project.KDUtils.dependencies.doctest] +fetchcontent_path = "tests/CMakeLists.txt" + [project.Knut] has_version_txt = true diff --git a/src/gh_utils.py b/src/gh_utils.py index 1f3c1ae..bd3dab7 100755 --- a/src/gh_utils.py +++ b/src/gh_utils.py @@ -13,6 +13,7 @@ import argparse import uuid from utils import get_projects, repo_exists, run_command, run_command_with_output, run_command_silent, tag_for_version, get_project, get_submodule_builtin_dependencies +import utils from version_utils import is_numeric, previous_version, get_current_version_in_cmake from changelog_utils import get_changelog @@ -275,6 +276,30 @@ def checkout_randomly_named_branch(repo_path, prefix): return None +def get_current_fetchcontent_sha1s(repo_path, proj_name, dep_name=None): + ''' + Returns the current shas of our fetchcontent dependencies. + Example: + shas = gh_utils.get_current_fetchcontent_sha1s(kdutils_dir, 'KDUtils') + would return: [{'name': 'fmt', 'repo': 'https://github.com/fmtlib/fmt.git', 'sha1': 'e69e5f977d458f2650bb346dadf2ad30c5320281'}, (etc...) ] + ''' + + deps = utils.get_fetchcontent_builtin_dependencies(proj_name) + if not deps.items(): + return [] + + result = [] + for key, dep in deps.items(): + if dep_name and dep_name != key: + continue + + cmake_filename = repo_path + '/' + dep['fetchcontent_path'] + with open(cmake_filename, 'r', encoding='UTF-8') as file: + cmake_code = file.read() + result.extend(utils.get_fetchcontents_from_code(cmake_code)) + return result + + def get_submodule_versions(master_repo_path, proj_name, submodule_name=None): ''' returns the list of submodule current and latest versions for give project diff --git a/src/utils.py b/src/utils.py index bd0d821..13fe2f5 100644 --- a/src/utils.py +++ b/src/utils.py @@ -98,6 +98,15 @@ def get_submodule_builtin_dependencies(name): return {k: v for k, v in deps.items() if 'submodule_path' in v} +def get_fetchcontent_builtin_dependencies(name): + ''' + Like get_builtin_dependencies() but only honours fetchcontent, not submodules + ''' + + deps = get_builtin_dependencies(name) + return {k: v for k, v in deps.items() if 'fetchcontent_path' in v} + + def download_file_as_string(filename): ''' Downloads a file and returns it as a string @@ -131,3 +140,50 @@ def create_tarball_with_submodules(proj_name, sha1, version): run_command(f"git -C {clone_dir} submodule update --init --recursive") run_command( f"tar --exclude='.git' -C {temp_dir} -czvf {proj_name.lower()}-{version}.tar.gz {proj_name.lower()}-{version}") + + +def get_fetchcontents_from_code(cmake_code): + ''' + Parses code and returns 1 line per fetchcontents_declare + ''' + fetchcontents = [] + lines = cmake_code.split('\n') + for i, line in enumerate(lines): + if line.strip().startswith('#') or line.strip().startswith('//'): + continue + + if 'fetchcontent_declare' in line.lower(): + line = line.strip() + if line.endswith('\\') or line.count('(') > line.count(')'): + j = i + 1 + while j < len(lines): + if not lines[j].strip().startswith('#'): + line += ' ' + lines[j].strip() + if not lines[j].strip().endswith('\\') and line.count('(') == line.count(')'): + break + j += 1 + fetchcontents.append(line) + + # Each line is for example: + # 'FetchContent_Declare( fmt GIT_REPOSITORY https://github.com/fmtlib/fmt.git GIT_TAG e69e5f977d458f2650bb346dadf2ad30c5320281)' + result = [] + for line in fetchcontents: + parts = [s.strip() for s in line.split()] + + try: + name = parts[parts.index('GIT_REPOSITORY') - 1] + if '(' in name: + name = name.split('(')[1].strip(',') + repo = parts[parts.index('GIT_REPOSITORY') + + 1].strip(')').strip(',') + sha1 = parts[parts.index('GIT_TAG') + 1].strip(')') + + result.append({ + 'name': name, + 'repo': repo, + 'sha1': sha1 + }) + except (ValueError, IndexError): + continue + + return result diff --git a/tests/submodules/kdutils b/tests/submodules/kdutils new file mode 160000 index 0000000..444c8d2 --- /dev/null +++ b/tests/submodules/kdutils @@ -0,0 +1 @@ +Subproject commit 444c8d2369b4ea9e79a8712bdabfe073588fe382 diff --git a/tests/test_stuff.py b/tests/test_stuff.py index f47efeb..d2bbc2c 100644 --- a/tests/test_stuff.py +++ b/tests/test_stuff.py @@ -6,6 +6,7 @@ import os import version_utils import gh_utils +import utils def test_get_version_in_versiontxt(): @@ -33,10 +34,30 @@ def test_submodule_versions(): versions = gh_utils.get_submodule_versions(knut_dir, 'Knut') assert len(versions) == 9 expected = [{'submodule_name': 'extra_cmake_modules', 'submodule_path': '3rdparty/extra-cmake-modules', 'current_version': 'v5.110.0', 'latest_version': 'v6.10.0'}, {'submodule_name': 'kdalgorithms', 'submodule_path': '3rdparty/kdalgorithms', 'current_version': '1.2', 'latest_version': '1.4'}, {'submodule_name': 'ksyntaxhighlighting', 'submodule_path': '3rdparty/ksyntaxhighlighting', 'current_version': 'v5.110.0', 'latest_version': 'v6.9.0'}, {'submodule_name': 'nlohmann_json', 'submodule_path': '3rdparty/nlohmann-json', 'current_version': 'v3.11.2', 'latest_version': 'v3.11.3'}, {'submodule_name': 'pugixml', - 'submodule_path': '3rdparty/pugixml', 'current_version': 'v1.14', 'latest_version': 'latest'}, {'submodule_name': 'spdlog', 'submodule_path': '3rdparty/spdlog', 'current_version': 'v1.14.1', 'latest_version': 'v1.15.0'}, {'submodule_name': 'tree_sitter', 'submodule_path': '3rdparty/tree-sitter', 'current_version': 'v0.20.8', 'latest_version': 'v0.24.1'}, {'submodule_name': 'tree_sitter_cpp', 'submodule_path': '3rdparty/tree-sitter-cpp', 'current_version': 'v0.20.2', 'latest_version': 'v0.23.4'}, {'submodule_name': 'tree_sitter_qmljs', 'submodule_path': '3rdparty/tree-sitter-qmljs', 'current_version': '0.1.2', 'latest_version': '0.2.0'}] + 'submodule_path': '3rdparty/pugixml', 'current_version': 'v1.14', 'latest_version': 'latest'}, {'submodule_name': 'spdlog', 'submodule_path': '3rdparty/spdlog', 'current_version': 'v1.14.1', 'latest_version': 'v1.15.0'}, {'submodule_name': 'tree_sitter', 'submodule_path': '3rdparty/tree-sitter', 'current_version': 'v0.20.8', 'latest_version': 'v0.24.1'}, {'submodule_name': 'tree_sitter_cpp', 'submodule_path': '3rdparty/tree-sitter-cpp', 'current_version': 'v0.20.2', 'latest_version': 'v0.23.4'}, {'submodule_name': 'tree_sitter_qmljs', 'submodule_path': '3rdparty/tree-sitter-qmljs', 'current_version': '0.1.2', 'latest_version': '0.2.0'}] i = 0 for submodule in versions: # we can't compare latest_version, as that changes upstream assert submodule['current_version'] == expected[i]['current_version'] i += 1 + + +def test_fetchcontent_versions(): + ''' + Tests gh_utils.get_fetchcontent_versions() + We have kdutils as a submodule, do not bump it + ''' + + deps = utils.get_fetchcontent_builtin_dependencies('KDUtils') + assert deps == {'KDBindings': {'fetchcontent_path': 'cmake/dependencies.cmake'}, 'fmt': {'fetchcontent_path': 'cmake/dependencies.cmake'}, 'spdlog': {'fetchcontent_path': 'cmake/dependencies.cmake'}, + 'whereami': {'fetchcontent_path': 'cmake/dependencies.cmake'}, 'mio': {'fetchcontent_path': 'cmake/dependencies.cmake'}, 'doctest': {'fetchcontent_path': 'tests/CMakeLists.txt'}} + + script_dir = os.path.dirname(os.path.realpath(__file__)) + kdutils_dir = script_dir + '/submodules/kdutils/' + + versions = gh_utils.get_current_fetchcontent_sha1s(kdutils_dir, 'KDUtils') + print(versions) + + assert versions == [{'name': 'fmt', 'repo': 'https://github.com/fmtlib/fmt.git', 'sha1': 'e69e5f977d458f2650bb346dadf2ad30c5320281'}, {'name': 'spdlog', 'repo': 'https://github.com/gabime/spdlog.git', 'sha1': '27cb4c76708608465c413f6d0e6b8d99a4d84302'}, {'name': 'KDBindings', 'repo': 'https://github.com/KDAB/KDBindings.git', 'sha1': 'efb54c58c3c2fce280d7089617935ec265fe4e2d'}, {'name': 'whereami', 'repo': 'https://github.com/gpakosz/whereami', 'sha1': 'e4b7ba1be0e9fd60728acbdd418bc7195cdd37e7'}, {'name': 'mio', 'repo': 'https://github.com/mandreyel/mio.git', 'sha1': '8b6b7d878c89e81614d05edca7936de41ccdd2da'}, {'name': 'fmt', 'repo': 'https://github.com/fmtlib/fmt.git', 'sha1': 'e69e5f977d458f2650bb346dadf2ad30c5320281'}, {'name': 'spdlog', 'repo': 'https://github.com/gabime/spdlog.git', 'sha1': '27cb4c76708608465c413f6d0e6b8d99a4d84302'}, {'name': 'KDBindings', 'repo': 'https://github.com/KDAB/KDBindings.git', 'sha1': 'efb54c58c3c2fce280d7089617935ec265fe4e2d'}, {'name': 'whereami', 'repo': 'https://github.com/gpakosz/whereami', 'sha1': 'e4b7ba1be0e9fd60728acbdd418bc7195cdd37e7'}, {'name': 'mio', 'repo': 'https://github.com/mandreyel/mio.git', 'sha1': '8b6b7d878c89e81614d05edca7936de41ccdd2da'}, {'name': 'fmt', 'repo': 'https://github.com/fmtlib/fmt.git', 'sha1': 'e69e5f977d458f2650bb346dadf2ad30c5320281'}, {'name': 'spdlog', 'repo': 'https://github.com/gabime/spdlog.git', 'sha1': '27cb4c76708608465c413f6d0e6b8d99a4d84302'}, {'name': 'KDBindings', 'repo': 'https://github.com/KDAB/KDBindings.git', 'sha1': 'efb54c58c3c2fce280d7089617935ec265fe4e2d'}, + {'name': 'whereami', 'repo': 'https://github.com/gpakosz/whereami', 'sha1': 'e4b7ba1be0e9fd60728acbdd418bc7195cdd37e7'}, {'name': 'mio', 'repo': 'https://github.com/mandreyel/mio.git', 'sha1': '8b6b7d878c89e81614d05edca7936de41ccdd2da'}, {'name': 'fmt', 'repo': 'https://github.com/fmtlib/fmt.git', 'sha1': 'e69e5f977d458f2650bb346dadf2ad30c5320281'}, {'name': 'spdlog', 'repo': 'https://github.com/gabime/spdlog.git', 'sha1': '27cb4c76708608465c413f6d0e6b8d99a4d84302'}, {'name': 'KDBindings', 'repo': 'https://github.com/KDAB/KDBindings.git', 'sha1': 'efb54c58c3c2fce280d7089617935ec265fe4e2d'}, {'name': 'whereami', 'repo': 'https://github.com/gpakosz/whereami', 'sha1': 'e4b7ba1be0e9fd60728acbdd418bc7195cdd37e7'}, {'name': 'mio', 'repo': 'https://github.com/mandreyel/mio.git', 'sha1': '8b6b7d878c89e81614d05edca7936de41ccdd2da'}, {'name': 'fmt', 'repo': 'https://github.com/fmtlib/fmt.git', 'sha1': 'e69e5f977d458f2650bb346dadf2ad30c5320281'}, {'name': 'spdlog', 'repo': 'https://github.com/gabime/spdlog.git', 'sha1': '27cb4c76708608465c413f6d0e6b8d99a4d84302'}, {'name': 'KDBindings', 'repo': 'https://github.com/KDAB/KDBindings.git', 'sha1': 'efb54c58c3c2fce280d7089617935ec265fe4e2d'}, {'name': 'whereami', 'repo': 'https://github.com/gpakosz/whereami', 'sha1': 'e4b7ba1be0e9fd60728acbdd418bc7195cdd37e7'}, {'name': 'mio', 'repo': 'https://github.com/mandreyel/mio.git', 'sha1': '8b6b7d878c89e81614d05edca7936de41ccdd2da'}, {'name': 'doctest', 'repo': 'https://github.com/doctest/doctest.git', 'sha1': 'v2.4.9'}]