diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..0e79fd7eb --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,45 @@ +name: 'tests' + +on: + pull_request: + paths: + - '.github/workflows/tests.yml' + - '**.spec' + - '**CMakeLists.txt' + - 'contrib/test-spec-bconds.py' + # allow manual execution from the GitHub web interface + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + spec-bconds: + name: Test rebuilding spec with different --with bconds + runs-on: ubuntu-latest + container: + image: fedora:rawhide + steps: + - name: Install packages + run: | + dnf -y install ccache dnf-plugins-core git rpm-build + + - name: Create ccache symlinks to prioritize it over gcc + run: | + ln -s /usr/bin/ccache /usr/local/bin/gcc + ln -s /usr/bin/ccache /usr/local/bin/g++ + ln -s /usr/bin/ccache /usr/local/bin/cc + ln -s /usr/bin/ccache /usr/local/bin/c++ + + - name: Checkout sources + run: | + git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY dnf5-pr + cd dnf5-pr + git fetch origin $GITHUB_REF:branch-pr + git switch branch-pr + + - name: Run tests + run: | + cd dnf5-pr/contrib + ./test-spec-bconds.py diff --git a/CMakeLists.txt b/CMakeLists.txt index abbe69bdf..f210a0896 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ option(WITH_PYTHON_PLUGINS_LOADER "Build a special dnf5 plugin that loads Python # build options - features option(WITH_COMPS "Build with comps groups and environments support" ON) option(WITH_MODULEMD "Build with modulemd modules support" ON) +option(WITH_STATIC_LIBSOLV "Link with dependencies of static libsolv" OFF) option(WITH_ZCHUNK "Build with zchunk delta compression support" ON) # build options - documentation diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index 814d00767..45db1ac1c 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -29,7 +29,7 @@ set(SWIG_COMPILE_OPTIONS -Wno-missing-declarations -Wno-missing-field-initializers -Wno-sign-compare - -Wno-sometimes-uninitialized +# -Wno-sometimes-uninitialized -Wno-strict-aliasing -Wno-unused-function -Wno-unused-parameter diff --git a/contrib/test-spec-bconds.py b/contrib/test-spec-bconds.py new file mode 100755 index 000000000..a68e7ae40 --- /dev/null +++ b/contrib/test-spec-bconds.py @@ -0,0 +1,169 @@ +#!/usr/bin/python3 + + +import os +import subprocess +import sys + + +FLAGS = { + "comps": {}, + "dnf5": { + "with": ["libdnf-cli"], + }, + "dnf5_plugins": {}, + "dnf5daemon_client": { + "with": ["libdnf-cli"], + }, + "dnf5daemon_server": { + "with": ["libdnf-cli"], + }, + "dnf5daemon_tests": {}, + "html": {}, + # "libdnf_cli": {}, + "modulemd": {}, + "perl5": {}, + "plugin_actions": {}, + "python3": {}, + "python_plugins_loader": { + # requires python3 + "with": ["python3"], + }, + "ruby": {}, + "static_libsolv": {}, + "zchunk": {}, +} + + +FLAGS_ALWAYS_WITH = [ + "libdnf_cli", + "tests", +] + + +FLAGS_ALWAYS_WITHOUT = [ + # we don't care about a different compiler now + "clang", + + # broken option + "go", + + # man pages require nearly all other options on + "man", + + # we don't care about performance tests now + "performance_tests", + + # we don't care about code sanity now + "sanitizers", +] + + +TOPDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +SPEC = os.path.abspath(os.path.join(TOPDIR, "dnf5.spec")) + + +def get_name_version(): + cmd = ["rpmspec", "-q", SPEC, "--srpm", "--qf", "%{name}-%{version}"] + return subprocess.check_output(cmd, encoding="utf-8").strip() + + +def git_archive(): + """ + Create a tarball named exactly as the tarball from the spec, + so we don't have to modify the spec at all. + """ + nv = get_name_version() + archive_path = f"{TOPDIR}/{nv}.tar.gz" + cmd = [ + "git", "archive", + "--prefix", f"{nv}/", + "--output", archive_path, + "HEAD" + ] + subprocess.run(cmd, check=True, cwd=TOPDIR) + print(f"Created archive {archive_path}") + + +def install_build_deps(): + cmd = ["dnf", "-y", "builddep", SPEC] + + flags = [] + flags += list(FLAGS) + flags += list(FLAGS_ALWAYS_WITH) + for data in FLAGS.values(): + flags += data.get("with", []) + + for flag in flags: + cmd += ["--define", f"_with_{flag} 1"] + + subprocess.run(cmd, check=True) + + +def build(with_flag): + data = FLAGS[with_flag] + + cmd = ["rpmbuild", "--ba", SPEC] + cmd += [ + # use tarball from git_archive()'s target location + "--define", f"_sourcedir {TOPDIR}", + # speedup: disable compression + "--define", "_source_payload w.ufdio", + "--define", "_binary_payload w.ufdio", + # speedup: disable debuginfo + "--define", "debug_package %{nil}", + ] + + # enable the current flag + cmd += ["--with", with_flag] + + # disable the other flags + for without_flag in FLAGS: + if without_flag == with_flag: + continue + + # enable deps instead of disabling + deps_with = data.get("with", []) + if without_flag in deps_with: + cmd += ["--with", without_flag] + continue + + cmd += ["--without", without_flag] + + # enable the flags that should be always on + for always_with_flag in FLAGS_ALWAYS_WITH: + cmd += ["--with", always_with_flag] + + # disable the flags that should be always off + for always_without_flag in FLAGS_ALWAYS_WITHOUT: + cmd += ["--without", always_without_flag] + + print(10 * "\n") + print(f"Building with flag '{with_flag}'...") + print("Running command:", cmd) + try: + subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + print(f"Error: Failed to build with flag '{with_flag}'") + return False + return True + + +def main(): + git_archive() + install_build_deps() + + errors = [] + for flag in FLAGS: + success = build(flag) + if not success: + errors.append(flag) + + if errors: + print(10 * "\n") + print("Error: The following flags failed to build:", errors) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/dnf5.spec b/dnf5.spec index 67fc2fb8d..2880d18fc 100644 --- a/dnf5.spec +++ b/dnf5.spec @@ -35,6 +35,12 @@ Obsoletes: microdnf < 4 %bcond_without modulemd %bcond_without zchunk +%if 0%{?is_opensuse} +%bcond_without static_libsolv +%else +%bcond_with static_libsolv +%endif + %bcond_with html %if 0%{?rhel} == 8 %bcond_with man @@ -84,6 +90,13 @@ BuildRequires: pkgconfig(rpm) >= 4.17.0 BuildRequires: pkgconfig(sqlite3) BuildRequires: toml11-static +%if %{with static_libsolv} +BuildRequires: pkgconfig(bzip2) +BuildRequires: pkgconfig(liblzma) +BuildRequires: pkgconfig(zlib) +BuildRequires: pkgconfig(libzstd) +%endif + %if %{with clang} BuildRequires: clang %else @@ -175,6 +188,7 @@ DNF5 is a command-line package manager that automates the process of installing, upgrading, configuring, and removing computer programs in a consistent manner. It supports RPM packages, modulemd modules, and comps groups & environments. +%if %{with dnf5} %files %{_bindir}/dnf5 @@ -191,7 +205,6 @@ It supports RPM packages, modulemd modules, and comps groups & environments. %dir %{_libdir}/dnf5 %dir %{_libdir}/dnf5/plugins %doc %{_libdir}/dnf5/plugins/README -%dir %{_libdir}/libdnf5/plugins %dir %{_datadir}/bash-completion/ %dir %{_datadir}/bash-completion/completions/ %{_datadir}/bash-completion/completions/dnf5 @@ -199,6 +212,7 @@ It supports RPM packages, modulemd modules, and comps groups & environments. %verify(not md5 size mtime) %ghost %{_prefix}/lib/sysimage/dnf/* %license COPYING.md %license gpl-2.0.txt +%if %{with man} %{_mandir}/man8/dnf5.8.* %{_mandir}/man8/dnf5-advisory.8.* %{_mandir}/man8/dnf5-clean.8.* @@ -228,6 +242,9 @@ It supports RPM packages, modulemd modules, and comps groups & environments. # TODO(jkolarik): modularity is not ready yet # %%{_mandir}/man7/dnf5-modularity.7.* %{_mandir}/man7/dnf5-specs.7.* +%endif +# with dnf5 +%endif # ========== libdnf5 ========== %package -n libdnf5 @@ -242,6 +259,7 @@ Package management library. %files -n libdnf5 %dir %{_libdir}/libdnf5 +%dir %{_libdir}/libdnf5/plugins %{_libdir}/libdnf5.so.1* %license lgpl-2.1.txt %{_var}/cache/libdnf/ @@ -265,6 +283,8 @@ Library for working with a terminal in a command-line package manager. # ========== dnf5-devel ========== +%if %{with dnf5} + %package -n dnf5-devel Summary: Development files for dnf5 License: LGPL-2.1-or-later @@ -280,6 +300,9 @@ Develpment files for dnf5. %license COPYING.md %license lgpl-2.1.txt +# with dnf5 +%endif + # ========== libdnf5-devel ========== @@ -490,8 +513,10 @@ Command-line interface for dnf5daemon-server. %{_bindir}/dnf5daemon-client %license COPYING.md %license gpl-2.0.txt +%if %{with man} %{_mandir}/man8/dnf5daemon-client.8.* %endif +%endif # ========== dnf5daemon-server ========== @@ -527,9 +552,11 @@ Package management service with a DBus interface. %{_datadir}/polkit-1/actions/org.rpm.dnf.v0.policy %license COPYING.md %license gpl-2.0.txt +%if %{with man} %{_mandir}/man8/dnf5daemon-server.8.* %{_mandir}/man8/dnf5daemon-dbus-api.8.* %endif +%endif # ========== dnf5-plugins ========== @@ -563,11 +590,13 @@ Core DNF5 plugins that enhance dnf5 with builddep and changelog commands. -DWITH_DNF5DAEMON_SERVER=%{?with_dnf5daemon_server:ON}%{!?with_dnf5daemon_server:OFF} \ -DWITH_LIBDNF5_CLI=%{?with_libdnf_cli:ON}%{!?with_libdnf_cli:OFF} \ -DWITH_DNF5=%{?with_dnf5:ON}%{!?with_dnf5:OFF} \ + -DWITH_DNF5_PLUGINS=%{?with_dnf5_plugins:ON}%{!?with_dnf5_plugins:OFF} \ -DWITH_PLUGIN_ACTIONS=%{?with_plugin_actions:ON}%{!?with_plugin_actions:OFF} \ -DWITH_PYTHON_PLUGINS_LOADER=%{?with_python_plugins_loader:ON}%{!?with_python_plugins_loader:OFF} \ \ -DWITH_COMPS=%{?with_comps:ON}%{!?with_comps:OFF} \ -DWITH_MODULEMD=%{?with_modulemd:ON}%{!?with_modulemd:OFF} \ + -DWITH_STATIC_LIBSOLV=%{?with_static_libsolv:ON}%{!?with_static_libsolv:OFF} \ -DWITH_ZCHUNK=%{?with_zchunk:ON}%{!?with_zchunk:OFF} \ \ -DWITH_HTML=%{?with_html:ON}%{!?with_html:OFF} \ @@ -601,6 +630,9 @@ Core DNF5 plugins that enhance dnf5 with builddep and changelog commands. %install %cmake_install +install -d %{buildroot}/%{_libdir}/libdnf5/plugins + +%if %{with dnf5} # own dirs and files that dnf5 creates on runtime mkdir -p %{buildroot}%{_prefix}/lib/sysimage/dnf for files in \ @@ -611,11 +643,13 @@ for files in \ do touch %{buildroot}%{_prefix}/lib/sysimage/dnf/$files done +# with dnf5 +%endif #find_lang {name} # Remove if condition when Fedora 37 is EOL -%if 0%{?fedora} > 37 +%if %{with dnf5} && 0%{?fedora} > 37 ln -sr %{buildroot}%{_bindir}/dnf5 %{buildroot}%{_bindir}/microdnf %endif diff --git a/dnf5/CMakeLists.txt b/dnf5/CMakeLists.txt index 06bc18d77..199c64ea2 100644 --- a/dnf5/CMakeLists.txt +++ b/dnf5/CMakeLists.txt @@ -41,7 +41,9 @@ else() endif() install(FILES bash-completion/dnf5 DESTINATION ${BASH_COMPLETION_COMPLETIONSDIR}) -install(FILES "README.plugins" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/dnf5/plugins" RENAME "README") +if(WITH_DNF5_PLUGINS) + install(FILES "README.plugins" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/dnf5/plugins" RENAME "README") +endif() install(DIRECTORY "config/usr/" DESTINATION "${CMAKE_INSTALL_PREFIX}") install(DIRECTORY "config/etc/" DESTINATION "${CMAKE_INSTALL_FULL_SYSCONFDIR}") diff --git a/libdnf/CMakeLists.txt b/libdnf/CMakeLists.txt index 147327743..8bfd4d8ad 100644 --- a/libdnf/CMakeLists.txt +++ b/libdnf/CMakeLists.txt @@ -63,17 +63,35 @@ pkg_check_modules(LIBSOLVEXT REQUIRED libsolvext>=0.7.7) list(APPEND LIBDNF5_PC_REQUIRES_PRIVATE "${LIBSOLVEXT_MODULE_NAME}") target_link_libraries(libdnf ${LIBSOLVEXT_LIBRARIES}) -pkg_check_modules(RPM REQUIRED rpm>=4.17.0) -list(APPEND LIBDNF5_PC_REQUIRES "${RPM_MODULE_NAME}") -target_link_libraries(libdnf ${RPM_LIBRARIES}) +if(WITH_STATIC_LIBSOLV) + pkg_check_modules(BZIP2 REQUIRED bzip2) + list(APPEND LIBDNF5_PC_REQUIRES_PRIVATE "${BZIP2_MODULE_NAME}") + target_link_libraries(libdnf ${BZIP2_LIBRARIES}) + + pkg_check_modules(LZMA REQUIRED liblzma) + list(APPEND LIBDNF5_PC_REQUIRES_PRIVATE "${LZMA_MODULE_NAME}") + target_link_libraries(libdnf ${LZMA_LIBRARIES}) + + pkg_check_modules(ZLIB REQUIRED zlib) + list(APPEND LIBDNF5_PC_REQUIRES_PRIVATE "${ZLIB_MODULE_NAME}") + target_link_libraries(libdnf ${ZLIB_LIBRARIES}) + + pkg_check_modules(ZSTD REQUIRED libzstd) + list(APPEND LIBDNF5_PC_REQUIRES_PRIVATE "${ZSTD_MODULE_NAME}") + target_link_libraries(libdnf ${ZSTD_LIBRARIES}) +endif() -if(WITH_COMPS) +if(WITH_COMPS OR WITH_STATIC_LIBSOLV) pkg_check_modules(LIBXML2 REQUIRED libxml-2.0) list(APPEND LIBDNF5_PC_REQUIRES_PRIVATE "${LIBXML2_MODULE_NAME}") include_directories(${LIBXML2_INCLUDE_DIRS}) target_link_libraries(libdnf ${LIBXML2_LIBRARIES}) endif() +pkg_check_modules(RPM REQUIRED rpm>=4.17.0) +list(APPEND LIBDNF5_PC_REQUIRES "${RPM_MODULE_NAME}") +target_link_libraries(libdnf ${RPM_LIBRARIES}) + if (WITH_ZCHUNK) pkg_check_modules(ZCHUNKLIB zck>=0.9.11 REQUIRED) add_definitions(-DWITH_ZCHUNK)