#! /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" # ╭──────────╮ # │ internal │ # ╰──────────╯ spcd_fill() { spcd_fill__index=${1} while [ "${spcd_fill__index}" -gt 0 ]; do printf "%s" "${2}" spcd_fill__index=$((spcd_fill__index - 1)) done } # ╭──────────┬────────╮ # │ internal │ 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_close() { spcd_banner_append \ "${SPCD_BANNER_DOWN_AND_LEFT}" \ "${SPCD_BANNER_VERTICAL}" \ "${SPCD_BANNER_UP_AND_LEFT}" } 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_unset spcd_banner_add_index spcd_banner_add "S" # 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_close spcd_banner_echo spcd_banner_unset } spcd_banner_split() { spcd_banner_append \ "${SPCD_BANNER_DOWN_AND_HORIZONTAL}" \ "${SPCD_BANNER_VERTICAL}" \ "${SPCD_BANNER_UP_AND_HORIZONTAL}" } spcd_banner_unset() { unset \ SPCD_BANNER_TOP \ SPCD_BANNER_MIDDLE \ SPCD_BANNER_BOTTOM } # ╭──────────┬───────╮ # │ internal │ error │ # ╰──────────┴───────╯ SPCD_ERROR_CI=1 SPCD_ERROR_OS=2 # ╭──────────┬───────╮ # │ internal │ frame │ # ╰──────────┴───────╯ SPCD_FRAME_DOWN_AND_RIGHT="╭" SPCD_FRAME_UP_AND_RIGHT="╰" spcd_frame_open() { echo "${SPCD_FRAME_DOWN_AND_RIGHT}${1}" } spcd_frame_shut() { echo "${SPCD_FRAME_UP_AND_RIGHT}${1}" } # ╭──────────┬────╮ # │ internal │ os │ # ╰──────────┴────╯ spcd_os_cat() { spcd_cat__file="${1}" if [ -n "${spcd_cat__file}" ]; then spcd_frame_open "${spcd_cat__file}" cat "${spcd_cat__file}" || exit spcd_frame_shut "${spcd_cat__file}" fi } # ╭──────────┬──────╮ # │ internal │ rule │ # ╰──────────┴──────╯ SPCD_RULE_HORIZONTAL="─" SPCD_RULE_LEFT="╴" SPCD_RULE_RIGHT="╶" # ╭──────────┬──────╮ # │ internal │ step │ # ╰──────────┴──────╯ SPCD_STEP_LEVEL=1 spcd_step_wipe() { unset \ "SPCD_STEP_${SPCD_STEP_LEVEL}_INDEX" \ "SPCD_STEP_${SPCD_STEP_LEVEL}_LABEL" } # ╭───────────┬───────╮ # │ 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 │ 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() { spcd_os_rm__path="${1}" if [ -e "${spcd_os_rm__path}" ]; then echo "← ${spcd_os_rm__path}" rm -r "${spcd_os_rm__path}" || exit fi } # ╭───────────┬───────╮ # │ functions │ split │ # ╰───────────┴───────╯ spcd_split() { echo "${SPCD_RULE_RIGHT}${SPCD_RULE_HORIZONTAL}${SPCD_RULE_LEFT}" } # ╭───────────┬──────╮ # │ functions │ step │ # ╰───────────┴──────╯ spcd_step() { if [ -n "${1}" ]; then 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 │ 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_PF_APK="apk" SPCD_PF_DEB="deb" SPCD_PF_PKG="pkg" SPCD_PF_RPM="rpm" 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 │ env │ # ╰───────┴─────╯ spcd_set_environment_variables() { spcd_step "Set environment 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 path SPCD_PATH="$(realpath "${0}")" spcd_os_printenv "SPCD_PATH" # 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_PKG_CA="ca-certificates" SPCD_PKG_DOS2UNIX="dos2unix" SPCD_PKG_GIT="git" SPCD_PYTHON_ALIAS="python3" spcd_split spcd_os_printenv "SPCD_DNS_FILE" \ "SPCD_PKG_CA" "SPCD_PKG_DOS2UNIX" "SPCD_PKG_GIT" "SPCD_PYTHON_ALIAS" # set ca command & root case "${SPCD_OS_ID}" in "${SPCD_OS_ALMA}" | "${SPCD_OS_FEDORA}" | "${SPCD_OS_ROCKY}") SPCD_CA_ROOT="/etc/pki/ca-trust/source/anchors" SPCD_CMD_CA="update-ca-trust" ;; "${SPCD_OS_ALPINE}") SPCD_CA_ROOT="/usr/local/share/ca-certificates" SPCD_CMD_CA="update-ca-certificates" ;; "${SPCD_OS_ARCH}") SPCD_CA_ROOT="/etc/ca-certificates/trust-source/anchors" SPCD_CMD_CA="update-ca-trust" ;; "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") SPCD_CA_ROOT="/usr/local/share/ca-certificates" SPCD_CMD_CA="update-ca-certificates" ;; "${SPCD_OS_OPENSUSE}") SPCD_CA_ROOT="/etc/pki/trust/anchors" SPCD_CMD_CA="update-ca-certificates" ;; *) ;; esac spcd_split spcd_os_printenv "SPCD_CA_ROOT" "SPCD_CMD_CA" # 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 format case "${SPCD_PM}" in "${SPCD_PM_APK}") SPCD_PF="${SPCD_PF_APK}" ;; "${SPCD_PM_APT}") SPCD_PF="${SPCD_PF_DEB}" ;; "${SPCD_PM_PACMAN}") SPCD_PF="${SPCD_PF_PKG}" ;; "${SPCD_PM_DNF}" | "${SPCD_PM_ZYPPER}") SPCD_PF="${SPCD_PF_RPM}" ;; *) ;; esac # set package manager variables spcd_split spcd_os_printenv "SPCD_PF" "SPCD_PM" case "${SPCD_PM}" in "${SPCD_PM_DNF}") SPCD_PM_CLEAN="dnf clean all" SPCD_PM_INSTALL="dnf install --assumeyes" SPCD_PM_QUERY="rpm --query" SPCD_PM_UPDATE="dnf makecache" SPCD_PM_UPGRADE="dnf upgrade --assumeyes" SPCD_PKG_PKG="" SPCD_PM_CONF_PATH="/etc/dnf/dnf.conf" SPCD_PM_CONF_TEXT="\ [main] best=True clean_requirements_on_remove=True gpgcheck=1 installonly_limit=3 skip_if_unavailable=False " SPCD_PM_HTTPS_PATH="/etc/dnf/dnf.conf.d/https.conf" SPCD_PM_HTTPS_TEXT="\ sslverify=False " ;; "${SPCD_PM_APK}") SPCD_PM_CLEAN="apk cache purge" SPCD_PM_INSTALL="apk add" SPCD_PM_QUERY="apk info" SPCD_PM_UPDATE="apk update" SPCD_PM_UPGRADE="apk upgrade" SPCD_PKG_PKG="" SPCD_PM_CONF_PATH="" SPCD_PM_CONF_TEXT="" SPCD_PM_HTTPS_PATH="/etc/apk/repositories.d/https" SPCD_PM_HTTPS_TEXT="\ --no-verify " ;; "${SPCD_PM_PACMAN}") SPCD_PM_CLEAN="pacman --sync --clean --noconfirm" SPCD_PM_INSTALL="pacman --sync --noconfirm" SPCD_PM_QUERY="pacman --query" SPCD_PM_UPDATE="pacman --sync --refresh" SPCD_PM_UPGRADE="pacman --sync --sysupgrade --noconfirm" SPCD_PKG_PKG="" SPCD_PM_CONF_PATH="" SPCD_PM_CONF_TEXT="" SPCD_PM_HTTPS_PATH="/etc/pacman.d/https.conf" SPCD_PM_HTTPS_TEXT="\ SSLVerify = No " ;; "${SPCD_PM_APT}") SPCD_PM_CLEAN="apt-get clean" SPCD_PM_INSTALL="apt-get install --assume-yes" SPCD_PM_QUERY="dpkg-query --show" SPCD_PM_UPDATE="apt-get update" SPCD_PM_UPGRADE="apt-get upgrade --assume-yes" SPCD_PKG_PKG="apt-utils" SPCD_PM_CONF_PATH="/etc/apt/apt.conf.d/apt.conf" SPCD_PM_CONF_TEXT="\ Acquire::Check-Valid-Until True; APT::Get::Show-Versions True; APT::Install-Recommends False; APT::Install-Suggests False; Dir::Etc::SourceParts \"\"; " SPCD_PM_HTTPS_PATH="/etc/apt/apt.conf.d/https" SPCD_PM_HTTPS_TEXT="\ Acquire::https::Verify-Peer False; " ;; "${SPCD_PM_ZYPPER}") SPCD_PM_CLEAN="zypper clean" SPCD_PM_INSTALL="zypper --non-interactive install" SPCD_PM_QUERY="rpm --query" SPCD_PM_UPDATE="zypper refresh" SPCD_PM_UPGRADE="zypper --non-interactive update" SPCD_PKG_PKG="" SPCD_PM_CONF_PATH="" SPCD_PM_CONF_TEXT="\ " SPCD_PM_HTTPS_PATH="" SPCD_PM_HTTPS_TEXT="\ " ;; *) ;; esac spcd_split spcd_os_printenv "SPCD_PM_CLEAN" \ "SPCD_PM_INSTALL" "SPCD_PM_QUERY" "SPCD_PM_UPDATE" "SPCD_PM_UPGRADE" spcd_split spcd_os_printenv "SPCD_PKG_PKG" "SPCD_PM_CONF_PATH" "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/${SPCD_PYTHON_ALIAS}/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" # variables # certificate authorities [ -n "${SPCD_CA_1}" ] && SPCD_CA=true # downloads SPCD_DL="$(mktemp --directory)" spcd_split spcd_os_printenv "SPCD_CA" "SPCD_DL" } spcd_list_working_directory() { spcd_step "List working directory" spcd_lwd__path="$(realpath .)" spcd_os_ls "${spcd_lwd__path}" } # ╭───────┬─────╮ # │ steps │ pkg │ # ╰───────┴─────╯ spcd_set_packages_repositories() { spcd_step "Set packages 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_sed "${spcd_spr__file}" \ "|^mirrorlist|# mirrorlist|" \ "|${SPCD_URL_DEFAULT}|${SPCD_URL_CHOSEN}|" \ "|^# baseurl|baseurl|" ;; "${SPCD_OS_ALPINE}") spcd_spr__file="/etc/apk/repositories" spcd_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_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_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_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_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_set_packages_configuration() { spcd_step "Set packages configuration" spcd_write "${SPCD_PM_CONF_PATH}" "${SPCD_PM_CONF_TEXT}" case "${SPCD_OS_ID}" in "${SPCD_OS_ARCH}") pacman-key --init ;; "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") export DEBIAN_FRONTEND="noninteractive" ;; *) ;; esac } # agnostic steps spcd_set_https_verification_off() { if [ -n "${SPCD_CA}" ] || [ "${SPCD_PM}" = "${SPCD_PM_APT}" ]; then spcd_step "Set HTTPS verification off" spcd_os_mkdir "$(dirname "${SPCD_PM_HTTPS_PATH}")" spcd_write "${SPCD_PM_HTTPS_PATH}" "${SPCD_PM_HTTPS_TEXT}" fi } spcd_set_dns_resolving() { spcd_step "Set DNS resolving" 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_write "${SPCD_DNS_FILE}" "${spcd_sdr__text}" } spcd_update_packages_catalog() { spcd_step "Update packages catalog" ${SPCD_PM_UPDATE} || exit } spcd_install_packages_tools() { spcd_step "Install packages tools" spcd_install_package "${SPCD_PKG_PKG}" } # ╭───────┬────╮ # │ steps │ ca │ # ╰───────┴────╯ spcd_install_ca_certificates() { spcd_step "Install CA" spcd_install_package "${SPCD_PKG_CA}" } spcd_write_ca_certificates() { spcd_step "Write CA certificates" spcd_os_mkdir "${SPCD_CA_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_CA_ROOT}/${spcd_wcc__index}.crt" spcd_split spcd_write "${spcd_wcc__path}" "${spcd_wcc__text}" spcd_openssl "${spcd_wcc__path}" done } spcd_update_ca_certificates() { spcd_step "Update CA certificates" ${SPCD_CMD_CA} || exit } # ╭───────┬─────╮ # │ steps │ pkg │ # ╰───────┴─────╯ spcd_set_https_verification_on() { spcd_step "Set HTTPS verification on" spcd_os_rm "${SPCD_PM_HTTPS_PATH}" } spcd_upgrade_packages() { spcd_step "Upgrade packages" ${SPCD_PM_UPGRADE} || exit } spcd_install_dos2unix() { spcd_step "Install dos2unix" spcd_install_package "${SPCD_PKG_DOS2UNIX}" } spcd_install_git() { spcd_step "Install Git" spcd_install_package "${SPCD_PKG_GIT}" } # ╭───────┬────────╮ # │ steps │ python │ # ╰───────┴────────╯ spcd_install_python() { spcd_step_in "Install Python" spcd_install_package "${SPCD_PYTHON_PACKAGE}" spcd_step "Link alias to command" spcd_ln_python "${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_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_step_out } spcd_install_python_modules() { spcd_step_in "Python modules" spcd_ipm__target="${SPCD_PYTHON_VENV_PACKAGES}" spcd_step "List" spcd_os_ls "${spcd_ipm__target}" spcd_step "Main" spcd_ipm__path="$(spcd_pip_install "${SPCD_GIT_MAIN}")" # check matching of file and variable spcd_step "Check" spcd_ipm__script="${spcd_ipm__path}/main.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_pip_install "${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_sed "/etc/yum.repos.d/epel.repo" \ "|^metalink|# metalink|" \ "|https://download.example|${spcd_ip__epel}|" \ "|^#baseurl|baseurl|" ;; *) ;; esac # bats spcd_step "BATS" spcd_install_package "bats" # 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_PF}" in "${SPCD_PF_RPM}") 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_write_python_module() { spcd_step "Write Python 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 for spcd_wpm__root in \ "${SPCD_PYTHON_PACKAGES}" "${SPCD_PYTHON_VENV_PACKAGES}"; do spcd_write "${spcd_wpm__root}/env.py" "${spcd_wpm__text} SPCD_STEP = $((SPCD_STEP + 1)) " done } spcd_switch_to_python() { spcd_step "Switch to Python" spcd_stp__name="$(basename "${SPCD_GIT_MAIN}")" echo "\ ${SPCD_PATH} ↓ ${SPCD_PYTHON_ALIAS} / ${spcd_stp__name}" "${SPCD_PYTHON_ALIAS}" -m "${spcd_stp__name}" } # ╭───────────╮ # │ functions │ # ╰───────────╯ spcd_install_package() { spcd_install_package__name="${1}" if [ -n "${spcd_install_package__name}" ]; then ${SPCD_PM_INSTALL} "${spcd_install_package__name}" || exit ${SPCD_PM_CLEAN} || exit fi } spcd_ln_python() { spcd_ln_python__command="${1}" if [ -n "${spcd_ln_python__command}" ]; then echo "→ ${SPCD_PYTHON_ALIAS} → ${spcd_ln_python__command}" ln -f -s "${spcd_ln_python__command}" \ "/usr/bin/${SPCD_PYTHON_ALIAS}" || exit fi } spcd_openssl() { spcd_openssl__file="${1}" if [ -f "${spcd_openssl__file}" ]; then openssl x509 \ -in "${spcd_openssl__file}" \ -noout -text || exit fi } spcd_pip_install() { if [ -n "${1}" ]; then spcd_pi__name="$(basename "${1}")" spcd_pi__path="$(spcd_git_clone "${1}")" spcd_pi__path="${spcd_pi__path}/${spcd_pi__name}" spcd_pi__target="${SPCD_PYTHON_VENV_PACKAGES}" cp --recursive "${spcd_pi__path}" "${spcd_pi__target}" echo "${spcd_pi__target}/${spcd_pi__name}" fi } spcd_sed() { spcd_sed__file="${1}" shift if [ -f "${spcd_sed__file}" ]; then spcd_os_cat "${spcd_sed__file}" for spcd_sed__regex in "${@}"; do sed --in-place "s${spcd_sed__regex}g" "${spcd_sed__file}" && spcd_os_cat "${spcd_sed__file}" || exit done fi } spcd_write() { spcd_write__file="${1}" spcd_write__text="${2}" if [ -n "${spcd_write__file}" ]; then [ -f "${spcd_write__file}" ] && spcd_os_cat "${spcd_write__file}" echo "→ ${spcd_write__file}" printf "%s" "${spcd_write__text}" >"${spcd_write__file}" || exit spcd_os_cat "${spcd_write__file}" fi } # ╭──────╮ # │ main │ # ╰──────╯ spcd_main() { # env spcd_set_environment_variables spcd_list_working_directory # pkg spcd_set_packages_repositories spcd_set_packages_configuration # spcd_set_https_verification_off spcd_set_dns_resolving spcd_update_packages_catalog spcd_install_packages_tools # ca spcd_install_ca_certificates spcd_write_ca_certificates spcd_update_ca_certificates # pkg spcd_set_https_verification_on spcd_update_packages_catalog spcd_upgrade_packages spcd_install_dos2unix spcd_install_git # python spcd_install_python spcd_install_python_modules spcd_install_packages spcd_write_python_module spcd_switch_to_python } spcd_main