summaryrefslogtreecommitdiffstats
path: root/ci
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:32:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:32:49 +0000
commit8053187731ae8e3eb368d8360989cf5fd6eed9f7 (patch)
tree32bada84ff5d7460cdf3934fcbdbe770d6afe4cd /ci
parentInitial commit. (diff)
downloadrnp-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-modules45
-rwxr-xr-xci/build_package_rpm.sh100
-rw-r--r--ci/docker/Makefile11
-rw-r--r--ci/docker/fedora35.Dockerfile52
-rwxr-xr-xci/docker/fedora35.test-locally22
-rw-r--r--ci/env-common.inc.sh29
-rw-r--r--ci/env-freebsd.inc.sh8
-rw-r--r--ci/env-linux.inc.sh46
-rw-r--r--ci/env.inc.sh29
-rw-r--r--ci/gha/setup-env.inc.sh60
-rwxr-xr-xci/install.sh7
-rwxr-xr-xci/install_cacheable_dependencies.sh7
-rwxr-xr-xci/install_noncacheable_dependencies.sh8
-rw-r--r--ci/lib/cacheable_install_functions.inc.sh242
-rw-r--r--ci/lib/install_functions.inc.sh869
-rwxr-xr-xci/local.sh16
-rwxr-xr-xci/main.sh109
-rwxr-xr-xci/run.sh5
-rwxr-xr-xci/style-check.sh14
-rwxr-xr-xci/success.sh16
-rwxr-xr-xci/tests/ci-tests.sh144
-rwxr-xr-xci/tests/deb-tests.sh102
-rwxr-xr-xci/tests/pk-tests.sh144
-rwxr-xr-xci/tests/pkg-tests.sh102
-rwxr-xr-xci/tests/rpm-tests.sh126
-rw-r--r--ci/utils.inc.sh43
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
+}