#! /usr/bin/env sh # ╭──────────╮ # │ defaults │ # ╰──────────╯ [ -n "${SPCD_CMD_SUM}" ] || SPCD_CMD_SUM="sha512sum" [ -n "${SPCD_DNS_1}" ] || SPCD_DNS_1="9.9.9.9" [ -n "${SPCD_GIT_MAIN}" ] || SPCD_GIT_MAIN="spcd" [ -n "${SPCD_GIT_ROOT}" ] || SPCD_GIT_ROOT="rwx" [ -n "${SPCD_GIT_SHUNIT}" ] || SPCD_GIT_SHUNIT="shunit2" [ -n "${SPCD_REF_FEATURE}" ] || SPCD_REF_FEATURE="f" [ -n "${SPCD_REF_RELEASE}" ] || SPCD_REF_RELEASE="main" [ -n "${SPCD_REF_STAGING}" ] || SPCD_REF_STAGING="dev" [ -n "${SPCD_URL_ALPINE}" ] || SPCD_URL_ALPINE="https://dl-cdn.alpinelinux.org" [ -n "${SPCD_URL_ARCH}" ] || SPCD_URL_ARCH="https://geo.mirror.pkgbuild.com" [ -n "${SPCD_URL_DEBIAN}" ] || SPCD_URL_DEBIAN="https://deb.debian.org" [ -n "${SPCD_URL_EPEL}" ] || SPCD_URL_EPEL="https://dl.fedoraproject.org" [ -n "${SPCD_URL_FEDORA}" ] || SPCD_URL_FEDORA="https://rpmfind.net" [ -n "${SPCD_URL_OPENSUSE}" ] || SPCD_URL_OPENSUSE="https://download.opensuse.org" [ -n "${SPCD_URL_PYTHON}" ] || SPCD_URL_PYTHON="https://pypi.org/simple" [ -n "${SPCD_URL_ROCKY}" ] || SPCD_URL_ROCKY="https://dl.rockylinux.org" [ -n "${SPCD_URL_UBUNTU}" ] || SPCD_URL_UBUNTU="https://ubuntu.mirrors.ovh.net" # ╭───────────╮ # │ internals │ # ╰───────────╯ _spcd_fill() { _spcd_fill__index=${1} while [ "${_spcd_fill__index}" -gt 0 ]; do printf "%s" "${2}" _spcd_fill__index=$((_spcd_fill__index - 1)) done unset _spcd_fill__index } # ╭───────────┬────────╮ # │ internals │ banner │ # ╰───────────┴────────╯ _SPCD_BANNER_DOWN_AND_HORIZONTAL="┬" _SPCD_BANNER_DOWN_AND_LEFT="╮" _SPCD_BANNER_DOWN_AND_RIGHT="╭" _SPCD_BANNER_HORIZONTAL="─" _SPCD_BANNER_UP_AND_HORIZONTAL="┴" _SPCD_BANNER_UP_AND_LEFT="╯" _SPCD_BANNER_UP_AND_RIGHT="╰" _SPCD_BANNER_VERTICAL="│" _spcd_banner_add() { if [ -n "${1}" ]; then spcd_ba__text=" ${1} " spcd_ba__length=${#spcd_ba__text} spcd_ba__filler="$( _spcd_fill "${spcd_ba__length}" "${_SPCD_BANNER_HORIZONTAL}" )" if [ -n "${__SPCD_BANNER_MIDDLE}" ]; then _spcd_banner_split else _spcd_banner_open fi _spcd_banner_append \ "${spcd_ba__filler}" "${spcd_ba__text}" "${spcd_ba__filler}" fi } _spcd_banner_add_index() { unset spcd_bai__label unset spcd_bai__level while true; do spcd_bai__level=$((spcd_bai__level + 1)) eval "spcd_bai__value=\"\${__SPCD_STEP_${spcd_bai__level}_INDEX}\"" [ -n "${spcd_bai__value}" ] || break if [ -n "${spcd_bai__label}" ]; then spcd_bai__label="${spcd_bai__label}.${spcd_bai__value}" else spcd_bai__label="${spcd_bai__value}" fi done _spcd_banner_add "${spcd_bai__label}" } _spcd_banner_append() { if [ -n "${3}" ]; then __SPCD_BANNER_TOP="${__SPCD_BANNER_TOP}${1}" __SPCD_BANNER_MIDDLE="${__SPCD_BANNER_MIDDLE}${2}" __SPCD_BANNER_BOTTOM="${__SPCD_BANNER_BOTTOM}${3}" fi } _spcd_banner_echo() { echo "\ ${__SPCD_BANNER_TOP} ${__SPCD_BANNER_MIDDLE} ${__SPCD_BANNER_BOTTOM}" } _spcd_banner_open() { _spcd_banner_append \ "${_SPCD_BANNER_DOWN_AND_RIGHT}" \ "${_SPCD_BANNER_VERTICAL}" \ "${_SPCD_BANNER_UP_AND_RIGHT}" } _spcd_banner_render() { _spcd_banner_wipe _spcd_banner_add "S" _spcd_banner_add_index # unset spcd_br__level while true; do spcd_br__level=$((spcd_br__level + 1)) eval "spcd_br__value=\"\${__SPCD_STEP_${spcd_br__level}_LABEL}\"" [ -n "${spcd_br__value}" ] || break _spcd_banner_add "${spcd_br__value}" done # _spcd_banner_shut _spcd_banner_echo _spcd_banner_wipe } _spcd_banner_shut() { _spcd_banner_append \ "${_SPCD_BANNER_DOWN_AND_LEFT}" \ "${_SPCD_BANNER_VERTICAL}" \ "${_SPCD_BANNER_UP_AND_LEFT}" } _spcd_banner_split() { _spcd_banner_append \ "${_SPCD_BANNER_DOWN_AND_HORIZONTAL}" \ "${_SPCD_BANNER_VERTICAL}" \ "${_SPCD_BANNER_UP_AND_HORIZONTAL}" } _spcd_banner_wipe() { unset \ __SPCD_BANNER_TOP \ __SPCD_BANNER_MIDDLE \ __SPCD_BANNER_BOTTOM } # ╭───────────┬───────╮ # │ internals │ error │ # ╰───────────┴───────╯ _SPCD_ERROR_CI=1 _SPCD_ERROR_OS=2 # ╭───────────┬───────╮ # │ internals │ frame │ # ╰───────────┴───────╯ _SPCD_FRAME_TOP="╭╴" _SPCD_FRAME_BOTTOM="╰╴" _spcd_frame_open() { echo "${_SPCD_FRAME_TOP}${1}" } _spcd_frame_shut() { echo "${_SPCD_FRAME_BOTTOM}${1}" } # ╭───────────┬────╮ # │ internals │ os │ # ╰───────────┴────╯ _spcd_os_cat() { if [ -n "${1}" ]; then _spcd_frame_open "${1}" cat "${1}" _spcd_frame_shut "${1}" fi } # ╭───────────┬──────╮ # │ internals │ rule │ # ╰───────────┴──────╯ _SPCD_RULE_LEFT="╶" _SPCD_RULE_MIDDLE="─" _SPCD_RULE_RIGHT="╴" # ╭───────────┬──────╮ # │ internals │ step │ # ╰───────────┴──────╯ _spcd_step_wipe() { unset \ "__SPCD_STEP_${__SPCD_STEP_LEVEL}_INDEX" \ "__SPCD_STEP_${__SPCD_STEP_LEVEL}_LABEL" } # ╭───────────╮ # │ functions │ # ╰───────────╯ # ╭───────────┬───────╮ # │ functions │ error │ # ╰───────────┴───────╯ spcd_error_ci() { echo "× CI: ${*}" exit "${_SPCD_ERROR_CI}" } spcd_error_os() { spcd_error_os__variable="${1}" printf "× OS: " spcd_os_printenv "${spcd_error_os__variable}" exit "${_SPCD_ERROR_OS}" } # ╭───────────┬─────╮ # │ functions │ git │ # ╰───────────┴─────╯ spcd_git_clone() { if [ -n "${1}" ]; then spcd_gc__name="$(basename "${1}")" spcd_gc__path="${SPCD_DL}/${spcd_gc__name}" spcd_gc__url="$(spcd_git_url "${1}")" git clone "${spcd_gc__url}" "${spcd_gc__path}" echo "${spcd_gc__path}" fi } spcd_git_url() { if [ -n "${1}" ]; then case "${1}" in http*) echo "${1}" ;; */*) echo "${SPCD_PROJECT_ROOT}/${1}" ;; *) echo "${SPCD_PROJECT_ROOT}/${SPCD_PROJECT_PATH}/${1}" ;; esac fi } # ╭───────────┬─────────╮ # │ functions │ openssl │ # ╰───────────┴─────────╯ spcd_openssl_x509() { spcd_openssl_x509__file="${1}" if [ -f "${spcd_openssl_x509__file}" ]; then openssl x509 \ -in "${spcd_openssl_x509__file}" \ -noout -text fi } # ╭───────────┬────╮ # │ functions │ os │ # ╰───────────┴────╯ spcd_os_grep() { spcd_os_grep__variable="${1}" [ -n "${spcd_os_grep__variable}" ] && grep "^${spcd_os_grep__variable}=" "/etc/os-release" | sed "s|^${spcd_os_grep__variable}=||" | sed "s|^\"\(.*\)\"$|\1|" } spcd_os_ls() { spcd_os_ls__path="${1}" if [ -n "${spcd_os_ls__path}" ]; then _spcd_frame_open "${spcd_os_ls__path}" ls -a -l "${spcd_os_ls__path}" _spcd_frame_shut "${spcd_os_ls__path}" fi } spcd_os_mkdir() { spcd_os_mkdir__path="${1}" if [ -n "${spcd_os_mkdir__path}" ]; then echo "→ ${spcd_os_mkdir__path}" mkdir --parents "${spcd_os_mkdir__path}" fi } spcd_os_printenv() { if [ -n "${1}" ]; then for spcd_os_printenv__name in "${@}"; do spcd_os_printenv__text="" eval "spcd_os_printenv__text=\"\${${spcd_os_printenv__name}}\"" echo "${spcd_os_printenv__name} = \"${spcd_os_printenv__text}\"" done fi } spcd_os_rm() { if [ -e "${1}" ]; then echo "← ${1}" rm -r "${1}" fi } spcd_os_sed() { spcd_os_sed__file="${1}" shift if [ -f "${spcd_os_sed__file}" ]; then _spcd_os_cat "${spcd_os_sed__file}" for spcd_os_sed__regex in "${@}"; do sed --in-place "s${spcd_os_sed__regex}g" "${spcd_os_sed__file}" && _spcd_os_cat "${spcd_os_sed__file}" done fi } spcd_os_write() { spcd_os_write__file="${1}" spcd_os_write__text="${2}" if [ -n "${spcd_os_write__file}" ]; then [ -f "${spcd_os_write__file}" ] && _spcd_os_cat "${spcd_os_write__file}" echo "→ ${spcd_os_write__file}" printf "%s" "${spcd_os_write__text}" >"${spcd_os_write__file}" _spcd_os_cat "${spcd_os_write__file}" fi } # ╭───────────┬────────╮ # │ functions │ python │ # ╰───────────┴────────╯ spcd_python_ln() { spcd_python_ln__command="${1}" if [ -n "${spcd_python_ln__command}" ]; then echo "→ ${SPCD_PYTHON_ALIAS} → ${spcd_python_ln__command}" ln -f -s "${spcd_python_ln__command}" \ "/usr/bin/${SPCD_PYTHON_ALIAS}" fi } spcd_python_pip() { if [ -n "${1}" ]; then spcd_pp__name="$(basename "${1}")" spcd_pp__path="$(spcd_git_clone "${1}")" spcd_pp__path="${spcd_pp__path}/${spcd_pp__name}" spcd_pp__target="${SPCD_PYTHON_VENV_PACKAGES}" cp --recursive "${spcd_pp__path}" "${spcd_pp__target}" echo "${spcd_pp__target}/${spcd_pp__name}" fi } # ╭───────────┬───────╮ # │ functions │ split │ # ╰───────────┴───────╯ spcd_split() { echo "${_SPCD_RULE_LEFT}${_SPCD_RULE_MIDDLE}${_SPCD_RULE_RIGHT}" } # ╭───────────┬──────╮ # │ functions │ step │ # ╰───────────┴──────╯ spcd_step() { if [ -n "${1}" ]; then [ -n "${__SPCD_STEP_LEVEL}" ] || __SPCD_STEP_LEVEL=1 spcd_step__prefix="__SPCD_STEP_${__SPCD_STEP_LEVEL}" spcd_step__index="${spcd_step__prefix}_INDEX" eval "${spcd_step__index}=\$((${spcd_step__index} + 1))" eval "${spcd_step__prefix}_LABEL=\"${1}\"" _spcd_banner_render fi } spcd_step_in() { [ -n "${1}" ] && spcd_step "${1}" __SPCD_STEP_LEVEL=$((__SPCD_STEP_LEVEL + 1)) _spcd_step_wipe } spcd_step_out() { _spcd_step_wipe __SPCD_STEP_LEVEL=$((__SPCD_STEP_LEVEL - 1)) } # ╭───────╮ # │ steps │ # ╰───────╯ # ╭───────┬───────────╮ # │ steps │ constants │ # ╰───────┴───────────╯ SPCD_OS_ALMA="alma" SPCD_OS_ALPINE="alpine" SPCD_OS_ARCH="arch" SPCD_OS_DEBIAN="debian" SPCD_OS_FEDORA="fedora" SPCD_OS_OPENSUSE="opensuse" SPCD_OS_ROCKY="rocky" SPCD_OS_UBUNTU="ubuntu" SPCD_PM_APK="apk" SPCD_PM_APT="apt" SPCD_PM_DNF="dnf" SPCD_PM_PACMAN="pacman" SPCD_PM_ZYPPER="zypper" SPCD_PYTHON_VENV="/opt/venv" SPCD_PYTHON_VENV_BINARIES="${SPCD_PYTHON_VENV}/bin" # ╭───────┬─────────────╮ # │ steps │ environment │ # ╰───────┴─────────────╯ spcd_environment_set_variables() { spcd_step "Set variables" # check script first [ -n "${SPCD}" ] || spcd_error_ci "SPCD" # continuous integration / github → gitea → forgejo if [ -n "${GITHUB_ACTIONS}" ]; then # project branch if [ -n "${GITHUB_REF_NAME}" ]; then SPCD_PROJECT_BRANCH="${GITHUB_REF_NAME}" else spcd_error_ci "GITHUB_REF_NAME" fi # project root if [ -n "${GITHUB_SERVER_URL}" ]; then SPCD_PROJECT_ROOT="$(dirname "${GITHUB_SERVER_URL}")//" [ -n "${GITHUB_TOKEN}" ] && SPCD_PROJECT_ROOT="${SPCD_PROJECT_ROOT}${GITHUB_TOKEN}@" SPCD_PROJECT_ROOT="\ ${SPCD_PROJECT_ROOT}$(basename "${GITHUB_SERVER_URL}")" else spcd_error_ci "GITHUB_SERVER_URL" fi # project path & name if [ -n "${GITHUB_REPOSITORY}" ]; then # project path SPCD_PROJECT_PATH="$(dirname "${GITHUB_REPOSITORY}")" # project name SPCD_PROJECT_NAME="$(basename "${GITHUB_REPOSITORY}")" else spcd_error_ci "GITHUB_REPOSITORY" fi # continuous integration / gitlab elif [ -n "${GITLAB_CI}" ]; then # project branch if [ -n "${CI_COMMIT_BRANCH}" ]; then SPCD_PROJECT_BRANCH="${CI_COMMIT_BRANCH}" else spcd_error_ci "CI_COMMIT_BRANCH" fi # project root / protocol if [ -n "${CI_SERVER_PROTOCOL}" ]; then # project root / login if [ -n "${CI_REGISTRY_USER}" ]; then # project root / password if [ -n "${CI_REGISTRY_PASSWORD}" ]; then # project root / host if [ -n "${CI_SERVER_FQDN}" ]; then # project root SPCD_PROJECT_ROOT="${CI_SERVER_PROTOCOL}\ ://${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD}@${CI_SERVER_FQDN}" # project path if [ -n "${CI_PROJECT_NAMESPACE}" ]; then SPCD_PROJECT_PATH="${CI_PROJECT_NAMESPACE}" # project name if [ -n "${CI_PROJECT_NAME}" ]; then SPCD_PROJECT_NAME="${CI_PROJECT_NAME}" else spcd_error_ci "CI_PROJECT_NAME" fi else spcd_error_ci "CI_PROJECT_NAMESPACE" fi else spcd_error_ci "CI_SERVER_FQDN" fi else spcd_error_ci "CI_REGISTRY_PASSWORD" fi else spcd_error_ci "CI_REGISTRY_USER" fi else spcd_error_ci "CI_SERVER_PROTOCOL" fi # continuous integration / unsupported else spcd_error_ci "ø" fi # check project variables case "${SPCD_PROJECT_BRANCH}" in "${SPCD_REF_RELEASE}" | \ "${SPCD_REF_STAGING}" | \ "${SPCD_REF_FEATURE}") ;; *) spcd_error_ci "SPCD_PROJECT_BRANCH" ;; esac [ -n "${SPCD_PROJECT_ROOT}" ] || spcd_error_ci "SPCD_PROJECT_ROOT" [ -n "${SPCD_PROJECT_PATH}" ] || spcd_error_ci "SPCD_PROJECT_PATH" [ -n "${SPCD_PROJECT_NAME}" ] || spcd_error_ci "SPCD_PROJECT_NAME" # spcd_os_printenv "SPCD_PROJECT_BRANCH" \ "SPCD_PROJECT_ROOT" "SPCD_PROJECT_PATH" "SPCD_PROJECT_NAME" # set operating system id SPCD_OS_ID="$(spcd_os_grep ID)" case "${SPCD_OS_ID}" in "almalinux") SPCD_OS_ID="${SPCD_OS_ALMA}" ;; "alpine") SPCD_OS_ID="${SPCD_OS_ALPINE}" ;; "arch") SPCD_OS_ID="${SPCD_OS_ARCH}" ;; "debian") SPCD_OS_ID="${SPCD_OS_DEBIAN}" ;; "fedora") SPCD_OS_ID="${SPCD_OS_FEDORA}" ;; "opensuse-leap") SPCD_OS_ID="${SPCD_OS_OPENSUSE}" ;; "rocky") SPCD_OS_ID="${SPCD_OS_ROCKY}" ;; "ubuntu") SPCD_OS_ID="${SPCD_OS_UBUNTU}" ;; *) spcd_error_os "SPCD_OS_ID" ;; esac # set operating system version case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_FEDORA}" | "${SPCD_OS_ROCKY}" | \ "${SPCD_OS_ARCH}") SPCD_OS_VERSION=$(spcd_os_grep VERSION_ID | sed "s|^\([0-9]\+\)\..*|\1|") ;; "${SPCD_OS_ALPINE}" | "${SPCD_OS_OPENSUSE}") SPCD_OS_VERSION=$(spcd_os_grep VERSION_ID | sed "s|^\([0-9]\+\.[0-9]\+\)\..*|\1|") ;; "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") SPCD_OS_VERSION="$(spcd_os_grep VERSION_CODENAME)" ;; *) ;; esac # check operating system version case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") case "${SPCD_OS_VERSION}" in "9" | "8") ;; *) spcd_error_os "SPCD_OS_VERSION" ;; esac ;; "${SPCD_OS_ALPINE}") case "${SPCD_OS_VERSION}" in "3.20" | "3.19") ;; *) spcd_error_os "SPCD_OS_VERSION" ;; esac ;; "${SPCD_OS_ARCH}") case "${SPCD_OS_VERSION}" in "20240818" | "20240101") ;; *) spcd_error_os "SPCD_OS_VERSION" ;; esac ;; "${SPCD_OS_DEBIAN}") case "${SPCD_OS_VERSION}" in "bookworm" | "bullseye") ;; *) spcd_error_os "SPCD_OS_VERSION" ;; esac ;; "${SPCD_OS_FEDORA}") case "${SPCD_OS_VERSION}" in "40" | "39") ;; *) spcd_error_os "SPCD_OS_VERSION" ;; esac ;; "${SPCD_OS_OPENSUSE}") case "${SPCD_OS_VERSION}" in "15.6" | "15.5") ;; *) spcd_error_os "SPCD_OS_VERSION" ;; esac ;; "${SPCD_OS_UBUNTU}") case "${SPCD_OS_VERSION}" in "noble" | "jammy") ;; *) spcd_error_os "SPCD_OS_VERSION" ;; esac ;; *) ;; esac spcd_split spcd_os_printenv "SPCD_OS_ID" "SPCD_OS_VERSION" # universal SPCD_DNS_FILE="/etc/resolv.conf" SPCD_PYTHON_ALIAS="python3" spcd_split spcd_os_printenv "SPCD_DNS_FILE" "SPCD_PYTHON_ALIAS" # set package manager case "${SPCD_OS_ID}" in "${SPCD_OS_ALPINE}") SPCD_PM="${SPCD_PM_APK}" ;; "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") SPCD_PM="${SPCD_PM_APT}" ;; "${SPCD_OS_ALMA}" | "${SPCD_OS_FEDORA}" | "${SPCD_OS_ROCKY}") SPCD_PM="${SPCD_PM_DNF}" ;; "${SPCD_OS_ARCH}") SPCD_PM="${SPCD_PM_PACMAN}" ;; "${SPCD_OS_OPENSUSE}") SPCD_PM="${SPCD_PM_ZYPPER}" ;; *) ;; esac # set package manager variables spcd_split spcd_os_printenv "SPCD_PM" case "${SPCD_PM}" in "${SPCD_PM_DNF}") SPCD_PM_HTTPS_PATH="/etc/dnf/dnf.conf.d/https.conf" SPCD_PM_HTTPS_TEXT="\ sslverify=False " ;; "${SPCD_PM_APK}") SPCD_PM_HTTPS_PATH="/etc/apk/repositories.d/https" SPCD_PM_HTTPS_TEXT="\ --no-verify " ;; "${SPCD_PM_PACMAN}") SPCD_PM_HTTPS_PATH="/etc/pacman.d/https.conf" SPCD_PM_HTTPS_TEXT="\ SSLVerify = No " ;; "${SPCD_PM_APT}") SPCD_PM_HTTPS_PATH="/etc/apt/apt.conf.d/https" SPCD_PM_HTTPS_TEXT="\ Acquire::https::Verify-Peer False; " ;; "${SPCD_PM_ZYPPER}") SPCD_PM_HTTPS_PATH="" SPCD_PM_HTTPS_TEXT="\ " ;; *) ;; esac spcd_split spcd_os_printenv "SPCD_PM_HTTPS_PATH" # specific case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}") SPCD_URL_DEFAULT="https://repo.almalinux.org/almalinux" ;; "${SPCD_OS_ALPINE}") SPCD_URL_DEFAULT="https://dl-cdn.alpinelinux.org/alpine" ;; "${SPCD_OS_ARCH}") SPCD_URL_DEFAULT="https://geo.mirror.pkgbuild.com" ;; "${SPCD_OS_DEBIAN}") SPCD_URL_DEFAULT="http://deb.debian.org/debian" ;; "${SPCD_OS_FEDORA}") SPCD_URL_DEFAULT="http://download.example/pub/fedora/linux/releases" ;; "${SPCD_OS_OPENSUSE}") SPCD_URL_DEFAULT="http://download.opensuse.org" ;; "${SPCD_OS_ROCKY}") SPCD_URL_DEFAULT="http://dl.rockylinux.org/\$contentdir" ;; "${SPCD_OS_UBUNTU}") SPCD_URL_DEFAULT="http://archive.ubuntu.com/ubuntu" ;; *) ;; esac SPCD_URL_CHOSEN="${SPCD_URL_DEFAULT}" case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}") [ -n "${SPCD_URL_ALMA}" ] && SPCD_URL_CHOSEN="${SPCD_URL_ALMA}" ;; "${SPCD_OS_ALPINE}") [ -n "${SPCD_URL_ALPINE}" ] && SPCD_URL_CHOSEN="${SPCD_URL_ALPINE}" ;; "${SPCD_OS_ARCH}") [ -n "${SPCD_URL_ARCH}" ] && SPCD_URL_CHOSEN="${SPCD_URL_ARCH}" ;; "${SPCD_OS_DEBIAN}") [ -n "${SPCD_URL_DEBIAN}" ] && SPCD_URL_CHOSEN="${SPCD_URL_DEBIAN}" || SPCD_URL_CHOSEN="https://deb.debian.org/debian" ;; "${SPCD_OS_FEDORA}") [ -n "${SPCD_URL_FEDORA}" ] && SPCD_URL_CHOSEN="${SPCD_URL_FEDORA}" || SPCD_URL_CHOSEN="https://rpmfind.net/linux/fedora/linux/releases" ;; "${SPCD_OS_OPENSUSE}") [ -n "${SPCD_URL_OPENSUSE}" ] && SPCD_URL_CHOSEN="${SPCD_URL_OPENSUSE}" || SPCD_URL_CHOSEN="https://download.opensuse.org" ;; "${SPCD_OS_ROCKY}") [ -n "${SPCD_URL_ROCKY}" ] && SPCD_URL_CHOSEN="${SPCD_URL_ROCKY}" || SPCD_URL_CHOSEN="https://dl.rockylinux.org/\$contentdir" ;; "${SPCD_OS_UBUNTU}") [ -n "${SPCD_URL_UBUNTU}" ] && SPCD_URL_CHOSEN="${SPCD_URL_UBUNTU}" || SPCD_URL_CHOSEN="https://ubuntu.mirrors.ovh.net/ubuntu" ;; *) ;; esac spcd_split spcd_os_printenv "SPCD_URL_DEFAULT" "SPCD_URL_CHOSEN" # set python command & package case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") SPCD_PYTHON_COMMAND="python3.12" SPCD_PYTHON_PACKAGE="python3.12" ;; "${SPCD_OS_ALPINE}") case "${SPCD_OS_VERSION}" in "3.20") SPCD_PYTHON_COMMAND="python3.12" ;; "3.19") SPCD_PYTHON_COMMAND="python3.11" ;; *) ;; esac SPCD_PYTHON_PACKAGE="python3" ;; "${SPCD_OS_ARCH}") SPCD_PYTHON_COMMAND="python3.12" SPCD_PYTHON_PACKAGE="python" ;; "${SPCD_OS_DEBIAN}") case "${SPCD_OS_VERSION}" in "bookworm") SPCD_PYTHON_COMMAND="python3.11" ;; "bullseye") SPCD_PYTHON_COMMAND="python3.9" ;; *) ;; esac SPCD_PYTHON_PACKAGE="python3" ;; "${SPCD_OS_FEDORA}") SPCD_PYTHON_COMMAND="python3.12" SPCD_PYTHON_PACKAGE="python3" ;; "${SPCD_OS_OPENSUSE}") case "${SPCD_OS_VERSION}" in "15.6") SPCD_PYTHON_COMMAND="python3.12" SPCD_PYTHON_PACKAGE="python312" ;; "15.5") SPCD_PYTHON_COMMAND="python3.11" SPCD_PYTHON_PACKAGE="python311" ;; *) ;; esac ;; "${SPCD_OS_UBUNTU}") case "${SPCD_OS_VERSION}" in "noble") SPCD_PYTHON_COMMAND="python3.12" ;; "jammy") SPCD_PYTHON_COMMAND="python3.10" ;; *) ;; esac SPCD_PYTHON_PACKAGE="python3" ;; *) ;; esac spcd_split spcd_os_printenv "SPCD_PYTHON_COMMAND" "SPCD_PYTHON_PACKAGE" # set python packages case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_FEDORA}" | "${SPCD_OS_ROCKY}" | \ "${SPCD_OS_OPENSUSE}") SPCD_PYTHON_PACKAGES="/usr/lib64/${SPCD_PYTHON_COMMAND}/site-packages" ;; "${SPCD_OS_ALPINE}" | "${SPCD_OS_ARCH}") SPCD_PYTHON_PACKAGES="/usr/lib/${SPCD_PYTHON_COMMAND}/site-packages" ;; "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") SPCD_PYTHON_PACKAGES="/usr/lib/python3/dist-packages" ;; *) ;; esac SPCD_PYTHON_VENV_PACKAGES="\ ${SPCD_PYTHON_VENV}/lib/${SPCD_PYTHON_COMMAND}/site-packages" spcd_split spcd_os_printenv "SPCD_PYTHON_PACKAGES" "SPCD_PYTHON_VENV_PACKAGES" # downloads SPCD_DL="$(mktemp --directory)" spcd_split spcd_os_printenv "SPCD_DL" } spcd_environment_list_workspace() { spcd_step "List workspace" spcd_lwd__path="$(realpath .)" spcd_os_ls "${spcd_lwd__path}" } # ╭───────┬───────────╮ # │ steps │ functions │ # ╰───────┴───────────╯ spcd_clean_cache() { case "${SPCD_PM}" in "${SPCD_PM_APK}") apk cache purge ;; "${SPCD_PM_APT}") apt-get clean ;; "${SPCD_PM_DNF}") dnf clean all ;; "${SPCD_PM_PACMAN}") pacman --sync --clean --noconfirm ;; "${SPCD_PM_ZYPPER}") zypper clean ;; *) ;; esac } spcd_install_package() { case "${SPCD_PM}" in "${SPCD_PM_APK}") apk add "${1}" ;; "${SPCD_PM_APT}") apt-get install --assume-yes "${1}" ;; "${SPCD_PM_DNF}") dnf install --assumeyes "${1}" ;; "${SPCD_PM_PACMAN}") pacman --sync --noconfirm "${1}" ;; "${SPCD_PM_ZYPPER}") zypper --non-interactive install "${1}" ;; *) ;; esac spcd_clean_cache } spcd_query_package() { case "${SPCD_PM}" in "${SPCD_PM_APK}") apk info "${1}" ;; "${SPCD_PM_APT}") dpkg-query --show "${1}" ;; "${SPCD_PM_DNF}") rpm --query "${1}" ;; "${SPCD_PM_PACMAN}") pacman --query "${1}" ;; "${SPCD_PM_ZYPPER}") rpm --query "${1}" ;; *) ;; esac } # ╭───────┬─────╮ # │ steps │ dns │ # ╰───────┴─────╯ spcd_dns() { spcd_step "DNS" while true; do spcd_sdr__index=$((spcd_sdr__index + 1)) eval "spcd_sdr__value=\"\${SPCD_DNS_${spcd_sdr__index}}\"" [ -n "${spcd_sdr__value}" ] || break spcd_sdr__text="${spcd_sdr__text}\ nameserver ${spcd_sdr__value} " done spcd_os_write "${SPCD_DNS_FILE}" "${spcd_sdr__text}" } # ╭───────┬──────────╮ # │ steps │ packages │ # ╰───────┴──────────╯ spcd_packages_set_repositories() { spcd_step "Set repositories" case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}") case "${SPCD_OS_VERSION}" in "8") spcd_spr__file="/etc/yum.repos.d/almalinux.repo" ;; "9") spcd_spr__file="/etc/yum.repos.d/almalinux-baseos.repo" ;; *) ;; esac spcd_os_sed "${spcd_spr__file}" \ "|^mirrorlist|# mirrorlist|" \ "|${SPCD_URL_DEFAULT}|${SPCD_URL_CHOSEN}|" \ "|^# baseurl|baseurl|" ;; "${SPCD_OS_ALPINE}") spcd_spr__file="/etc/apk/repositories" spcd_os_write "${spcd_spr__file}" "\ ${SPCD_URL_CHOSEN}/v${SPCD_OS_VERSION}/main ${SPCD_URL_CHOSEN}/v${SPCD_OS_VERSION}/community " ;; "${SPCD_OS_DEBIAN}") spcd_spr__file="/etc/apt/sources.list" spcd_os_write "${spcd_spr__file}" "\ deb ${SPCD_URL_CHOSEN} ${SPCD_OS_VERSION} main deb ${SPCD_URL_CHOSEN} ${SPCD_OS_VERSION}-backports main deb ${SPCD_URL_CHOSEN} ${SPCD_OS_VERSION}-updates main deb ${SPCD_URL_CHOSEN}-security ${SPCD_OS_VERSION}-security main " ;; "${SPCD_OS_OPENSUSE}") for spcd_spr__file in \ "backports-update" \ "non-oss" \ "oss" \ "sle-update" \ "update-non-oss" \ "update" \ "openh264"; do spcd_os_sed "/etc/zypp/repos.d/repo-${spcd_spr__file}.repo" \ "|${SPCD_URL_DEFAULT}|${SPCD_URL_CHOSEN}|" done ;; "${SPCD_OS_ROCKY}") case "${SPCD_OS_VERSION}" in "8") spcd_spr__file="/etc/yum.repos.d/Rocky-BaseOS.repo" ;; "9") spcd_spr__file="/etc/yum.repos.d/rocky.repo" ;; *) ;; esac spcd_os_sed "${spcd_spr__file}" \ "|^mirrorlist|# mirrorlist|" \ "|${SPCD_URL_DEFAULT}|${SPCD_URL_CHOSEN}|" \ "|^#baseurl|baseurl|" ;; "${SPCD_OS_UBUNTU}") spcd_spr__file="/etc/apt/sources.list" spcd_os_write "${spcd_spr__file}" "\ deb ${SPCD_URL_CHOSEN} ${SPCD_OS_VERSION} main universe deb ${SPCD_URL_CHOSEN} ${SPCD_OS_VERSION}-backports main universe deb ${SPCD_URL_CHOSEN} ${SPCD_OS_VERSION}-updates main universe deb ${SPCD_URL_CHOSEN} ${SPCD_OS_VERSION}-security main universe " ;; *) ;; esac } spcd_packages_set_configuration() { spcd_step "Set configuration" case "${SPCD_PM}" in "${SPCD_PM_DNF}") spcd_os_write "/etc/dnf/dnf.conf" "\ [main] best=True clean_requirements_on_remove=True gpgcheck=1 installonly_limit=3 skip_if_unavailable=False " ;; "${SPCD_PM_APK}") ;; "${SPCD_PM_PACMAN}") ;; "${SPCD_PM_APT}") spcd_os_write "/etc/apt/apt.conf.d/apt.conf" "\ Acquire::Check-Valid-Until True; APT::Get::Show-Versions True; APT::Install-Recommends False; APT::Install-Suggests False; Dir::Etc::SourceParts \"\"; " ;; "${SPCD_PM_ZYPPER}") ;; *) ;; esac case "${SPCD_OS_ID}" in "${SPCD_OS_ARCH}") pacman-key --init ;; "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") export DEBIAN_FRONTEND="noninteractive" ;; *) ;; esac } spcd_packages_trust_https() { spcd_step "Trust HTTPS" if [ -n "${SPCD_CA_1}" ] || [ "${SPCD_PM}" = "${SPCD_PM_APT}" ]; then spcd_os_mkdir "$(dirname "${SPCD_PM_HTTPS_PATH}")" spcd_os_write "${SPCD_PM_HTTPS_PATH}" "${SPCD_PM_HTTPS_TEXT}" fi } spcd_packages_update_catalog() { spcd_step "Update catalog" case "${SPCD_PM}" in "${SPCD_PM_APK}") apk update ;; "${SPCD_PM_APT}") apt-get update ;; "${SPCD_PM_DNF}") dnf makecache ;; "${SPCD_PM_PACMAN}") pacman --sync --refresh ;; "${SPCD_PM_ZYPPER}") zypper refresh ;; *) ;; esac } spcd_packages_install_tools() { spcd_step "Install tools" case "${SPCD_PM}" in "${SPCD_PM_APT}") spcd_install_package "apt-utils" ;; *) ;; esac } # ╭───────┬────╮ # │ steps │ ca │ # ╰───────┴────╯ spcd_ca_install_package() { spcd_step "Install package" spcd_install_package "ca-certificates" } spcd_ca_write_certificates() { spcd_step "Write certificates" case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_FEDORA}" | "${SPCD_OS_ROCKY}") spcd_wcc__root="/etc/pki/ca-trust/source/anchors" ;; "${SPCD_OS_ALPINE}" | "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") spcd_wcc__root="/usr/local/share/ca-certificates" ;; "${SPCD_OS_ARCH}") spcd_wcc__root="/etc/ca-certificates/trust-source/anchors" ;; "${SPCD_OS_OPENSUSE}") spcd_wcc__root="/etc/pki/trust/anchors" ;; *) ;; esac spcd_os_mkdir "${spcd_wcc__root}" while true; do spcd_wcc__index=$((spcd_wcc__index + 1)) eval "spcd_wcc__text=\"\${SPCD_CA_${spcd_wcc__index}}\"" [ -n "${spcd_wcc__text}" ] || break spcd_wcc__path="${spcd_wcc__root}/${spcd_wcc__index}.crt" spcd_split spcd_os_write "${spcd_wcc__path}" "${spcd_wcc__text}" spcd_openssl_x509 "${spcd_wcc__path}" done } spcd_ca_update_certificates() { spcd_step "Update certificates" case "${SPCD_OS_ID}" in "${SPCD_OS_ARCH}" | \ "${SPCD_OS_ALMA}" | \ "${SPCD_OS_FEDORA}" | \ "${SPCD_OS_ROCKY}") update-ca-trust ;; "${SPCD_OS_ALPINE}" | \ "${SPCD_OS_DEBIAN}" | \ "${SPCD_OS_OPENSUSE}" | \ "${SPCD_OS_UBUNTU}") update-ca-certificates ;; *) ;; esac } # ╭───────┬──────────╮ # │ steps │ packages │ # ╰───────┴──────────╯ spcd_packages_verify_https() { spcd_step "Verify HTTPS" spcd_os_rm "${SPCD_PM_HTTPS_PATH}" } spcd_packages_upgrade_system() { spcd_step "Upgrade system" case "${SPCD_PM}" in "${SPCD_PM_APK}") apk upgrade ;; "${SPCD_PM_APT}") apt-get upgrade --assume-yes ;; "${SPCD_PM_DNF}") dnf upgrade --assumeyes ;; "${SPCD_PM_PACMAN}") pacman --sync --sysupgrade --noconfirm ;; "${SPCD_PM_ZYPPER}") zypper --non-interactive update ;; *) ;; esac } spcd_packages_install_dos2unix() { spcd_step "Install dos2unix" spcd_install_package "dos2unix" } spcd_packages_install_git() { spcd_step "Install Git" spcd_install_package "git" } # ╭───────┬────────╮ # │ steps │ python │ # ╰───────┴────────╯ spcd_python_install() { spcd_step "Install package" spcd_install_package "${SPCD_PYTHON_PACKAGE}" spcd_step "Link alias to command" spcd_python_ln "${SPCD_PYTHON_COMMAND}" # venv spcd_step_in "Virtual environment" spcd_step "Install package" case "${SPCD_OS_ID}" in "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") spcd_install_package "python3-venv" ;; *) ;; esac spcd_step "Configure PIP" spcd_os_write "/etc/pip.conf" "\ [global] index-url = ${SPCD_URL_PYTHON} " spcd_step "Create" "${SPCD_PYTHON_ALIAS}" -m "venv" "${SPCD_PYTHON_VENV}" spcd_step "Activate" export PATH="${SPCD_PYTHON_VENV_BINARIES}:${PATH}" export VIRTUAL_ENV="${SPCD_PYTHON_VENV}" spcd_step_out } spcd_python_modules() { spcd_step_in "Modules" spcd_ipm__target="${SPCD_PYTHON_VENV_PACKAGES}" spcd_step "List" spcd_os_ls "${spcd_ipm__target}" spcd_step "Main" spcd_ipm__path="$(spcd_python_pip "${SPCD_GIT_MAIN}")" # check matching of file and variable spcd_step "Check" spcd_ipm__script="${spcd_ipm__path}/bootstrap.sh" ls -l "${spcd_ipm__script}" spcd_ipm__check="${spcd_ipm__script}.${SPCD_CMD_SUM}" "${SPCD_CMD_SUM}" "${spcd_ipm__script}" >"${spcd_ipm__check}" printf "%s" "${SPCD}" >"${spcd_ipm__script}" ls -l "${spcd_ipm__script}" dos2unix "${spcd_ipm__script}" ls -l "${spcd_ipm__script}" "${SPCD_CMD_SUM}" -c "${spcd_ipm__check}" || spcd_error_ci "SPCD" spcd_step "Root" spcd_python_pip "${SPCD_GIT_ROOT}" spcd_step "List" spcd_os_ls "${spcd_ipm__target}" spcd_step_out } spcd_install_packages() { spcd_step_in "OS packages" # epel spcd_step "EPEL" case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") spcd_install_package "epel-release" [ -n "${SPCD_URL_EPEL}" ] && spcd_ip__epel="${SPCD_URL_EPEL}" || spcd_ip__epel="https://dl.fedoraproject.org" spcd_os_sed "/etc/yum.repos.d/epel.repo" \ "|^metalink|# metalink|" \ "|https://download.example|${spcd_ip__epel}|" \ "|^#baseurl|baseurl|" ;; *) ;; esac # graphviz spcd_step "GraphViz" spcd_install_package "graphviz" # openssh spcd_step "OpenSSH" case "${SPCD_PM}" in "${SPCD_PM_APK}" | "${SPCD_PM_APT}") spcd_install_package "openssh-client" ;; "${SPCD_PM_DNF}" | "${SPCD_PM_ZYPPER}") spcd_install_package "openssh-clients" ;; "${SPCD_PM_PACMAN}") spcd_install_package "openssh" ;; *) ;; esac # plantuml spcd_step "PlantUML" spcd_install_package "plantuml" # rsync spcd_step "Rsync" spcd_install_package "rsync" # shell check spcd_step "ShellCheck" case "${SPCD_PM}" in "${SPCD_PM_DNF}" | "${SPCD_PM_ZYPPER}") spcd_install_package "ShellCheck" ;; *) spcd_install_package "shellcheck" ;; esac # shfmt spcd_step "ShellFormat" case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") ;; "${SPCD_OS_DEBIAN}") case "${SPCD_OS_VERSION}" in "bullseye") ;; *) spcd_install_package "shfmt" ;; esac ;; *) spcd_install_package "shfmt" ;; esac spcd_step_out } spcd_python_write_module() { spcd_step "Write module" for spcd_wpm__variable in \ OS_ID OS_VERSION \ PROJECT_ROOT PROJECT_PATH PROJECT_NAME \ PYTHON_VENV_BINARIES PYTHON_VENV_PACKAGES \ OPEN DOWN VERT SPLT __UP SHUT; do spcd_wpm__value="$(spcd_os_printenv "SPCD_${spcd_wpm__variable}")" spcd_wpm__text="${spcd_wpm__text}${spcd_wpm__value} " done spcd_wpm__index=$((__SPCD_STEP_1_INDEX + 1)) for spcd_wpm__root in \ "${SPCD_PYTHON_PACKAGES}" "${SPCD_PYTHON_VENV_PACKAGES}"; do spcd_os_write "${spcd_wpm__root}/env.py" "${spcd_wpm__text} SPCD_STEP = ${spcd_wpm__index} " done } spcd_python_switch() { spcd_step "Switch" spcd_stp__name="$(basename "${SPCD_GIT_MAIN}")" spcd_stp__path="$(realpath "${0}")" echo "\ ${spcd_stp__path} ↓ ${SPCD_PYTHON_ALIAS} / ${spcd_stp__name}" "${SPCD_PYTHON_ALIAS}" -m "${spcd_stp__name}" } # ╭──────╮ # │ main │ # ╰──────╯ spcd_main() { # environment spcd_step_in "Environment" spcd_environment_set_variables spcd_environment_list_workspace spcd_step_out # dns spcd_dns # packages spcd_step_in "Packages" spcd_packages_set_repositories spcd_packages_set_configuration spcd_packages_trust_https spcd_packages_update_catalog spcd_packages_install_tools spcd_step_out # ca spcd_step_in "CA" spcd_ca_install_package spcd_ca_write_certificates spcd_ca_update_certificates spcd_step_out # packages spcd_step_in "Packages" spcd_packages_verify_https spcd_packages_update_catalog spcd_packages_upgrade_system spcd_packages_install_dos2unix spcd_packages_install_git spcd_step_out # python spcd_step_in "Python" spcd_python_install spcd_python_modules spcd_install_packages spcd_python_write_module spcd_python_switch } spcd_main