diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:32:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:32:49 +0000 |
commit | 8053187731ae8e3eb368d8360989cf5fd6eed9f7 (patch) | |
tree | 32bada84ff5d7460cdf3934fcbdbe770d6afe4cd /ci | |
parent | Initial commit. (diff) | |
download | rnp-8053187731ae8e3eb368d8360989cf5fd6eed9f7.tar.xz rnp-8053187731ae8e3eb368d8360989cf5fd6eed9f7.zip |
Adding upstream version 0.17.0.upstream/0.17.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ci')
-rw-r--r-- | ci/botan-modules | 45 | ||||
-rwxr-xr-x | ci/build_package_rpm.sh | 100 | ||||
-rw-r--r-- | ci/docker/Makefile | 11 | ||||
-rw-r--r-- | ci/docker/fedora35.Dockerfile | 52 | ||||
-rwxr-xr-x | ci/docker/fedora35.test-locally | 22 | ||||
-rw-r--r-- | ci/env-common.inc.sh | 29 | ||||
-rw-r--r-- | ci/env-freebsd.inc.sh | 8 | ||||
-rw-r--r-- | ci/env-linux.inc.sh | 46 | ||||
-rw-r--r-- | ci/env.inc.sh | 29 | ||||
-rw-r--r-- | ci/gha/setup-env.inc.sh | 60 | ||||
-rwxr-xr-x | ci/install.sh | 7 | ||||
-rwxr-xr-x | ci/install_cacheable_dependencies.sh | 7 | ||||
-rwxr-xr-x | ci/install_noncacheable_dependencies.sh | 8 | ||||
-rw-r--r-- | ci/lib/cacheable_install_functions.inc.sh | 242 | ||||
-rw-r--r-- | ci/lib/install_functions.inc.sh | 869 | ||||
-rwxr-xr-x | ci/local.sh | 16 | ||||
-rwxr-xr-x | ci/main.sh | 109 | ||||
-rwxr-xr-x | ci/run.sh | 5 | ||||
-rwxr-xr-x | ci/style-check.sh | 14 | ||||
-rwxr-xr-x | ci/success.sh | 16 | ||||
-rwxr-xr-x | ci/tests/ci-tests.sh | 144 | ||||
-rwxr-xr-x | ci/tests/deb-tests.sh | 102 | ||||
-rwxr-xr-x | ci/tests/pk-tests.sh | 144 | ||||
-rwxr-xr-x | ci/tests/pkg-tests.sh | 102 | ||||
-rwxr-xr-x | ci/tests/rpm-tests.sh | 126 | ||||
-rw-r--r-- | ci/utils.inc.sh | 43 |
26 files changed, 2356 insertions, 0 deletions
diff --git a/ci/botan-modules b/ci/botan-modules new file mode 100644 index 0000000..626e0fe --- /dev/null +++ b/ci/botan-modules @@ -0,0 +1,45 @@ +aead +aes +auto_rng +bigint +blowfish +camellia +cast128 +cbc +cfb +crc24 +curve25519 +des +dl_algo +dl_group +dsa +eax +ecc_key +ecdh +ecdsa +ed25519 +elgamal +eme_pkcs1 +emsa_pkcs1 +emsa_raw +ffi +hash +hmac +hmac_drbg +idea +kdf +md5 +ocb +pgp_s2k +rfc3394 +rmd160 +rsa +sha1 +sha2_32 +sha2_64 +sha3 +sm2 +sm3 +sm4 +sp800_56a +twofish diff --git a/ci/build_package_rpm.sh b/ci/build_package_rpm.sh new file mode 100755 index 0000000..645bf5d --- /dev/null +++ b/ci/build_package_rpm.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1091 +set -euxo pipefail + +: "${BUILD_SHARED_LIBS:=off}" + +: "${VERBOSE:=1}" + +declare packaging_dependencies_yum=( + rpmdevtools + ) + +install_rpm_packaging_utils() { + yum_install \ + "${packaging_dependencies_yum[@]}" \ + "$@" +} + +install_packaging_dependencies() { + case "${DIST}" in + centos) + install_rpm_packaging_utils epel-rpm-macros + ;; + *) + install_rpm_packaging_utils + esac +} + +# NOTE: This should be done by install_noncacheable_dependencies.sh. +install_build_dependencies() { + "${OS}_install" +} + +install_dependencies() { + # NOTE: This is done by install_noncacheable_dependencies.sh. + # install_build_dependencies + install_packaging_dependencies +} + +prepare_build_package() { + install_dependencies + rpmdev-setuptree + export SOURCE_PATH=rnp${RNP_VERSION:+-${RNP_VERSION}} + cp -a "${GITHUB_WORKSPACE}" ~/rpmbuild/SOURCES/"${SOURCE_PATH}" +} + +build_package() { + pushd ~/rpmbuild/SOURCES/"${SOURCE_PATH}" + + # XXX: debug + command -v asciidoctor + + cpack -G RPM --config ./CPackSourceConfig.cmake + make package VERBOSE="${VERBOSE}" + + popd +} + +post_build_package() { + pushd ~/rpmbuild/SOURCES/"${SOURCE_PATH}" + + mv ./*.src.rpm ~/rpmbuild/SRPMS/ + # mkdir -p ~/rpmbuild/RPMS/noarch/ + # mv *.noarch.rpm ~/rpmbuild/RPMS/noarch/ + mkdir -p ~/rpmbuild/RPMS/x86_64/ + mv ./*.rpm ~/rpmbuild/RPMS/x86_64/ + + popd +} + +test_packages() { + yum_install ~/rpmbuild/RPMS/x86_64/*.rpm +} + +main() { + # For asciidoctor: + export PATH=$HOME/bin:$PATH + + . ci/env.inc.sh + + prepare_build_package + + export LDFLAGS='-Wl,-t' # XXX: DELETEME: for debugging only + + pushd ~/rpmbuild/SOURCES/"${SOURCE_PATH}" + + export cmakeopts=( + -DBUILD_SHARED_LIBS="${BUILD_SHARED_LIBS}" + -DBUILD_TESTING=no + -DCPACK_GENERATOR=RPM + ) + build_rnp "." + popd + + build_package + post_build_package + test_packages +} + +main "$@" diff --git a/ci/docker/Makefile b/ci/docker/Makefile new file mode 100644 index 0000000..b5e9877 --- /dev/null +++ b/ci/docker/Makefile @@ -0,0 +1,11 @@ +all: fedora35.pushed +clean: + rm *.built *.pushed +.PHONY: all clean + +fedora35.built: + cd ../.. && docker build --squash -t andreyutkin/rnp-ci-fedora:35 -f ci/docker/fedora35.Dockerfile . + touch $@ +fedora35.pushed: fedora35.built + docker push andreyutkin/rnp-ci-fedora:35 + touch $@ diff --git a/ci/docker/fedora35.Dockerfile b/ci/docker/fedora35.Dockerfile new file mode 100644 index 0000000..dd71b05 --- /dev/null +++ b/ci/docker/fedora35.Dockerfile @@ -0,0 +1,52 @@ +FROM fedora:35 +RUN dnf makecache +RUN dnf -y install \ +autoconf \ +automake \ +bison \ +botan2 \ +botan2-devel \ +byacc \ +bzip2 \ +bzip2-devel \ +clang \ +cmake \ +gcc \ +gcc-c++ \ +gettext-devel \ +git \ +gtest \ +gtest-devel \ +gzip \ +json-c \ +json-c-devel \ +libtool \ +make \ +ncurses-devel \ +openssl \ +openssl-devel \ +openssl-libs \ +python3 \ +ruby-devel \ +rubygem-asciidoctor \ +sudo \ +wget \ +zlib-devel \ +; +RUN dnf clean all + +RUN useradd rnpuser +RUN echo -e "rnpuser\tALL=(ALL)\tNOPASSWD:\tALL" > /etc/sudoers.d/rnpuser +RUN echo -e "rnpuser\tsoft\tnproc\tunlimited\n" > /etc/security/limits.d/30-rnpuser.conf + +# Everything below wouldn't be needed if packaged gpg didn't fail with "Unknown elliptic curve" +# on these tests from cli_tests.Misc: +# test_aead_last_chunk_zero_length +# test_clearsign_long_lines +# test_eddsa_sig_lead_zero +# test_text_sig_crcr + +COPY ci ci +RUN export USE_STATIC_DEPENDENCIES=yes && su rnpuser -c ci/install_noncacheable_dependencies.sh +RUN export USE_STATIC_DEPENDENCIES=yes && su rnpuser -c ci/install_cacheable_dependencies.sh +RUN rm -rf /home/rnpuser/local-builds diff --git a/ci/docker/fedora35.test-locally b/ci/docker/fedora35.test-locally new file mode 100755 index 0000000..892c9a6 --- /dev/null +++ b/ci/docker/fedora35.test-locally @@ -0,0 +1,22 @@ +#!/bin/bash + +rm -rf /tmp/rnp* + +cat > run-this <<EOF +#!/bin/bash +set -e +set -x + +export USE_STATIC_DEPENDENCIES=no + +export BUILD_MODE=normal CC=gcc CXX=g++ CRYPTO_BACKEND=openssl +#export BUILD_MODE=sanitize CC=clang CXX=clang++ CRYPTO_BACKEND=botan + +cp -a /rnp /rnp.container +cd /rnp.container +chown -R rnpuser:rnpuser . +su rnpuser -c ci/run.sh || bash -i +EOF +chmod a+x run-this + +docker run -v $PWD:/rnp -it andreyutkin/rnp-ci-fedora:35 /rnp/run-this diff --git a/ci/env-common.inc.sh b/ci/env-common.inc.sh new file mode 100644 index 0000000..11712f0 --- /dev/null +++ b/ci/env-common.inc.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +: "${LOCAL_BUILDS:=$HOME/local-builds}" +: "${LOCAL_INSTALLS:=$HOME/local-installs}" +: "${BOTAN_INSTALL:=$LOCAL_INSTALLS/botan-install}" +: "${JSONC_INSTALL:=$LOCAL_INSTALLS/jsonc-install}" +: "${GPG_INSTALL:=$LOCAL_INSTALLS/gpg-install}" +: "${RNP_INSTALL:=$LOCAL_INSTALLS/rnp-install}" +: "${CPU:=}" +: "${SUDO:=}" + +for var in LOCAL_BUILDS LOCAL_INSTALLS BOTAN_INSTALL JSONC_INSTALL \ + GPG_INSTALL RNP_INSTALL CPU SUDO; do + export "${var?}" +done + +: "${BUILD_MODE:=normal}" + +if [ "$BUILD_MODE" = "sanitize" ]; then + export CXX=clang++ + export CC=clang +fi + +BOTAN_MODULES=$(<ci/botan-modules tr '\n' ',') + +export BOTAN_MODULES + +# Don't clean up tempdirs when in CI runners to save time. Unset to disable. +export RNP_KEEP_TEMP=1 diff --git a/ci/env-freebsd.inc.sh b/ci/env-freebsd.inc.sh new file mode 100644 index 0000000..3509111 --- /dev/null +++ b/ci/env-freebsd.inc.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +export PATH="/usr/local/bin:$PATH" +export MAKE=gmake +export SUDO=sudo + +: "${CORES:=$(sysctl -n hw.ncpu)}" +export CORES diff --git a/ci/env-linux.inc.sh b/ci/env-linux.inc.sh new file mode 100644 index 0000000..9267972 --- /dev/null +++ b/ci/env-linux.inc.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1091 + +: "${CORES:=$(grep -c '^$' /proc/cpuinfo)}" +export CORES +export MAKE=make + +DIST="$(get_linux_dist)" +DIST_VERSION_ID="$(sh -c '. /etc/os-release && echo $VERSION_ID')" +DIST_VERSION="${DIST}-${DIST_VERSION_ID}" + +export DIST +export DIST_VERSION +export DIST_VERSION_ID + +case "${DIST}" in + centos|fedora) + if command -v dnf >/dev/null; then + export YUM=dnf + else + export YUM=yum + fi + export SUDO=sudo + ;; + ubuntu) + export SUDO=sudo + ;; +esac + +# XXX: debug function for locale +case "${DIST}" in + fedora|centos) + debuglocale() { + locale -a + localedef --list-archive + if ! command -v diff >/dev/null; then + "${YUM}" -y -q install diffutils + fi + bash -c 'diff -u <(localedef --list-archive | sort) <(locale -a | sort) || :' + localedef -c -i "${LC_ALL%.*}" -f UTF-8 "${LC_ALL}" + # Error: character map file `UTF-8' not found: No such file or directory + # Error: cannot read character map directory `/usr/share/i18n/charmaps': No such file or directory + locale -a | grep "${LC_ALL}" || : + } + ;; +esac diff --git a/ci/env.inc.sh b/ci/env.inc.sh new file mode 100644 index 0000000..ab2271f --- /dev/null +++ b/ci/env.inc.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1090 +# shellcheck disable=SC1091 +if [[ -z "${INCLUDED_ENV_INC_SH:-}" ]]; then + . ci/utils.inc.sh + . ci/env-common.inc.sh + + OS="$(get_os)" + export OS + + . "ci/env-${OS}.inc.sh" + + : "${MAKE_PARALLEL:=$CORES}" + export MAKE_PARALLEL + + . ci/lib/install_functions.inc.sh + + + : "${MAKE_PARALLEL:=$CORES}" + export MAKE_PARALLEL + + : "${CTEST_PARALLEL:=$CORES}" + export CTEST_PARALLEL + + : "${PARALLEL_TEST_PROCESSORS:=$CORES}" + export PARALLEL_TEST_PROCESSORS + + export INCLUDED_ENV_INC_SH=1 +fi diff --git a/ci/gha/setup-env.inc.sh b/ci/gha/setup-env.inc.sh new file mode 100644 index 0000000..c0aca85 --- /dev/null +++ b/ci/gha/setup-env.inc.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2086,SC2129,SC2034 + +set -euxo pipefail +# execute this script in a separate, early step + +LOCAL_BUILDS="${GITHUB_WORKSPACE}/builds" + +# To install and cache our dependencies we need an absolute path +# that does not change, is writable, and resides within +# GITHUB_WORKSPACE. +# On macOS GITHUB_WORKSPACE includes the github runner version, +# so it does not remain constant. +# This causes problems with, for example, pkgconfig files +# referencing paths that no longer exist. +CACHE_DIR="installs" +mkdir -p "${CACHE_DIR}" + +if [[ "${RUNNER_OS}" = "Windows" ]] +then + rnp_local_installs="${RUNNER_TEMP}/rnp-local-installs" +else + rnp_local_installs=/tmp/rnp-local-installs +fi + +ln -s "$GITHUB_WORKSPACE/installs" "${rnp_local_installs}" +LOCAL_INSTALLS="${rnp_local_installs}" + +# When building packages, dependencies with non-standard installation paths must +# be found by the (DEB) package builder. +BOTAN_INSTALL="${rnp_local_installs}/botan-install" +JSONC_INSTALL="${rnp_local_installs}/jsonc-install" +GPG_INSTALL="${rnp_local_installs}/gpg-install" + +# set this explicitly since we don't want to cache the rnp installation +RNP_INSTALL="${GITHUB_WORKSPACE}/rnp-install" + +for var in \ + LOCAL_BUILDS \ + CACHE_DIR \ + LOCAL_INSTALLS \ + BOTAN_INSTALL \ + JSONC_INSTALL \ + GPG_INSTALL \ + RNP_INSTALL +do + val="${!var}" + + # Replace all backslashes with forward slashes, for cmake, so the following + # error would not come up: + # + # Invalid character escape '\a'. + # + if [[ "${RUNNER_OS}" = "Windows" ]] + then + val="${val//\\/\/}" + fi + + echo "${var}=${val}" >> "$GITHUB_ENV" +done diff --git a/ci/install.sh b/ci/install.sh new file mode 100755 index 0000000..9d90265 --- /dev/null +++ b/ci/install.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1091 +set -exu + +. ci/env.inc.sh + +install_static_cacheable_build_dependencies "$@" diff --git a/ci/install_cacheable_dependencies.sh b/ci/install_cacheable_dependencies.sh new file mode 100755 index 0000000..ea23ad6 --- /dev/null +++ b/ci/install_cacheable_dependencies.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1091 +set -exu + +. ci/env.inc.sh + +install_static_cacheable_build_dependencies_if_needed "$@" diff --git a/ci/install_noncacheable_dependencies.sh b/ci/install_noncacheable_dependencies.sh new file mode 100755 index 0000000..bfb93da --- /dev/null +++ b/ci/install_noncacheable_dependencies.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1091 +set -exu + +. ci/env.inc.sh + +"${OS}_install" +install_static_noncacheable_build_dependencies_if_needed "$@" diff --git a/ci/lib/cacheable_install_functions.inc.sh b/ci/lib/cacheable_install_functions.inc.sh new file mode 100644 index 0000000..6ef35bb --- /dev/null +++ b/ci/lib/cacheable_install_functions.inc.sh @@ -0,0 +1,242 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1090 +# shellcheck disable=SC1091 +# shellcheck disable=SC2164 +# +# All of the following functions install things into the +# CACHE_DIR, so they could be safely skipped in case of a +# cache hit. Conversely, these should not attempt to export +# environment variables (unless for self consumption), nor +# modify other system parts (again, unless for self +# consumption), as these will not be available in case of +# cache hits. + +install_botan() { + # botan + local botan_build=${LOCAL_BUILDS}/botan + if [[ ! -e "${BOTAN_INSTALL}/lib/libbotan-2.so" ]] && \ + [[ ! -e "${BOTAN_INSTALL}/lib/libbotan-2.dylib" ]] && \ + [[ ! -e "${BOTAN_INSTALL}/lib/libbotan-2.a" ]]; then + + if [[ -d "${botan_build}" ]]; then + rm -rf "${botan_build}" + fi + + git clone --depth 1 --branch "${BOTAN_VERSION}" https://github.com/randombit/botan "${botan_build}" + pushd "${botan_build}" + + local osparam=() + local cpuparam=() + local run=run + # Position independent code is a default for shared libraries at any xNIX platform + # but it makes no sense and is not supported for Windows + local extra_cflags="-fPIC" + case "${OS}" in + linux) + case "${DIST_VERSION}" in + centos-8|centos-9|fedora-*|debian-*) + run=run_in_python_venv + ;; + esac + ;; + esac + + [[ -z "$CPU" ]] || cpuparam=(--cpu="$CPU" --disable-cc-tests) + + local build_target="shared,cli" + is_use_static_dependencies && build_target="static,cli" + + "${run}" ./configure.py --prefix="${BOTAN_INSTALL}" --with-debug-info --extra-cxxflags="-fno-omit-frame-pointer ${extra_cflags}" \ + ${osparam+"${osparam[@]}"} ${cpuparam+"${cpuparam[@]}"} --without-documentation --without-openssl --build-targets="${build_target}" \ + --minimized-build --enable-modules="$BOTAN_MODULES" + ${MAKE} -j"${MAKE_PARALLEL}" install + popd + fi +} + +# TODO: +# /tmp/rnp-local-installs/jsonc-install/lib +# | If you ever happen to want to link against installed libraries +# | in a given directory, LIBDIR, you must either use libtool, and +# | specify the full pathname of the library, or use the '-LLIBDIR' +# | flag during linking and do at least one of the following: +# | - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable +# | during execution +# | - add LIBDIR to the 'LD_RUN_PATH' environment variable +# | during linking +# | - use the '-Wl,-rpath -Wl,LIBDIR' linker flag +# | - have your system administrator add LIBDIR to '/etc/ld.so.conf' +install_jsonc() { + local jsonc_build=${LOCAL_BUILDS}/json-c + if [[ ! -e "${JSONC_INSTALL}/lib/libjson-c.so" ]] && \ + [[ ! -e "${JSONC_INSTALL}/lib/libjson-c.dylib" ]] && \ + [[ ! -e "${JSONC_INSTALL}/lib/libjson-c.a" ]]; then + + if [ -d "${jsonc_build}" ]; then + rm -rf "${jsonc_build}" + fi + + mkdir -p "${jsonc_build}" + pushd "${jsonc_build}" + wget https://s3.amazonaws.com/json-c_releases/releases/json-c-"${JSONC_VERSION}".tar.gz -O json-c.tar.gz + tar xzf json-c.tar.gz --strip 1 + + autoreconf -ivf + local cpuparam=() + [[ -z "$CPU" ]] || cpuparam=(--build="$CPU") + local build_type_args=( + "--enable-$(is_use_static_dependencies && echo 'static' || echo 'shared')" + "--disable-$(is_use_static_dependencies && echo 'shared' || echo 'static')" + ) + env CFLAGS="-fPIC -fno-omit-frame-pointer -Wno-implicit-fallthrough -g" ./configure ${cpuparam+"${cpuparam[@]}"} "${build_type_args[@]}" --prefix="${JSONC_INSTALL}" + ${MAKE} -j"${MAKE_PARALLEL}" install + popd + fi +} + +_install_gpg() { + local VERSION_SWITCH=$1 + local NPTH_VERSION=$2 + local LIBGPG_ERROR_VERSION=$3 + local LIBGCRYPT_VERSION=$4 + local LIBASSUAN_VERSION=$5 + local LIBKSBA_VERSION=$6 + local PINENTRY_VERSION=$7 + local GNUPG_VERSION=$8 + + local gpg_build="$PWD" + # shellcheck disable=SC2153 + local gpg_install="${GPG_INSTALL}" + mkdir -p "${gpg_build}" "${gpg_install}" + git clone --depth 1 https://github.com/rnpgp/gpg-build-scripts + pushd gpg-build-scripts + + local cpuparam=() + [[ -z "$CPU" ]] || cpuparam=(--build="$CPU") + + # configure_opts="\ + # --prefix=${gpg_install} \ + # --with-libgpg-error-prefix=${gpg_install} \ + # --with-libassuan-prefix=${gpg_install} \ + # --with-libgcrypt-prefix=${gpg_install} \ + # --with-ksba-prefix=${gpg_install} \ + # --with-npth-prefix=${gpg_install} \ + # --disable-doc \ + # --extra-cflags=\"-O3 -fomit-frame-pointer\" \ + # --enable-pinentry-curses \ + # --disable-pinentry-emacs \ + # --disable-pinentry-gtk2 \ + # --disable-pinentry-gnome3 \ + # --disable-pinentry-qt \ + # --disable-pinentry-qt4 \ + # --disable-pinentry-qt5 \ + # --disable-pinentry-tqt \ + # --disable-pinentry-fltk \ + # --enable-maintainer-mode \ + # ${cpuparam+"${cpuparam[@]}"}" + + local configure_opts=( + "--prefix=${gpg_install}" + "--with-libgpg-error-prefix=${gpg_install}" + "--with-libassuan-prefix=${gpg_install}" + "--with-libgcrypt-prefix=${gpg_install}" + "--with-ksba-prefix=${gpg_install}" + "--with-npth-prefix=${gpg_install}" + "--disable-doc" + "--enable-pinentry-curses" + "--disable-pinentry-emacs" + "--disable-pinentry-gtk2" + "--disable-pinentry-gnome3" + "--disable-pinentry-qt" + "--disable-pinentry-qt4" + "--disable-pinentry-qt5" + "--disable-pinentry-tqt" + "--disable-pinentry-fltk" + "--enable-maintainer-mode" + "--enable-install-gpg-error-config" + ${cpuparam+"${cpuparam[@]}"} + ) + + local common_args=( + --force-autogen +# --verbose commented out to speed up recurring CI builds +# --trace uncomment if you are debugging CI + --build-dir "${gpg_build}" + --configure-opts "${configure_opts[*]}" + ) + + case "${OS}" in + linux) + if [[ "${DIST}" != "ubuntu" ]]; then + common_args+=(--ldconfig) + fi + ;; + esac + + # For "tee"-ing to /etc/ld.so.conf.d/gpg-from_build_scripts.conf from option `--ldconfig` + if [[ "${SUDO}" = "sudo" && "${DIST}" != "ubuntu" ]]; then + common_args+=(--sudo) + fi + + # Workaround to correctly build pinentry on the latest GHA on macOS. Most likely there is a better solution. + export CFLAGS="-D_XOPEN_SOURCE_EXTENDED" + export CXXFLAGS="-D_XOPEN_SOURCE_EXTENDED" + + # Always build GnuPG with gcc, even if we are testing clang + # ref https://github.com/rnpgp/rnp/issues/1669 + export CC="gcc" + export CXX="g++" + + for component in libgpg-error:$LIBGPG_ERROR_VERSION \ + libgcrypt:$LIBGCRYPT_VERSION \ + libassuan:$LIBASSUAN_VERSION \ + libksba:$LIBKSBA_VERSION \ + npth:$NPTH_VERSION \ + pinentry:$PINENTRY_VERSION \ + gnupg:$GNUPG_VERSION; do + local name="${component%:*}" + local version="${component#*:}" + + ./install_gpg_component.sh \ + --component-name "$name" \ + --"$VERSION_SWITCH" "$version" \ + "${common_args[@]}" + done + popd +} + + +install_gpg() { + local gpg_build=${LOCAL_BUILDS}/gpg + + # shellcheck disable=SC2153 + if [[ ! -e "${GPG_INSTALL}/bin/gpg" ]]; then + mkdir -p "${gpg_build}" + pushd "${gpg_build}" + + # shellcheck disable=SC2153 + case "${GPG_VERSION}" in + stable) + # npth libgpg-error libgcrypt libassuan libksba pinentry gnupg + _install_gpg component-version 1.6 1.46 1.10.1 2.5.5 1.6.3 1.2.1 2.4.0 + ;; + lts) + # npth libgpg-error libgcrypt libassuan libksba pinentry gnupg + _install_gpg component-version 1.6 1.46 1.8.10 2.5.5 1.6.3 1.2.1 2.2.41 + ;; + beta) + # npth libgpg-error libgcrypt libassuan libksba pinentry gnupg + _install_gpg component-git-ref 2501a48 f73605e d9c4183 909133b 3df0cd3 0e2e53c c6702d7 + # _install_gpg component-git-ref 7e45b50 c66594d cf88dca 57cf9d6 4243085 6e8ad31 d4e5979 + ;; + "2.3.1") + # npth libgpg-error libgcrypt libassuan libksba pinentry gnupg + _install_gpg component-version 1.6 1.42 1.9.3 2.5.5 1.6.0 1.1.1 2.3.1 + ;; + *) + >&2 echo "\$GPG_VERSION is set to invalid value: ${GPG_VERSION}" + exit 1 + esac + popd + fi +} diff --git a/ci/lib/install_functions.inc.sh b/ci/lib/install_functions.inc.sh new file mode 100644 index 0000000..98acc82 --- /dev/null +++ b/ci/lib/install_functions.inc.sh @@ -0,0 +1,869 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1090 +# shellcheck disable=SC1091 +# shellcheck disable=SC2164 + +: "${GPG_VERSION:=stable}" +: "${BUILD_SHARED_LIBS:=off}" +: "${USE_STATIC_DEPENDENCIES:=}" +: "${OS:=}" +: "${DIST:=}" +: "${DIST_VERSION:=}" +: "${DIST_VERSION_ID:=}" + +: "${MINIMUM_CMAKE_VERSION:=3.20.0}" +: "${MINIMUM_RUBY_VERSION:=3.0.0}" + +: "${RECOMMENDED_BOTAN_VERSION:=2.18.2}" +: "${RECOMMENDED_JSONC_VERSION:=0.12.1}" +: "${RECOMMENDED_CMAKE_VERSION:=3.20.5}" +: "${RECOMMENDED_PYTHON_VERSION:=3.9.2}" +: "${RECOMMENDED_RUBY_VERSION:=3.1.1}" + +: "${CMAKE_VERSION:=${RECOMMENDED_CMAKE_VERSION}}" +: "${BOTAN_VERSION:=${RECOMMENDED_BOTAN_VERSION}}" +: "${JSONC_VERSION:=${RECOMMENDED_JSONC_VERSION}}" +: "${PYTHON_VERSION:=${RECOMMENDED_PYTHON_VERSION}}" +: "${RUBY_VERSION:=${RECOMMENDED_RUBY_VERSION}}" + +# Should minimum automake version change +# please consider release of Ribose RPM for it +# [https://github.com/riboseinc/rpm-spec-automake116-automake] + +: "${MINIMUM_AUTOMAKE_VERSION:=1.16.3}" +: "${RECOMMENDED_AUTOMAKE_VERSION:=1.16.4}" +: "${AUTOMAKE_VERSION:=${RECOMMENDED_AUTOMAKE_VERSION}}" + +: "${VERBOSE:=1}" + + +if [[ "${OS}" = "freebsd" ]] || \ + [[ "${DIST}" = "ubuntu" ]] || \ + [[ "${DIST}" = "centos" ]] || \ + [[ "${DIST}" = "fedora" ]] +then + SUDO="${SUDO:-sudo}" +else + SUDO="${SUDO:-run}" +fi + +# Simply run its arguments. +run() { + "$@" +} + +. ci/lib/cacheable_install_functions.inc.sh + +freebsd_install() { + local packages=( + git + readline + bash + gnupg + devel/pkgconf + wget + cmake + gmake + autoconf + automake + libtool + gettext-tools + python + lang/ruby27 + ) + + # Note: we assume sudo is already installed + "${SUDO}" pkg install -y "${packages[@]}" + + cd /usr/ports/devel/ruby-gems + "${SUDO}" make -DBATCH RUBY_VER=2.7 install + cd + + mkdir -p ~/.gnupg + echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf + dirmngr </dev/null + dirmngr --daemon + ensure_automake +} + +openbsd_install() { + echo "" +} + +netbsd_install() { + echo "" +} + +linux_prepare_ribose_yum_repo() { + "${SUDO}" rpm --import https://github.com/riboseinc/yum/raw/master/ribose-packages.pub + "${SUDO}" rpm --import https://github.com/riboseinc/yum/raw/master/ribose-packages-next.pub + "${SUDO}" curl -L https://github.com/riboseinc/yum/raw/master/ribose.repo \ + -o /etc/yum.repos.d/ribose.repo +} + +# Prepare the system by updating and optionally installing repos +yum_prepare_repos() { + yum_install "${util_depedencies_yum[@]}" + linux_prepare_ribose_yum_repo + "${SUDO}" "${YUM}" -y update + if [[ $# -gt 0 ]]; then + yum_install "$@" + fi +} + +linux_install_fedora() { + yum_prepare_repos + extra_dep=(cmake json-c-devel ruby) + + yum_install_build_dependencies "${extra_dep[@]}" + yum_install_dynamic_build_dependencies_if_needed + + ensure_automake + ensure_cmake +# ensure_ruby + rubygem_install_build_dependencies +} + +linux_install_centos() { + case "${DIST_VERSION}" in + centos-7) + linux_install_centos7 + ;; + centos-8) + linux_install_centos8 + ;; + centos-9) + linux_install_centos9 + ;; + *) + >&2 echo "Error: unsupported CentOS version \"${DIST_VERSION_ID}\" (supported: 7, 8, 9). Aborting." + exit 1 + esac +} + +declare util_depedencies_yum=( + sudo + wget + git +) + +declare basic_build_dependencies_yum=( + # cmake3 # XXX: Fedora 22+ only has cmake + clang + gcc + gcc-c++ + make + autoconf + libtool + bzip2 + gzip + ribose-automake116 +) + +declare build_dependencies_yum=( + bison + byacc + bzip2-devel + gettext-devel + ncurses-devel + python3 +# ruby-devel + zlib-devel +) + +declare dynamic_build_dependencies_yum=( + botan2 + botan2-devel +) + +apt_install() { + local apt_command=(apt-get -y -q install "$@") + if command -v sudo >/dev/null; then + sudo "${apt_command[@]}" + else + "${apt_command[@]}" + fi +} + +yum_install() { + local yum_command=("${YUM}" -y -q install "$@") + if command -v sudo >/dev/null; then + sudo "${yum_command[@]}" + else + "${yum_command[@]}" + fi +} + +prepare_build_tool_env() { + enable_llvm_toolset_7 + enable_rh_ruby30 + enable_ribose_automake +# prepare_rbenv_env +} + +yum_install_build_dependencies() { + yum_install \ + "${basic_build_dependencies_yum[@]}" \ + "${build_dependencies_yum[@]}" \ + "$@" + + if [[ "${CRYPTO_BACKEND:-}" == "openssl" ]]; then + yum_install openssl-devel + fi +} + +linux_install_centos7() { + yum_prepare_repos epel-release centos-release-scl centos-sclo-rh + + extra_dep=(cmake3 llvm-toolset-7.0 json-c12-devel rh-ruby30) + + yum_install_build_dependencies "${extra_dep[@]}" + yum_install_dynamic_build_dependencies_if_needed + + ensure_automake + ensure_cmake +# ensure_ruby + enable_rh_ruby30 + rubygem_install_build_dependencies +} + +linux_install_centos8() { + "${SUDO}" "${YUM}" -y -q install 'dnf-command(config-manager)' + "${SUDO}" "${YUM}" config-manager --set-enabled powertools + "${SUDO}" "${YUM}" module reset ruby -y + yum_prepare_repos epel-release + + extra_dep=(cmake texinfo json-c-devel @ruby:3.0) + + yum_install_build_dependencies "${extra_dep[@]}" + yum_install_dynamic_build_dependencies_if_needed + + ensure_automake + ensure_cmake +# ensure_ruby + ensure_symlink_to_target /usr/bin/python3 /usr/bin/python + rubygem_install_build_dependencies +} + +linux_install_centos9() { + "${SUDO}" "${YUM}" -y -q install 'dnf-command(config-manager)' + "${SUDO}" "${YUM}" config-manager --set-enabled crb + yum_prepare_repos epel-release + + extra_dep=(cmake texinfo json-c-devel ruby) + + yum_install_build_dependencies "${extra_dep[@]}" + yum_install_dynamic_build_dependencies_if_needed + + ensure_automake + ensure_cmake +# ensure_ruby + rubygem_install_build_dependencies +} + +is_use_static_dependencies() { + [[ -n "${USE_STATIC_DEPENDENCIES}" ]] && \ + [[ no != "${USE_STATIC_DEPENDENCIES}" ]] && \ + [[ off != "${USE_STATIC_DEPENDENCIES}" ]] && \ + [[ false != "${USE_STATIC_DEPENDENCIES}" ]] && \ + [[ 0 != "${USE_STATIC_DEPENDENCIES}" ]] +} + +yum_install_dynamic_build_dependencies_if_needed() { + if ! is_use_static_dependencies; then + yum_install_dynamic_build_dependencies + fi +} + +install_static_noncacheable_build_dependencies_if_needed() { + if is_use_static_dependencies; then + install_static_noncacheable_build_dependencies "$@" + fi +} + +install_static_cacheable_build_dependencies_if_needed() { + if is_use_static_dependencies || [[ "$#" -gt 0 ]]; then + USE_STATIC_DEPENDENCIES=true + install_static_cacheable_build_dependencies "$@" + fi +} + +install_static_cacheable_build_dependencies() { + prepare_build_tool_env + + mkdir -p "$LOCAL_BUILDS" + + local default=(jsonc gpg) + if [[ "${CRYPTO_BACKEND:-}" != "openssl" ]]; then + default=(botan "${default[@]}") + fi + local items=("${@:-${default[@]}}") + for item in "${items[@]}"; do + install_"$item" + done +} + +install_static_noncacheable_build_dependencies() { + mkdir -p "$LOCAL_BUILDS" + + local default=(asciidoctor) + local items=("${@:-${default[@]}}") + for item in "${items[@]}"; do + install_"$item" + done +} + +rubygem_install_build_dependencies() { + install_asciidoctor +} + +yum_install_dynamic_build_dependencies() { + yum_install \ + "${dynamic_build_dependencies_yum[@]}" + + # Work around pkg-config giving out wrong include path for json-c: + ensure_symlink_to_target /usr/include/json-c12 /usr/include/json-c +} + +# Make sure cmake is at least 3.14+ as required by rnp +# Also make sure ctest is available. +# If not, build cmake from source. +ensure_cmake() { + ensure_symlink_to_target /usr/bin/cmake3 /usr/bin/cmake + ensure_symlink_to_target /usr/bin/cpack3 /usr/bin/cpack + + local cmake_version + cmake_version=$({ + command -v cmake >/dev/null && command cmake --version || \ + command -v cmake3 >/dev/null && command cmake3 --version + } | head -n1 | cut -f3 -d' ' + ) + + local need_to_build_cmake= + + # Make sure ctest is also in PATH. If not, build cmake from source. + # TODO: Check CentOS7 tests in GHA. + if ! command -v ctest >/dev/null; then + >&2 echo "ctest not found." + need_to_build_cmake=1 + elif ! is_version_at_least cmake "${MINIMUM_CMAKE_VERSION}" echo "${cmake_version}"; then + >&2 echo "cmake version lower than ${MINIMUM_CMAKE_VERSION}." + need_to_build_cmake=1 + fi + + if [[ "${need_to_build_cmake}" != 1 ]]; then + CMAKE="$(command -v cmake)" + >&2 echo "cmake rebuild is NOT needed." + return + fi + + >&2 echo "cmake rebuild is needed." + + pushd "$(mktemp -d)" || return 1 + + install_prebuilt_cmake Linux-x86_64 +# build_and_install_cmake + + command -v cmake + + popd + + # Abort if ctest still not found. + if ! command -v ctest >/dev/null; then + >&2 echo "Error: ctest not found. Aborting." + exit 1 + fi +} + +# E.g. for i386 +# NOTE: Make sure cmake's build prerequisites are installed. +build_and_install_cmake() { + local cmake_build=${LOCAL_BUILDS}/cmake + mkdir -p "${cmake_build}" + pushd "${cmake_build}" + wget https://github.com/Kitware/CMake/releases/download/v"${CMAKE_VERSION}"/cmake-"${CMAKE_VERSION}".tar.gz -O cmake.tar.gz + tar xzf cmake.tar.gz --strip 1 + + PREFIX="${PREFIX:-/usr}" + mkdir -p "${PREFIX}" + ./configure --prefix="${PREFIX}" && ${MAKE} -j"${MAKE_PARALLEL}" && "${SUDO}" make install + popd + CMAKE="${PREFIX}"/bin/cmake +} + +# 'arch' corresponds to the last segment of GitHub release URL +install_prebuilt_cmake() { + local arch="${1:?Missing architecture}" + local cmake_build=${LOCAL_BUILDS}/cmake + mkdir -p "${cmake_build}" + pushd "${cmake_build}" + curl -L -o \ + cmake.sh \ + https://github.com/Kitware/CMake/releases/download/v"${CMAKE_VERSION}"/cmake-"${CMAKE_VERSION}"-"${arch}".sh + + PREFIX="${PREFIX:-/usr}" + mkdir -p "${PREFIX}" + "${SUDO}" sh cmake.sh --skip-license --prefix="${PREFIX}" + popd + CMAKE="${PREFIX}"/bin/cmake +} + +build_and_install_python() { + python_build=${LOCAL_BUILDS}/python + mkdir -p "${python_build}" + pushd "${python_build}" + curl -L -o python.tar.xz https://www.python.org/ftp/python/"${PYTHON_VERSION}"/Python-"${PYTHON_VERSION}".tar.xz + tar -xf python.tar.xz --strip 1 + ./configure --enable-optimizations --prefix=/usr && ${MAKE} -j"${MAKE_PARALLEL}" && "${SUDO}" make install + ensure_symlink_to_target /usr/bin/python3 /usr/bin/python + popd +} + +# Make sure automake is at least $MINIMUM_AUTOMAKE_VERSION (1.16.3) as required by GnuPG 2.3 +# - We assume that on fedora/centos ribose rpm was used (see basic_build_dependencies_yum) +# - If automake version is less then reuired automake build it from source +ensure_automake() { + + local using_ribose_automake= + enable_ribose_automake + + local automake_version= + automake_version=$({ + command -v automake >/dev/null && command automake --version + } | head -n1 | cut -f4 -d' ' + ) + + local need_to_build_automake= + if ! is_version_at_least automake "${MINIMUM_AUTOMAKE_VERSION}" echo "${automake_version}"; then + >&2 echo "automake version lower than ${MINIMUM_AUTOMAKE_VERSION}." + need_to_build_automake=1 + fi + + if [[ "${need_to_build_automake}" != 1 ]]; then + >&2 echo "automake rebuild is NOT needed." + return + fi + + # Disable and automake116 from Ribose's repository as that may be too old. + if [[ "${using_ribose_automake}" == 1 ]]; then + >&2 echo "ribose-automake116 does not meet version requirements, disabling and removing." + . /opt/ribose/ribose-automake116/disable + "${SUDO}" rpm -e ribose-automake116 + using_ribose_automake=0 + fi + + >&2 echo "automake rebuild is needed." + pushd "$(mktemp -d)" || return 1 + build_and_install_automake + + command -v automake + popd +} + +enable_ribose_automake() { + case "${DIST}" in + centos|fedora) + if rpm --quiet -q ribose-automake116 && [[ "$PATH" != */opt/ribose/ribose-automake116/root/usr/bin* ]]; then + ACLOCAL_PATH=$(scl enable ribose-automake116 -- aclocal --print-ac-dir):$(rpm --eval '%{_datadir}/aclocal') + export ACLOCAL_PATH + . /opt/ribose/ribose-automake116/enable + >&2 echo "Ribose automake was enabled." + using_ribose_automake=1 + fi + ;; + esac +} + +enable_llvm_toolset_7() { + if [[ "${DIST_VERSION}" == "centos-7" ]] && \ + rpm --quiet -q llvm-toolset-7.0 && \ + [[ "$PATH" != */opt/rh/llvm-toolset-7.0/root/usr/bin* ]]; then + . /opt/rh/llvm-toolset-7.0/enable + fi +} + +enable_rh_ruby30() { + if [[ "${DIST_VERSION}" == "centos-7" ]] && \ + rpm --quiet -q rh-ruby30 && \ + [[ "$PATH" != */opt/rh/rh-ruby30/root/usr/bin* ]]; then + . /opt/rh/rh-ruby30/enable + PATH=$HOME/bin:$PATH + export PATH + export SUDO_GEM="run" + fi +} + +build_and_install_automake() { + # automake + automake_build=${LOCAL_BUILDS}/automake + mkdir -p "${automake_build}" + pushd "${automake_build}" + curl -L -o automake.tar.xz "https://ftp.gnu.org/gnu/automake/automake-${AUTOMAKE_VERSION}.tar.xz" + tar -xf automake.tar.xz --strip 1 + ./configure --enable-optimizations --prefix=/usr + "${MAKE}" -j"${MAKE_PARALLEL}" + "${SUDO}" "${MAKE}" install + popd +} + +# json-c is installed with install_jsonc +# asciidoctor is installed with install_asciidoctor +linux_install_ubuntu() { + "${SUDO}" apt-get update + apt_install \ + "${util_dependencies_ubuntu[@]}" \ + "${basic_build_dependencies_ubuntu[@]}" \ + "${build_dependencies_ubuntu[@]}" \ + "$@" + + ubuntu_install_dynamic_build_dependencies_if_needed + ensure_automake +} + +ubuntu_install_dynamic_build_dependencies_if_needed() { + if ! is_use_static_dependencies; then + ubuntu_install_dynamic_build_dependencies + fi +} + +ubuntu_install_dynamic_build_dependencies() { + apt_install \ + "${dynamic_build_dependencies_ubuntu[@]}" +} + +declare util_dependencies_ubuntu=() + +declare util_dependencies_deb=( + sudo + wget + git + software-properties-common + # botan # Debian 9 does not have botan in default repos? +) + +declare basic_build_dependencies_ubuntu=( + build-essential + cmake +) + +declare basic_build_dependencies_deb=( + autoconf + automake + build-essential + curl + libtool +) + +declare build_dependencies_ubuntu=( + gettext + libbz2-dev + libncurses-dev + python3 + python3-venv + ruby-dev + zlib1g-dev +) + +declare dynamic_build_dependencies_ubuntu=( + botan + libbotan-2-dev +) + +declare build_dependencies_deb=( + # botan # Debian 9 does not have botan in default repos? + gettext + libbz2-dev + libncurses5-dev + libssl-dev + python3 + python3-venv + ruby-dev + zlib1g-dev +) + +declare ruby_build_dependencies_ubuntu=( + bison + curl + libbz2-dev + libssl-dev + rubygems + zlib1g-dev +) + +declare ruby_build_dependencies_deb=( + bison + curl + libbz2-dev + libssl-dev + rubygems + zlib1g-dev +) + +linux_install_debian() { + "${SUDO}" apt-get update + apt_install \ + "${util_dependencies_deb[@]}" \ + "${basic_build_dependencies_deb[@]}" \ + "${build_dependencies_deb[@]}" \ + "$@" + + if [ "${CC-gcc}" = "clang" ]; then +# Add apt.llvm.org repository and install clang +# We may use https://packages.debian.org/stretch/clang-3.8 as well but this package gets installed to +# /usr/lib/clang... and requires update-alternatives which would be very ugly considering CC/CXX environment +# settings coming from yaml already + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - + ${SUDO} apt-add-repository "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch main" + ${SUDO} apt-get install -y clang + fi + + ensure_automake + ensure_ruby + ensure_cmake +} + +linux_install() { + if type "linux_install_${DIST}" | grep -qwi 'function'; then + "linux_install_${DIST}" + fi +} + +msys_install() { + local packages=( + tar + git + automake + autoconf + libtool + automake-wrapper + gnupg2 + make + pkg-config + p7zip + mingw64/mingw-w64-x86_64-cmake + mingw64/mingw-w64-x86_64-python3 + ) + + if [ "${CC}" = "gcc" ]; then + packages+=(mingw64/mingw-w64-x86_64-gcc + mingw64/mingw-w64-x86_64-libbotan + mingw64/mingw-w64-x86_64-json-c + ) + else + packages+=(clang64/mingw-w64-clang-x86_64-clang + clang64/mingw-w64-clang-x86_64-openmp + clang64/mingw-w64-clang-x86_64-libc++ + clang64/mingw-w64-clang-x86_64-libbotan + clang64/mingw-w64-clang-x86_64-json-c + clang64/mingw-w64-clang-x86_64-libsystre + ) + fi + + pacman --noconfirm -S --needed "${packages[@]}" + +} + +# Mainly for all python scripts with shebangs pointing to +# 'python', which is +# unavailable in CentOS 8 by default. +# +# This creates an environment where straight 'python' is available. +prepare_python_virtualenv() { + python3 -m venv ~/.venv +} + +# Run its arguments inside a python-virtualenv-enabled sub-shell. +run_in_python_venv() { + if [[ ! -e ~/.venv ]] || [[ ! -f ~/.venv/bin/activate ]]; then + prepare_python_virtualenv + fi + + ( + # Avoid issues like '_OLD_VIRTUAL_PATH: unbound variable' + set +u + . ~/.venv/bin/activate + set -u + "$@" + ) +} + +install_asciidoctor() { + gem_install asciidoctor +} + +declare ruby_build_dependencies_yum=( + zlib + zlib-devel + patch + readline-devel + libyaml-devel + libffi-devel + openssl-devel + bzip2 + bison + curl + sqlite-devel + which # for rbenv-doctor +) + +ensure_ruby() { + if is_version_at_least ruby "${MINIMUM_RUBY_VERSION}" command ruby -e 'puts RUBY_VERSION'; then + return + fi + + if [[ "${DIST_VERSION}" = fedora-20 ]]; then + ruby_build_dependencies_yum+=(--enablerepo=updates-testing) + fi + + case "${DIST}" in + centos|fedora) + yum_install "${ruby_build_dependencies_yum[@]}" + setup_rbenv + rbenv install -v "${RUBY_VERSION}" + rbenv global "${RUBY_VERSION}" + rbenv rehash + "${SUDO}" chown -R "$(whoami)" "$(rbenv prefix)" + ;; + debian) + apt_install "${ruby_build_dependencies_deb[@]}" + ;; + ubuntu) + apt_install "${ruby_build_dependencies_ubuntu[@]}" + ;; + *) + # TODO: handle ubuntu? + >&2 echo "Error: Need to install ruby ${MINIMUM_RUBY_VERSION}+" + exit 1 + esac +} + + +# shellcheck disable=SC2016 +setup_rbenv() { + pushd "$(mktemp -d)" || return 1 + local rbenv_rc=$HOME/setup_rbenv.sh + git clone https://github.com/sstephenson/rbenv.git ~/.rbenv + echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> "${rbenv_rc}" + echo 'eval "$($HOME/.rbenv/bin/rbenv init -)"' >> "${rbenv_rc}" + + git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build + echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> "${rbenv_rc}" + echo ". \"${rbenv_rc}\"" >> ~/.bash_profile + prepare_rbenv_env + + # Verify rbenv is set up correctly + curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash + popd || return 1 +} + +prepare_rbenv_env() { + case "${DIST}" in + centos|fedora) + local rbenv_rc=$HOME/setup_rbenv.sh + [[ ! -r "${rbenv_rc}" ]] || . "${rbenv_rc}" + ;; + esac + + if command -v rbenv >/dev/null; then + rbenv rehash + fi +} + +is_version_at_least() { + local bin_name="${1:?Missing bin name}"; shift + local version_constraint="${1:?Missing version constraint}"; shift + local need_to_build=0 + + if ! command -v "${bin_name}"; then + >&2 echo "Warning: ${bin_name} not installed." + need_to_build=1 + fi + + local installed_version installed_version_major installed_version_minor #version_patch + installed_version="$("$@")" + + # shellcheck disable=SC2181 + # shellcheck disable=SC2295 + if [[ $? -ne 0 ]]; then + need_to_build=1 + else + installed_version_major="${installed_version%%.*}" + installed_version_minor="${installed_version#*.}" + installed_version_minor="${installed_version_minor%%.*}" + installed_version_minor="${installed_version_minor:-0}" + installed_version_patch="${installed_version#${installed_version_major}.}" + installed_version_patch="${installed_version_patch#${installed_version_minor}}" + installed_version_patch="${installed_version_patch#[.-]}" + installed_version_patch="${installed_version_patch%%[.-]*}" + installed_version_patch="${installed_version_patch:-0}" + + local need_version_major + need_version_major="${version_constraint%%.*}" + need_version_minor="${version_constraint#*.}" + need_version_minor="${need_version_minor%%.*}" + need_version_minor="${need_version_minor:-0}" + need_version_patch="${version_constraint##*.}" + need_version_patch="${version_constraint#${need_version_major}.}" + need_version_patch="${need_version_patch#${need_version_minor}}" + need_version_patch="${need_version_patch#.}" + need_version_patch="${need_version_patch%%.*}" + need_version_patch="${need_version_patch:-0}" + + # Naive semver comparison + if [[ "${installed_version_major}" -lt "${need_version_major}" ]] || \ + [[ "${installed_version_major}" = "${need_version_major}" && "${installed_version_minor}" -lt "${need_version_minor}" ]] || \ + [[ "${installed_version_major}.${installed_version_minor}" = "${need_version_major}.${need_version_minor}" && "${installed_version_patch}" -lt "${need_version_patch}" ]]; then + need_to_build=1 + fi + fi + + if [[ 1 = "${need_to_build}" ]]; then + >&2 echo "Warning: Need to build ${bin_name} since version constraint ${version_constraint} not met." + else + >&2 echo "No need to build ${bin_name} since version constraint ${version_constraint} is met." + fi + + return "${need_to_build}" +} + +# Install specified gem. +# Use rbenv when available. Otherwise use system 'gem', and use 'sudo' +# depending on OS. +# Set SUDO_GEM to 'sudo' to force use of sudo. +# Set SUDO_GEM to 'run' to disable sudo. +gem_install() { + local gem_name="${1:?Missing gem name}" + local bin_name="${2:-${gem_name}}" + if ! command -v "${bin_name}" >/dev/null; then + if command -v rbenv >/dev/null; then + gem install "${gem_name}" + rbenv rehash + else + "${SUDO_GEM:-${SUDO:-run}}" gem install "${gem_name}" + fi + fi +} + +build_rnp() { +# shellcheck disable=SC2154 + "${CMAKE:-cmake}" "${cmakeopts[@]}" "${1:-.}" +} + +make_install() { + make -j"${MAKE_PARALLEL}" install "$@" +} + +is_true_cmake_bool() { + local arg="${1:?Missing parameter}" + case "${arg}" in + yes|on|true|y) + true + ;; + no|off|false|n) + false + ;; + *) + >&2 echo "Warning: unrecognized boolean expression ($arg). Continuing and interpreting as 'false' anyway." + false + esac +} diff --git a/ci/local.sh b/ci/local.sh new file mode 100755 index 0000000..db687ff --- /dev/null +++ b/ci/local.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -eux + +: "${GPG_VERSION:=stable}" +: "${BUILD_MODE:=normal}" + +rsync -a /usr/local/rnp /tmp +sudo -iu travis bash -x <<EOF +cd /tmp/rnp +env ${CXX:+CXX=$CXX} \ + ${CC:+CC=$CC} \ + GPG_VERSION=$GPG_VERSION \ + BUILD_MODE=$BUILD_MODE \ + ${RNP_TESTS:+RNP_TESTS=$RNP_TESTS} \ + ci/run.sh +EOF diff --git a/ci/main.sh b/ci/main.sh new file mode 100755 index 0000000..c8d80c9 --- /dev/null +++ b/ci/main.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +set -eux + +. ci/env.inc.sh + +: "${GPG_VERSION:=stable}" +: "${BUILD_MODE:=normal}" + +: "${RNP_TESTS=${RNP_TESTS-.*}}" +: "${LD_LIBRARY_PATH:=}" + +: "${DIST:=}" +: "${DIST_VERSION:=}" + +: "${SKIP_TESTS:=0}" + +prepare_build_prerequisites() { + CMAKE=cmake + + case "${OS}-${CPU}" in +# linux-i386) # For i386/Debian (the only 32 bit run) python3 is already installed by +# build_and_install_python # linux_install @ install_functions.inc.sh called from install_cacheable_dependencies.sh +# ;; # If there is a distribution that does not have python3 pre-apckeges (highly unlikely) + linux-*) # it shall be implemented like ensure_cmake + ensure_cmake + ;; + esac + + export CMAKE +} + +prepare_test_env() { + prepare_build_tool_env + + export LD_LIBRARY_PATH="${GPG_INSTALL}/lib:${BOTAN_INSTALL}/lib:${JSONC_INSTALL}/lib:${RNP_INSTALL}/lib:$LD_LIBRARY_PATH" + + # update dll search path for windows + if [[ "${OS}" = "msys" ]]; then + export PATH="${LOCAL_BUILDS}/rnp-build/lib:${LOCAL_BUILDS}/rnp-build/bin:${LOCAL_BUILDS}/rnp-build/src/lib:${BOTAN_INSTALL}/bin:$PATH" + fi +} + +prepare_tests() { + : "${COVERITY_SCAN_BRANCH:=0}" + if [[ ${COVERITY_SCAN_BRANCH} = 1 ]]; then + exit 0 + fi +} + +build_tests() { + # use test costs to prioritize + mkdir -p "${LOCAL_BUILDS}/rnp-build/Testing/Temporary" + cp "${rnpsrc}/cmake/CTestCostData.txt" "${LOCAL_BUILDS}/rnp-build/Testing/Temporary" + + local run=run + case "${DIST_VERSION}" in + centos-8|centos-9|fedora-*) + run=run_in_python_venv + ;; + esac + + "${run}" ctest -j"${CTEST_PARALLEL}" -R "$RNP_TESTS" --output-on-failure + popd +} + +main() { + if [[ ${SKIP_TESTS} = 0 ]]; then + prepare_test_env + fi + prepare_build_prerequisites + + export rnpsrc="$PWD" + + mkdir -p "${LOCAL_BUILDS}/rnp-build" + pushd "${LOCAL_BUILDS}/rnp-build" + + cmakeopts=( + -DCMAKE_BUILD_TYPE=Release + -DBUILD_SHARED_LIBS=yes + -DCMAKE_INSTALL_PREFIX="${RNP_INSTALL}" + -DCMAKE_PREFIX_PATH="${BOTAN_INSTALL};${JSONC_INSTALL};${GPG_INSTALL}" + ) + [[ ${SKIP_TESTS} = 1 ]] && cmakeopts+=(-DBUILD_TESTING=OFF) + [[ "${BUILD_MODE}" = "coverage" ]] && cmakeopts+=(-DENABLE_COVERAGE=yes) + [[ "${BUILD_MODE}" = "sanitize" ]] && cmakeopts+=(-DENABLE_SANITIZERS=yes) + [ -n "${GTEST_SOURCES:-}" ] && cmakeopts+=(-DGTEST_SOURCES="${GTEST_SOURCES}") + [ -n "${DOWNLOAD_GTEST:-}" ] && cmakeopts+=(-DDOWNLOAD_GTEST="${DOWNLOAD_GTEST}") + [ -n "${CRYPTO_BACKEND:-}" ] && cmakeopts+=(-DCRYPTO_BACKEND="${CRYPTO_BACKEND}") + [ -n "${ENABLE_SM2:-}" ] && cmakeopts+=(-DENABLE_SM2="${ENABLE_SM2}") + [ -n "${ENABLE_IDEA:-}" ] && cmakeopts+=(-DENABLE_IDEA="${ENABLE_IDEA}") + [ -n "${ENABLE_TWOFISH:-}" ] && cmakeopts+=(-DENABLE_TWOFISH="${ENABLE_TWOFISH}") + [ -n "${ENABLE_BRAINPOOL:-}" ] && cmakeopts+=(-DENABLE_BRAINPOOL="${ENABLE_BRAINPOOL}") + + if [[ "${OS}" = "msys" ]]; then + cmakeopts+=(-G "MSYS Makefiles") + fi + build_rnp "${rnpsrc}" + make_install VERBOSE=0 + + if [[ ${SKIP_TESTS} = 0 ]]; then + echo "TESTS NOT SKIPPED" + prepare_tests + build_tests + fi +} + +main "$@" + +exit 0 diff --git a/ci/run.sh b/ci/run.sh new file mode 100755 index 0000000..b9e366c --- /dev/null +++ b/ci/run.sh @@ -0,0 +1,5 @@ +#!/bin/sh +set -eux + +ci/main.sh +ci/success.sh diff --git a/ci/style-check.sh b/ci/style-check.sh new file mode 100755 index 0000000..683bbcd --- /dev/null +++ b/ci/style-check.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -eu + +echo Evaluating changes: +git diff -U0 "$TRAVIS_COMMIT_RANGE" +echo + +diffs=$(git diff -U0 --no-color "$TRAVIS_COMMIT_RANGE" | "$CLANG_FORMAT_DIFF" -p1 -iregex '.*\.[ch]$') +if [ "$diffs" != "" ]; then + echo ==== Style changes required ==== + echo "$diffs" + exit 1 +fi + diff --git a/ci/success.sh b/ci/success.sh new file mode 100755 index 0000000..1a34be7 --- /dev/null +++ b/ci/success.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -eu + +: "${BUILD_MODE:=normal}" + +if [ "$BUILD_MODE" = "coverage" ]; then + curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step + curl -Os https://uploader.codecov.io/latest/linux/codecov + curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM + curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig + gpgv codecov.SHA256SUM.sig codecov.SHA256SUM + shasum -a 256 -c codecov.SHA256SUM + chmod +x codecov + find "${LOCAL_BUILDS}/rnp-build/" -type f -name '*.gcno' -exec gcov -p {} + + ./codecov +fi diff --git a/ci/tests/ci-tests.sh b/ci/tests/ci-tests.sh new file mode 100755 index 0000000..1aaba03 --- /dev/null +++ b/ci/tests/ci-tests.sh @@ -0,0 +1,144 @@ +#! /bin/bash +# +# Copyright (c) 2023 [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of rnp +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +set -o errexit -o pipefail -o noclobber -o nounset + +DIR0="$( cd "$( dirname "$0" )" && pwd )" +# shellcheck disable=SC2034 +SHUNIT_PARENT="$0" + +# Defaults applicable to 'normal' installation and not build environment +: "${BOTAN_INSTALL:=/usr}" +: "${JSONC_INSTALL:=/usr}" +: "${RNP_INSTALL:=/usr}" + +: "${ENABLE_SM2:=}" +: "${ENABLE_IDEA:=}" + +test_symbol_visibility() { + case "$OSTYPE" in + msys) + mkdir tmp + wget -O tmp/Dependencies_x64_Release.zip https://github.com/lucasg/Dependencies/releases/download/v1.10/Dependencies_x64_Release.zip + 7z x tmp/Dependencies_x64_Release.zip -otmp + tmp/Dependencies -exports "$RNP_INSTALL"/bin/librnp.dll > exports + rm -rf tmp + ;; + darwin*) + nm --defined-only -g "$RNP_INSTALL"/lib/librnp.dylib > exports + ;; + *) + nm --defined-only -g "$RNP_INSTALL"/lib64/librnp*.so > exports + esac + + assertEquals "Unexpected: 'dst_close' is in exports" 0 "$(grep -c dst_close exports)" + assertEquals "Unexpected: 'Botan' is in exports" 0 "$(grep -c Botan exports)" + assertEquals "Unexpected: 'OpenSSL' is in exports" 0 "$(grep -c OpenSSL exports)" + assertEquals "Unexpected: 'rnp_version_string_full' is not in exports" 1 "$(grep -c rnp_version_string_full exports)" + + rm -f exports +} + +test_supported_features() { + # Make sure that we support all features which should be supported + supported=( RSA ELGAMAL DSA ECDH ECDSA EDDSA \ + TRIPLEDES CAST5 BLOWFISH AES128 AES192 AES256 CAMELLIA128 CAMELLIA192 CAMELLIA256 \ + MD5 SHA1 RIPEMD160 SHA256 SHA384 SHA512 SHA224 SHA3-256 SHA3-512 \ + ZIP ZLIB BZip2 \ + "NIST P-256" "NIST P-384" "NIST P-521" Ed25519 Curve25519 secp256k1 \ + OCB) + + # Old versions say ${unsupported[@]} is unbound if empty + unsupported=( NOOP ) + + botan_only=( TWOFISH EAX ) + brainpool=( brainpoolP256r1 brainpoolP384r1 brainpoolP512r1 ) + sm2=( SM2 SM4 SM3 "SM2 P-256" ) + + # SM2 + if [[ "$ENABLE_SM2" == "Off" ]]; then + unsupported+=("${sm2[@]}") + elif [[ "${CRYPTO_BACKEND:-}" == "openssl" ]]; then + unsupported+=("${sm2[@]}") + else + supported+=("${sm2[@]}") + fi + + # IDEA + if [[ "$ENABLE_IDEA" == "Off" ]] ;then + unsupported+=(IDEA) + else + supported+=(IDEA) + fi + + case "$OSTYPE" in + msys) + so_folder="bin" + support+=("${brainpool[@]}") + ;; + darwin*) + so_folder="lib" + support+=("${brainpool[@]}") + ;; + *) + so_folder="lib64" + botan_only+=("${brainpool[@]}") + esac + + if [[ "${CRYPTO_BACKEND:-}" == "openssl" ]]; then + unsupported+=("${botan_only[@]}") + library_path="${JSONC_INSTALL}/$so_folder:${RNP_INSTALL}/$so_folder" + else + supported+=("${botan_only[@]}") + library_path="${BOTAN_INSTALL}/$so_folder:${JSONC_INSTALL}/$so_folder:${RNP_INSTALL}/$so_folder" + fi + + if [[ "$OSTYPE" == darwin* ]]; then + export DYLD_LIBRARY_PATH="$library_path" + else + export LD_LIBRARY_PATH="$library_path" + fi + + "$RNP_INSTALL"/bin/rnp --version > rnp-version + + for feature in "${supported[@]}" + do + fea="$(grep -ci "$feature" rnp-version)" + assertTrue "Unexpected unsupported feature: '$feature'" "[[ $fea -ge 1 ]]" + done + for feature in "${unsupported[@]}" + do + fea="$(grep -ci "$feature" rnp-version)" + assertTrue "Unexpected supported feature: '$feature'" "[[ $fea == 0 ]]" + done + + rm -f rnp-version +} + +# ...................................................................... +# shellcheck source=/dev/null +. "$DIR0"/shunit2/shunit2 diff --git a/ci/tests/deb-tests.sh b/ci/tests/deb-tests.sh new file mode 100755 index 0000000..7805702 --- /dev/null +++ b/ci/tests/deb-tests.sh @@ -0,0 +1,102 @@ +#! /bin/bash +# +# Copyright (c) 2023 [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of rnp +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +set -o errexit -o pipefail -o noclobber -o nounset + +DIR0="$( cd "$( dirname "$0" )" && pwd )" + +# Defaults applicable to 'normal' installation and not build environment +: "${INSTALL_PREFIX:=/usr}" +DIR_LIB="$INSTALL_PREFIX/lib/x86_64-linux-gnu" +DIR_INC="$INSTALL_PREFIX/include/rnp" +DIR_BIN="$INSTALL_PREFIX/bin" +#DIR_MAN="$INSTALL_PREFIX/share/man" +DIR_CMAKE="$INSTALL_PREFIX/lib/x86_64-linux-gnu/cmake/rnp" + +declare expected_libraries=( + "$DIR_LIB/librnp.so.0" +) + +declare expected_devlibraries=( + "$DIR_LIB/librnp.so" + "$DIR_LIB/librnp.a" + "$DIR_LIB/libsexp.a" + "$DIR_LIB/pkgconfig/librnp.pc" +) + +declare expected_includes=( + "$DIR_INC/rnp.h" + "$DIR_INC/rnp_err.h" + "$DIR_INC/rnp_export.h" +) + +declare expected_cmakefiles=( + "$DIR_CMAKE/rnp-config.cmake" + "$DIR_CMAKE/rnp-config-version.cmake" + "$DIR_CMAKE/rnp-targets.cmake" + "$DIR_CMAKE/rnp-targets-release.cmake" +) + +declare expected_binaries=( + "$DIR_BIN/rnp" + "$DIR_BIN/rnpkeys" +) + +# Man page installation does not work as expected +#declare expected_manuals=( +# "$DIR_MAN/man3/librnp.3.gz" +# "$DIR_MAN/man1/rnp.1.gz" +# "$DIR_MAN/man1/rnpkeys.1.gz" +#) + +t_installed_files() { + local f= + for f in "$@" + do + assertTrue "$f was not installed" "[ -e $f ]" + done +} + +test_installed_files_librnp() { +# shellcheck disable=SC2046 + sudo dpkg -i $(ls ./*.deb) || sudo apt-get -y -f install + + t_installed_files "${expected_libraries[@]}" + t_installed_files "${expected_devlibraries[@]}" + t_installed_files "${expected_includes[@]}" + t_installed_files "${expected_cmakefiles[@]}" + t_installed_files "${expected_binaries[@]}" + +# Man page installation does not work as expected +# t_installed_files "${expected_manuals[@]}" + + sudo dpkg -r rnp0 +} + +# ...................................................................... +# shellcheck source=/dev/null +. "$DIR0"/shunit2/shunit2 diff --git a/ci/tests/pk-tests.sh b/ci/tests/pk-tests.sh new file mode 100755 index 0000000..2b22df9 --- /dev/null +++ b/ci/tests/pk-tests.sh @@ -0,0 +1,144 @@ +#! /bin/bash +# +# Copyright (c) 2023 [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of rnp +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +set -o errexit -o pipefail -o noclobber -o nounset + +DIR0="$( cd "$( dirname "$0" )" && pwd )" + +# Defaults applicable to 'normal' installation and not build environment +: "${INSTALL_PREFIX:=/usr}" + +DIR_CMAKE="$INSTALL_PREFIX/lib64/cmake/rnp" + +create_source_file() { + cat <<"EOF" > find_package_test.cpp + #include <rnp/rnp.h> + + int main(int argc, char *argv[]) { + printf("RNP version: %s\n", rnp_version_string()); + return 0; + } +EOF +} + +create_cmake_file() { + cat <<"EOF" > CMakeLists.txt + project(find_package_test) + + find_package(PkgConfig REQUIRED) + + find_package(BZip2 REQUIRED) + find_package(ZLIB REQUIRED) + + pkg_check_modules(JSONC IMPORTED_TARGET json-c12) + if(NOT JSONC_FOUND) + pkg_check_modules(JSONC REQUIRED IMPORTED_TARGET json-c) + endif(NOT JSONC_FOUND) + + add_library(JSON-C::JSON-C INTERFACE IMPORTED) + set_target_properties(JSON-C::JSON-C PROPERTIES INTERFACE_LINK_LIBRARIES PkgConfig::JSONC) + + pkg_check_modules(Botan REQUIRED IMPORTED_TARGET botan-2) + add_library(Botan2::Botan2 INTERFACE IMPORTED) + set_target_properties(Botan2::Botan2 PROPERTIES INTERFACE_LINK_LIBRARIES PkgConfig::Botan) + + find_package(rnp REQUIRED) + + cmake_minimum_required(VERSION 3.12) + add_executable(find_package_test find_package_test.cpp) +EOF + echo "target_link_libraries(find_package_test $1)">>CMakeLists.txt +} + +test_shared_library() { + sudo yum -y localinstall librnp0-0*.*.rpm librnp0-devel-0*.*.rpm + pushd "$(mktemp -d)" + create_source_file + create_cmake_file 'rnp::librnp' + +# shellcheck disable=SC2251 +! cmake . -DCMAKE_MODULE_PATH="$DIR_CMAKE"/* + assertEquals "cmake failed at shared library test" 0 "${PIPESTATUS[0]}" + +# shellcheck disable=SC2251 +! make + assertEquals "make failed at shared library test" 0 "${PIPESTATUS[0]}" + +# shellcheck disable=SC2251 +! ./find_package_test + assertEquals "test program failed at shared library test" 0 "${PIPESTATUS[0]}" + +# shellcheck disable=SC2251 +! ldd find_package_test | grep librnp + assertEquals "no reference to shared rnp library at shared library test" 0 "${PIPESTATUS[1]}" + + popd +# shellcheck disable=SC2046 + sudo yum -y erase $(rpm -qa | grep rnp) +} + +test_static_library() { + sudo yum -y localinstall librnp0-0*.*.rpm librnp0-devel-0*.*.rpm + pushd "$(mktemp -d)" + create_source_file + create_cmake_file 'rnp::librnp-static' + +# shellcheck disable=SC2251 +! cmake . -DCMAKE_MODULE_PATH="$DIR_CMAKE"/* + assertEquals "cmake failed at static library test" 0 "${PIPESTATUS[0]}" + +# shellcheck disable=SC2251 +! make + assertEquals "make failed at static library test" 0 "${PIPESTATUS[0]}" + +# shellcheck disable=SC2251 +! ./find_package_test + assertEquals "test program failed at static library test" 0 "${PIPESTATUS[0]}" + +# shellcheck disable=SC2251 +! ldd find_package_test | grep librnp + assertNotEquals "unexpected reference to shared rnp library at static library test" 0 "${PIPESTATUS[1]}" + + popd +# shellcheck disable=SC2046 + sudo yum -y erase $(rpm -qa | grep rnp) +} + +test_no_library() { + pushd "$(mktemp -d)" + create_source_file + create_cmake_file 'rnp::librnp' + +# shellcheck disable=SC2251 +! cmake . -DCMAKE_MODULE_PATH="$DIR_CMAKE"/* + assertNotEquals "cmake succeeded at no library test" 0 "${PIPESTATUS[0]}" + popd +} + +# ...................................................................... +# shellcheck source=/dev/null +. "$DIR0"/shunit2/shunit2 diff --git a/ci/tests/pkg-tests.sh b/ci/tests/pkg-tests.sh new file mode 100755 index 0000000..dbeaac6 --- /dev/null +++ b/ci/tests/pkg-tests.sh @@ -0,0 +1,102 @@ +#! /bin/bash +# +# Copyright (c) 2023 [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of rnp +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +set -o errexit -o pipefail -o noclobber -o nounset + +DIR0="$( cd "$( dirname "$0" )" && pwd )" + +# Defaults applicable to 'normal' installation and not build environment +: "${INSTALL_PREFIX:=/usr/local}" +DIR_LIB="$INSTALL_PREFIX/lib" +DIR_INC="$INSTALL_PREFIX/include/rnp" +DIR_BIN="$INSTALL_PREFIX/bin" +# DIR_MAN="$INSTALL_PREFIX/share/man" +DIR_CMAKE="$INSTALL_PREFIX/lib/cmake/rnp" + +declare expected_libraries=( + "$DIR_LIB/librnp.so.0" +) + +declare expected_devlibraries=( + "$DIR_LIB/librnp.so" + "$DIR_LIB/librnp.a" + "$DIR_LIB/libsexp.a" + "$DIR_LIB/pkgconfig/librnp.pc" +) + +declare expected_includes=( + "$DIR_INC/rnp.h" + "$DIR_INC/rnp_err.h" + "$DIR_INC/rnp_export.h" +) + +declare expected_cmakefiles=( + "$DIR_CMAKE/rnp-config.cmake" + "$DIR_CMAKE/rnp-config-version.cmake" + "$DIR_CMAKE/rnp-targets.cmake" + "$DIR_CMAKE/rnp-targets-release.cmake" +) + +declare expected_binaries=( + "$DIR_BIN/rnp" + "$DIR_BIN/rnpkeys" +) + +# Installation of man files does not work as expected +#declare expected_manuals=( +# "$DIR_MAN/man3/librnp.3.gz" +# "$DIR_MAN/man1/rnp.1.gz" +# "$DIR_MAN/man1/rnpkeys.1.gz" +#) + +t_installed_files() { + local f= + for f in "$@" + do + assertTrue "$f was not installed" "[ -e $f ]" + done +} + +test_installed_files_librnp() { +# shellcheck disable=SC2046 + pkg add $(ls ./*.pkg) + + t_installed_files "${expected_libraries[@]}" + t_installed_files "${expected_devlibraries[@]}" + t_installed_files "${expected_includes[@]}" + t_installed_files "${expected_cmakefiles[@]}" + t_installed_files "${expected_binaries[@]}" + +# Installation of man files does not work as expected +# t_installed_files "${expected_manuals[@]}" + + pkg delete rnp0 +} + +# ...................................................................... +# shellcheck source=/dev/null +. "$DIR0"/shunit2/shunit2 diff --git a/ci/tests/rpm-tests.sh b/ci/tests/rpm-tests.sh new file mode 100755 index 0000000..39f8dd0 --- /dev/null +++ b/ci/tests/rpm-tests.sh @@ -0,0 +1,126 @@ +#! /bin/bash +# +# Copyright (c) 2023 [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of rnp +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +set -o errexit -o pipefail -o noclobber -o nounset + +DIR0="$( cd "$( dirname "$0" )" && pwd )" + +# Defaults applicable to 'normal' installation and not build environment +: "${INSTALL_PREFIX:=/usr}" +: "${BOTAN_INSTALL:=$INSTALL_PREFIX}" +: "${JSONC_INSTALL:=$INSTALL_PREFIX}" +: "${RNP_INSTALL:=$INSTALL_PREFIX}" + +: "${ENABLE_SM2:=}" +: "${ENABLE_IDEA:=}" + +DIR_LIB="$INSTALL_PREFIX/lib64" +DIR_INC="$INSTALL_PREFIX/include/rnp" +DIR_BIN="$INSTALL_PREFIX/bin" +DIR_MAN="$INSTALL_PREFIX/share/man" +DIR_CMAKE="$INSTALL_PREFIX/lib64/cmake/rnp" + +declare expected_libraries=( + "$DIR_LIB/librnp.so.0" +) + +declare expected_devlibraries=( + "$DIR_LIB/librnp.so" + "$DIR_LIB/librnp.a" + "$DIR_LIB/libsexp.a" + "$DIR_LIB/pkgconfig/librnp.pc" +) + +declare expected_includes=( + "$DIR_INC/rnp.h" + "$DIR_INC/rnp_err.h" + "$DIR_INC/rnp_export.h" +) + +declare expected_cmakefiles=( + "$DIR_CMAKE/rnp-config.cmake" + "$DIR_CMAKE/rnp-config-version.cmake" + "$DIR_CMAKE/rnp-targets.cmake" + "$DIR_CMAKE/rnp-targets-release.cmake" +) + +declare expected_binaries=( + "$DIR_BIN/rnp" + "$DIR_BIN/rnpkeys" +) + +declare expected_manuals=( + "$DIR_MAN/man3/librnp.3.gz" + "$DIR_MAN/man1/rnp.1.gz" + "$DIR_MAN/man1/rnpkeys.1.gz" +) + +test_installed_files() { + local f= + for f in "$@" + do + assertTrue "$f was not installed" "[ -e $f ]" + done +} + +test_installed_files_librnp() { + sudo yum -y localinstall librnp0-0*.*.rpm + test_installed_files "${expected_libraries[@]}" +# shellcheck disable=SC2046 + sudo yum -y erase $(rpm -qa | grep rnp) +} + +test_installed_files_librnp-devel() { + sudo yum -y localinstall librnp0-0*.*.rpm librnp0-devel-0*.*.rpm + test_installed_files "${expected_libraries[@]}" + test_installed_files "${expected_devlibraries[@]}" + test_installed_files "${expected_includes[@]}" + test_installed_files "${expected_cmakefiles[@]}" +# shellcheck disable=SC2046 + sudo yum -y erase $(rpm -qa | grep rnp) +} + +test_installed_files_rnp() { + sudo yum -y localinstall librnp0-0*.*.rpm rnp0-0*.*.rpm + test_installed_files "${expected_libraries[@]}" + test_installed_files "${expected_binaries[@]}" +# shellcheck disable=SC2046 + sudo yum -y erase $(rpm -qa | grep rnp) +} + +test_installed_files_doc() { +# in case the nodocs transaction flag is set in the yum configuration + sudo yum --setopt=tsflags='' -y install man-db + sudo yum --setopt=tsflags='' -y localinstall rnp-*-doc.rpm + test_installed_files "${expected_manuals[@]}" +# shellcheck disable=SC2046 + sudo yum -y erase $(rpm -qa | grep rnp) +} + +# ...................................................................... +# shellcheck source=/dev/null +. "$DIR0"/shunit2/shunit2 diff --git a/ci/utils.inc.sh b/ci/utils.inc.sh new file mode 100644 index 0000000..618df78 --- /dev/null +++ b/ci/utils.inc.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Derived from: https://gist.github.com/marcusandre/4b88c2428220ea255b83 +get_os() { + local ostype + ostype=$(<<< "$OSTYPE" tr '[:upper:]' '[:lower:]') + if [ -z "$ostype" ]; then + ostype=$(uname | tr '[:upper:]' '[:lower:]') + fi + + case $ostype in + freebsd*) echo "freebsd" ;; + netbsd*) echo "netbsd" ;; + openbsd*) echo "openbsd" ;; + darwin*) echo "macos" ;; + linux*) echo "linux" ;; + cygwin*) echo "cygwin" ;; + msys*) echo "msys" ;; + mingw*) echo "win" ;; + *) echo "unknown"; exit 1 ;; + esac +} + +get_linux_dist() { + if [[ -f /etc/os-release ]]; then + sh -c '. /etc/os-release && echo $ID' + elif type lsb_release >/dev/null 2>&1; then + lsb_release -si | tr '[:upper:]' '[:lower:]' + fi +} + +# If target does not exist, create symlink from source to target. +ensure_symlink_to_target() { + local from="${1:?Missing source}" + local to="${2:?Missing target}" + + if [[ -e "${from}" && ! -e "${to}" ]]; then + if ! sudo ln -s "${from}" "${to}" + then + >&2 echo "Error: ${to} still not available after symlink. Aborting." + exit 1 + fi + fi +} |