diff --git a/readme.md b/readme.md index f8d9ebc..df9ea36 100644 --- a/readme.md +++ b/readme.md @@ -150,31 +150,31 @@ Handle project workflows in a unified way: #### Latest -| os | https | updt-ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | -|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:| -| Arch 20240818 | ☑ | ☑ | 3.12 | 12.0 | 1.2023.13 | 0.10 | 2.1.8 | 3.8 | -| Alpine 3.20 | ☑ | ☐ | 3.12 | 9.0 | 1.2024.4 | 0.10 | 2.1.8 | 3.8 | -| Fedora 40 | ☑ | ☑ | 3.12 → 3.13 | 9.0 | 1.2024.6 | 0.9 | 2.1.6 | 3.7 | -| Debian Bookworm | ☐ | ☐ | 3.11 | 2.42 | 1.2020.2 | 0.9 | 2.1.8 | 3.6 | -| OpenSUSE 15.6 | ☐ | ☑ | 3.6 → 3.12 | 2.48 | 1.2020.9 | 0.8 | 2.1.6 | 3.5 | -| Ubuntu Noble | ☐ | ☐ | 3.12 | u2.42 | u1.2020.2 | u0.9 | 2.1.8 | u3.8 | -| Alma / Rocky 9 | ☑ | ☑ | 3.9 → 3.12 | 2.44 | e1.2024.6 | e0.8 | | | +| os | https | up ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | gource | ffmpeg | +|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:|-----:|-------:| +| Arch 20240818 | ☑ | ☑ | 3.12 | 12.0 | 1.2023.13 | 0.10 | 2.1.8 | 3.8 | 0.54 | 7.0.2 | +| Alpine 3.20 | ☑ | ☐ | 3.12 | 9.0 | 1.2024.4 | 0.10 | 2.1.8 | 3.8 | 0.54 | 6.1.1 | +| Fedora 40 | ☑ | ☑ | 3.12 → 3.13 | 9.0 | 1.2024.6 | 0.9 | 2.1.6 | 3.7 | 0.55 | 6.1.2 | +| Debian Bookworm | ☐ | ☐ | 3.11 | 2.42 | 1.2020.2 | 0.9 | 2.1.8 | 3.6 | 0.54 | 5.1.6 | +| OpenSUSE 15.6 | ☐ | ☑ | 3.6 → 3.12 | 2.48 | 1.2020.9 | 0.8 | 2.1.6 | 3.5 | 0.54 | 4.4.4 | +| Ubuntu Noble | ☐ | ☐ | 3.12 | u2.42 | u1.2020.2 | u0.9 | 2.1.8 | u3.8 | 0.54 | 6.1.1 | +| Alma / Rocky 9 | ☑ | ☑ | 3.9 → 3.12 | 2.44 | e1.2024.6 | e0.8 | | | | e5.1.4 | #### Previous -| os | https | updt-ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | -|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:| -| Alpine 3.19 | ☑ | ☐ | 3.11 | 9.0 | 1.2023.12 | 0.9 | 2.1.8 | 3.7 | -| Fedora 39 | ☑ | ☑ | 3.12 → 3.13 | 8.1 | 1.2024.6 | 0.9 | 2.1.6 | 3.5 | -| OpenSUSE 15.5 | ☐ | ☑ | 3.6 → 3.11 | 2.48 | 1.2020.9 | 0.8 | 2.1.6 | 3.5 | -| Alma / Rocky 8 | ☑ | ☑ | 3.6 → 3.12 | 2.40 | e1.2024.6 | e0.6 | | | +| os | https | up ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | gource | ffmpeg | +|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:|-----:|-------:| +| Alpine 3.19 | ☑ | ☐ | 3.11 | 9.0 | 1.2023.12 | 0.9 | 2.1.8 | 3.7 | 0.54 | 6.1.1 | +| Fedora 39 | ☑ | ☑ | 3.12 → 3.13 | 8.1 | 1.2024.6 | 0.9 | 2.1.6 | 3.5 | 0.55 | 6.1.1 | +| OpenSUSE 15.5 | ☐ | ☑ | 3.6 → 3.11 | 2.48 | 1.2020.9 | 0.8 | 2.1.6 | 3.5 | 0.54 | 4.4.4 | +| Alma / Rocky 8 | ☑ | ☑ | 3.6 → 3.12 | 2.40 | e1.2024.6 | e0.6 | | | | | #### Older Python -| os | https | updt-ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | -|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:| -| Ubuntu Jammy | ☐ | ☐ | 3.10 | u2.42 | u1.2020.2 | u0.8 | 2.1.6 | u3.4 | -| Debian Bullseye | ☐ | ☐ | 3.9 | 2.42 | 1.2020.2 | 0.7 | 2.1.6 | | +| os | https | up ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | gource | ffmpeg | +|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:|-----:|-------:| +| Ubuntu Jammy | ☐ | ☐ | 3.10 | u2.42 | u1.2020.2 | u0.8 | 2.1.6 | u3.4 | 0.51 | 4.4.2 | +| Debian Bullseye | ☐ | ☐ | 3.9 | 2.42 | 1.2020.2 | 0.7 | 2.1.6 | | 0.51 | 4.3.7 | --- @@ -224,6 +224,7 @@ Handle project workflows in a unified way: #### Shell * comment +* git/pypi fallback for rwx/spcd * handle errors * packages * configure @@ -240,6 +241,7 @@ Handle project workflows in a unified way: * locales * persist * test +* workspace variable #### Shell → Python @@ -282,7 +284,9 @@ Handle project workflows in a unified way: ### Task stack * automate versions fetching +* gource, xvfb, xauth * handle openh264 repositories +* rpm fusion * tex * translate to french * try to support nix diff --git a/spcd.sh b/spcd.sh index a577aed..76cb937 100755 --- a/spcd.sh +++ b/spcd.sh @@ -1,27 +1,30 @@ #! /usr/bin/env sh gource \ ---auto-skip-seconds 1 \ ---date-format "%Y / %m / %d ⋅ %H : %M : %S" \ ---disable-progress \ --f \ ---hide mouse,usernames \ ---highlight-dirs \ ---key \ ---output-framerate 60 \ ---seconds-per-day 2.0 \ ---output-ppm-stream - \ -| \ -ffmpeg \ --codec:v ppm \ --format image2pipe \ --framerate 120 \ --i - \ --codec:v libx264 \ --preset veryslow \ --qp 23 \ --movflags \ -+faststart \ --pix_fmt yuv420p \ --y \ -spcd.mp4 + --auto-skip-seconds 0.25 \ + --date-format "%Y / %m / %d ⋅ %H : %M : %S" \ + --disable-input \ + --font-scale 2.5 \ + --frameless \ + --hide mouse,usernames \ + --highlight-dirs \ + --key \ + --multi-sampling \ + --output-framerate 60 \ + --output-ppm-stream - \ + --seconds-per-day 0.6 \ + --stop-at-end \ + --viewport "1920x1080" | + ffmpeg \ + -codec:v ppm \ + -format image2pipe \ + -framerate 120 \ + -i - \ + -codec:v libx264 \ + -preset veryslow \ + -qp 28 \ + -movflags \ + +faststart \ + -pix_fmt yuv420p \ + -y \ + spcd.mp4 diff --git a/spcd/bootstrap.sh b/spcd/bootstrap.sh index 0268849..747e02b 100644 --- a/spcd/bootstrap.sh +++ b/spcd/bootstrap.sh @@ -4,9 +4,9 @@ # │ __ = internal │ # ╰───────────────╯ -# __SPCD_BANNER_TOP -# __SPCD_BANNER_MIDDLE -# __SPCD_BANNER_BOTTOM +# __SPCD_BAR_TOP +# __SPCD_BAR_MIDDLE +# __SPCD_BAR_BOTTOM # __SPCD_STEP_LEVEL # __SPCD_STEP_level_INDEX @@ -36,35 +36,35 @@ _spcd_fill() { done } -# ╭───┬────────╮ -# │ _ │ banner │ -# ╰───┴────────╯ +# ╭───┬─────╮ +# │ _ │ bar │ +# ╰───┴─────╯ -_SPCD_BANNER_BOTTOM_LEFT="${_SPCD_BOX_UP_AND_RIGHT}" -_SPCD_BANNER_BOTTOM_MIDDLE="${_SPCD_BOX_UP_AND_HORIZONTAL}" -_SPCD_BANNER_BOTTOM_RIGHT="${_SPCD_BOX_UP_AND_LEFT}" -_SPCD_BANNER_HORIZONTAL="${_SPCD_BOX_HORIZONTAL}" -_SPCD_BANNER_TOP_LEFT="${_SPCD_BOX_DOWN_AND_RIGHT}" -_SPCD_BANNER_TOP_MIDDLE="${_SPCD_BOX_DOWN_AND_HORIZONTAL}" -_SPCD_BANNER_TOP_RIGHT="${_SPCD_BOX_DOWN_AND_LEFT}" -_SPCD_BANNER_VERTICAL="${_SPCD_BOX_VERTICAL}" +_SPCD_BAR_BOTTOM_LEFT="${_SPCD_BOX_UP_AND_RIGHT}" +_SPCD_BAR_BOTTOM_MIDDLE="${_SPCD_BOX_UP_AND_HORIZONTAL}" +_SPCD_BAR_BOTTOM_RIGHT="${_SPCD_BOX_UP_AND_LEFT}" +_SPCD_BAR_HORIZONTAL="${_SPCD_BOX_HORIZONTAL}" +_SPCD_BAR_TOP_LEFT="${_SPCD_BOX_DOWN_AND_RIGHT}" +_SPCD_BAR_TOP_MIDDLE="${_SPCD_BOX_DOWN_AND_HORIZONTAL}" +_SPCD_BAR_TOP_RIGHT="${_SPCD_BOX_DOWN_AND_LEFT}" +_SPCD_BAR_VERTICAL="${_SPCD_BOX_VERTICAL}" -_spcd_banner_add() { +_spcd_bar_add() { if [ -n "${1}" ]; then local text length filler text=" ${1} " length=${#text} - filler="$(_spcd_fill "${length}" "${_SPCD_BANNER_HORIZONTAL}")" - if [ -n "${__SPCD_BANNER_MIDDLE}" ]; then - _spcd_banner_split + filler="$(_spcd_fill "${length}" "${_SPCD_BAR_HORIZONTAL}")" + if [ -n "${__SPCD_BAR_MIDDLE}" ]; then + _spcd_bar_split else - _spcd_banner_open + _spcd_bar_open fi - _spcd_banner_append "${filler}" "${text}" "${filler}" + _spcd_bar_append "${filler}" "${text}" "${filler}" fi } -_spcd_banner_add_index() { +_spcd_bar_add_index() { local level value label while true; do level=$((level + 1)) @@ -76,68 +76,68 @@ _spcd_banner_add_index() { label="${value}" fi done - _spcd_banner_add "${label}" + _spcd_bar_add "${label}" } -_spcd_banner_append() { +_spcd_bar_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}" + __SPCD_BAR_TOP="${__SPCD_BAR_TOP}${1}" + __SPCD_BAR_MIDDLE="${__SPCD_BAR_MIDDLE}${2}" + __SPCD_BAR_BOTTOM="${__SPCD_BAR_BOTTOM}${3}" fi } -_spcd_banner_echo() { +_spcd_bar_echo() { echo "\ -${__SPCD_BANNER_TOP} -${__SPCD_BANNER_MIDDLE} -${__SPCD_BANNER_BOTTOM}" +${__SPCD_BAR_TOP} +${__SPCD_BAR_MIDDLE} +${__SPCD_BAR_BOTTOM}" } -_spcd_banner_open() { - _spcd_banner_append \ - "${_SPCD_BANNER_TOP_LEFT}" \ - "${_SPCD_BANNER_VERTICAL}" \ - "${_SPCD_BANNER_BOTTOM_LEFT}" +_spcd_bar_open() { + _spcd_bar_append \ + "${_SPCD_BAR_TOP_LEFT}" \ + "${_SPCD_BAR_VERTICAL}" \ + "${_SPCD_BAR_BOTTOM_LEFT}" } -_spcd_banner_render() { - _spcd_banner_wipe - _spcd_banner_add "S" - _spcd_banner_add_index +_spcd_bar_render() { + _spcd_bar_wipe + _spcd_bar_add "S" + _spcd_bar_add_index # local level value while true; do level=$((level + 1)) eval "value=\"\${__SPCD_STEP_${level}_LABEL}\"" [ -n "${value}" ] || break - _spcd_banner_add "${value}" + _spcd_bar_add "${value}" done # - _spcd_banner_shut - _spcd_banner_echo - _spcd_banner_wipe + _spcd_bar_shut + _spcd_bar_echo + _spcd_bar_wipe } -_spcd_banner_shut() { - _spcd_banner_append \ - "${_SPCD_BANNER_TOP_RIGHT}" \ - "${_SPCD_BANNER_VERTICAL}" \ - "${_SPCD_BANNER_BOTTOM_RIGHT}" +_spcd_bar_shut() { + _spcd_bar_append \ + "${_SPCD_BAR_TOP_RIGHT}" \ + "${_SPCD_BAR_VERTICAL}" \ + "${_SPCD_BAR_BOTTOM_RIGHT}" } -_spcd_banner_split() { - _spcd_banner_append \ - "${_SPCD_BANNER_TOP_MIDDLE}" \ - "${_SPCD_BANNER_VERTICAL}" \ - "${_SPCD_BANNER_BOTTOM_MIDDLE}" +_spcd_bar_split() { + _spcd_bar_append \ + "${_SPCD_BAR_TOP_MIDDLE}" \ + "${_SPCD_BAR_VERTICAL}" \ + "${_SPCD_BAR_BOTTOM_MIDDLE}" } -_spcd_banner_wipe() { +_spcd_bar_wipe() { unset \ - __SPCD_BANNER_TOP \ - __SPCD_BANNER_MIDDLE \ - __SPCD_BANNER_BOTTOM + __SPCD_BAR_TOP \ + __SPCD_BAR_MIDDLE \ + __SPCD_BAR_BOTTOM } # ╭───┬───────╮ @@ -199,7 +199,7 @@ _spcd_step_wipe() { _SPCD_TXT_CHARSET="UTF-8" _SPCD_TXT_LOCALE_DEFAULT="C" -_spcd_txt_pick() { +_spcd_txt() { case "${SPCD_TXT_LOCALE}" in "${SPCD_TXT_LOCALE_ENGLISH}") echo "${1}" ;; "${SPCD_TXT_LOCALE_FRENCH}") echo "${2}" ;; @@ -211,54 +211,6 @@ _spcd_txt_pick() { # │ p = public │ # ╰────────────╯ -spcd_ca() { - local grep="\(After\|Before\|Issuer\|Signature Algorithm\|Subject:\)" - local index name value - local root="${2}" - while true; do - index=$((index + 1)) - name="SPCD_CA_${index}" - eval "value=\"\${${name}}\"" - [ -n "${value}" ] || break - case "${1}" in - "list") - echo "${name} =" - echo "${value}" | - openssl x509 -noout -text | - grep "${grep}" - ;; - "write") - spcd_os_write "${root}/${index}.crt" "${value}" - ;; - *) ;; - esac - done -} - -spcd_dns() { - local index name text value - while true; do - index=$((index + 1)) - name="SPCD_DNS_${index}" - eval "value=\"\${${name}}\"" - [ -n "${value}" ] || break - case "${1}" in - "list") - spcd_os_printenv "${name}" - ;; - "write") - text="${text}\ -nameserver ${value} -" - ;; - *) ;; - esac - done - if [ "${1}" = "write" ]; then - spcd_os_write "/etc/resolv.conf" "${text}" - fi -} - spcd_run() { if [ -n "${1}" ]; then _spcd_frame_open "${@}" @@ -368,7 +320,7 @@ spcd_step() { local index="${prefix}_INDEX" eval "${index}=\$((${index} + 1))" eval "${prefix}_LABEL=\"${1}\"" - _spcd_banner_render + _spcd_bar_render fi } @@ -390,19 +342,19 @@ spcd_step_out() { SPCD_TXT_LOCALE_ENGLISH="en_US" SPCD_TXT_LOCALE_FRENCH="fr_FR" -spcd_txt_get() { +spcd_txt() { case "${1}" in - "set") _spcd_txt_pick "Set" "Définir" ;; + "set") _spcd_txt "Set" "Définir" ;; *) ;; esac } -# ╭──────────╮ -# │ s = step │ -# ╰──────────╯ +# ╭─────────────────╮ +# │ e = environment │ +# ╰─────────────────╯ # ╭───┬───────────╮ -# │ s │ constants │ +# │ e │ constants │ # ╰───┴───────────╯ SPCD_OS_ALMA="alma" @@ -420,43 +372,12 @@ SPCD_PM_DNF="dnf" SPCD_PM_PACMAN="pacman" SPCD_PM_ZYPPER="zypper" -# ╭───┬─────────────╮ -# │ s │ environment │ -# ╰───┴─────────────╯ +# ╭───┬───────────╮ +# │ e │ functions │ +# ╰───┴───────────╯ -spcd_step__environment_print() { - spcd_ca "list" - spcd_dns "list" - set -- \ - "GIT_RWX" \ - "GIT_SPCD" \ - "GIT_SHUNIT" \ - "REF_FEATURE" \ - "REF_RELEASE" \ - "REF_STAGING" \ - "TXT_LOCALE" \ - "URL_ALMA" \ - "URL_ALPINE" \ - "URL_ARCH" \ - "URL_DEBIAN" \ - "URL_EPEL" \ - "URL_FEDORA" \ - "URL_OPENSUSE" \ - "URL_PYTHON" \ - "URL_ROCKY" \ - "URL_UBUNTU" - local item name value - for item in "${@}"; do - name="SPCD_${item}" - eval "value=\"\${${name}}\"" - if [ -n "${value}" ]; then - spcd_os_printenv "${name}" - fi - done -} - -spcd_step__environment_defaults_set() { - spcd_step "$(spcd_txt_get "set")" +spcd_e_default() { + spcd_step "$(spcd_txt "set")" [ -n "${SPCD_DNS_1}" ] || SPCD_DNS_1="9.9.9.9" @@ -484,6 +405,7 @@ spcd_step__environment_defaults_set() { # /$repo/os/$arch SPCD_URL_ARCH="https://geo.mirror.pkgbuild.com" [ -n "${SPCD_URL_DEBIAN}" ] || + # /dists/… SPCD_URL_DEBIAN="https://deb.debian.org/debian" [ -n "${SPCD_URL_EPEL}" ] || # /$releasever/Everything/… @@ -507,10 +429,11 @@ spcd_step__environment_defaults_set() { # /$contentdir/$releasever/… SPCD_URL_ROCKY="https://dl.rockylinux.org" [ -n "${SPCD_URL_UBUNTU}" ] || + # /dists/… SPCD_URL_UBUNTU="https://ubuntu.mirrors.ovh.net/ubuntu" } -spcd_step__environment_set_variables() { +spcd_e_set() { spcd_step "Set variables" # check script first [ -n "${SPCD}" ] || spcd_error_ci "SPCD" @@ -785,27 +708,268 @@ ${SPCD_PYTHON_VENV}/lib/${SPCD_PYTHON_COMMAND}/site-packages" spcd_os_printenv "SPCD_DL" } -spcd_step__environment_list_workspace() { - spcd_step "List workspace" - spcd_os_ls "$(realpath .)" -} - # ╭──────────────╮ # │ f = function │ # ╰──────────────╯ -spcd_git_clone() { +spcd_f_dns() { + local index name text value + while true; do + index=$((index + 1)) + name="SPCD_DNS_${index}" + eval "value=\"\${${name}}\"" + [ -n "${value}" ] || break + case "${1}" in + "list") + spcd_os_printenv "${name}" + ;; + "write") + text="${text}\ +nameserver ${value} +" + ;; + *) ;; + esac + done + if [ "${1}" = "write" ]; then + spcd_os_write "/etc/resolv.conf" "${text}" + fi +} + +spcd_f_pkg() { + spcd_step_in "OS packages" + local file + # epel + spcd_step "EPEL" + case "${SPCD_OS_ID}" in + "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") + spcd_f_pm_pkg_install "epel-release" + case "${SPCD_OS_VERSION}" in + "9") + set -- \ + "-testing" \ + "" + ;; + "8") + set -- \ + "-modular" \ + "-testing-modular" \ + "-testing" \ + "" + ;; + *) ;; + esac + for file in "${@}"; do + spcd_os_sed "/etc/yum.repos.d/epel${file}.repo" \ + "|^metalink|#metalink|" \ + "|https://download.example/pub/epel|${SPCD_URL_EPEL}|" \ + "|^#baseurl|baseurl|" + done + file="/etc/yum.repos.d/epel-cisco-openh264.repo" + if [ -f "${file}" ]; then + spcd_os_sed "${file}" \ + "|^enabled=1|enabled=0|" + fi + spcd_f_pm_pkg_update + ;; + *) ;; + esac + # ffmpeg + spcd_step "FFMPEG" + case "${SPCD_OS_ID}" in + "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") + case "${SPCD_OS_VERSION}" in + "8") ;; + *) + dnf config-manager --enable "crb" + spcd_f_pm_pkg_install "ffmpeg-free" + ;; + esac + ;; + "${SPCD_OS_FEDORA}") spcd_f_pm_pkg_install "ffmpeg-free" ;; + "${SPCD_OS_OPENSUSE}") spcd_f_pm_pkg_install "ffmpeg-4" ;; + *) spcd_f_pm_pkg_install "ffmpeg" ;; + esac + # gource + spcd_step "Gource" + case "${SPCD_OS_ID}" in + "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") ;; + *) spcd_f_pm_pkg_install "gource" ;; + esac + # graphviz + spcd_step "GraphViz" + spcd_f_pm_pkg_install "graphviz" + # openssh + spcd_step "OpenSSH" + case "${SPCD_PM}" in + "${SPCD_PM_APK}" | "${SPCD_PM_APT}") + spcd_f_pm_pkg_install "openssh-client" + ;; + "${SPCD_PM_DNF}" | "${SPCD_PM_ZYPPER}") + spcd_f_pm_pkg_install "openssh-clients" + ;; + "${SPCD_PM_PACMAN}") spcd_f_pm_pkg_install "openssh" ;; + *) ;; + esac + # plantuml + spcd_step "PlantUML" + spcd_f_pm_pkg_install "plantuml" + # rsync + spcd_step "Rsync" + spcd_f_pm_pkg_install "rsync" + # shell check + spcd_step "ShellCheck" + case "${SPCD_PM}" in + "${SPCD_PM_DNF}" | "${SPCD_PM_ZYPPER}") + spcd_f_pm_pkg_install "ShellCheck" + ;; + *) spcd_f_pm_pkg_install "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_f_pm_pkg_install "shfmt" ;; + esac + ;; + *) spcd_f_pm_pkg_install "shfmt" ;; + esac + spcd_step_out +} + +# ╭───┬──────────────────────────────╮ +# │ f │ ca = certificate authorities │ +# ╰───┴──────────────────────────────╯ + +spcd_f_ca() { + case "${1}" in + "list") + local grep="\(After\|Before\|Issuer\|Signature Algorithm\|Subject:\)" + ;; + "write") + local root + case "${SPCD_OS_ID}" in + "${SPCD_OS_ALMA}" | "${SPCD_OS_FEDORA}" | "${SPCD_OS_ROCKY}") + root="/etc/pki/ca-trust/source/anchors" + ;; + "${SPCD_OS_ALPINE}" | "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") + root="/usr/local/share/ca-certificates" + ;; + "${SPCD_OS_ARCH}") + root="/etc/ca-certificates/trust-source/anchors" + ;; + "${SPCD_OS_OPENSUSE}") + root="/etc/pki/trust/anchors" + ;; + *) ;; + esac + spcd_os_mkdir "${root}" + ;; + *) ;; + esac + local index name value + while true; do + index=$((index + 1)) + name="SPCD_CA_${index}" + eval "value=\"\${${name}}\"" + [ -n "${value}" ] || break + case "${1}" in + "list") + echo "${name} =" + echo "${value}" | + openssl x509 -noout -text | + grep "${grep}" + ;; + "write") + spcd_os_write "${root}/${index}.crt" "${value}" + ;; + *) ;; + esac + done +} + +spcd_f_ca_install() { + spcd_step "Install package" + spcd_f_pm_pkg_install "ca-certificates" +} + +spcd_f_ca_update() { + spcd_step "Update certificates" + case "${SPCD_OS_ID}" in + "${SPCD_OS_ARCH}" | \ + "${SPCD_OS_ALMA}" | \ + "${SPCD_OS_FEDORA}" | \ + "${SPCD_OS_ROCKY}") + spcd_run update-ca-trust + ;; + "${SPCD_OS_ALPINE}" | \ + "${SPCD_OS_DEBIAN}" | \ + "${SPCD_OS_OPENSUSE}" | \ + "${SPCD_OS_UBUNTU}") + spcd_run update-ca-certificates + ;; + *) ;; + esac +} + +# ╭───┬───────────────────╮ +# │ f │ env = environment │ +# ╰───┴───────────────────╯ + +spcd_f_env_list() { + spcd_f_ca "list" + spcd_f_dns "list" + set -- \ + "GIT_RWX" \ + "GIT_SPCD" \ + "GIT_SHUNIT" \ + "REF_FEATURE" \ + "REF_RELEASE" \ + "REF_STAGING" \ + "TXT_LOCALE" \ + "URL_ALMA" \ + "URL_ALPINE" \ + "URL_ARCH" \ + "URL_DEBIAN" \ + "URL_EPEL" \ + "URL_FEDORA" \ + "URL_OPENSUSE" \ + "URL_PYTHON" \ + "URL_ROCKY" \ + "URL_UBUNTU" + local item name value + for item in "${@}"; do + name="SPCD_${item}" + eval "value=\"\${${name}}\"" + if [ -n "${value}" ]; then + spcd_os_printenv "${name}" + fi + done +} + +spcd_f_env_workspace() { + spcd_os_ls "$(realpath .)" +} + +# ╭───┬─────╮ +# │ f │ git │ +# ╰───┴─────╯ + +spcd_f_git_clone() { if [ -n "${1}" ]; then local name path url name="$(basename "${1}")" path="${SPCD_DL}/${name}" - url="$(spcd_git_url "${1}")" + url="$(spcd_f_git_url "${1}")" git clone "${url}" "${path}" echo "${path}" fi } -spcd_git_url() { +spcd_f_git_url() { if [ -n "${1}" ]; then case "${1}" in http*) echo "${1}" ;; @@ -815,309 +979,68 @@ spcd_git_url() { fi } -spcd_python_ln() { - local command="${1}" - if [ -n "${command}" ]; then - echo "→ ${SPCD_PYTHON_ALIAS} → ${command}" - ln -f -s "${command}" \ - "/usr/bin/${SPCD_PYTHON_ALIAS}" - fi +# ╭───┬───────────────╮ +# │ f │ pkg = package │ +# ╰───┴───────────────╯ + +spcd_f_pkg_dos2unix() { + spcd_step "Install dos2unix" + spcd_f_pm_pkg_install "dos2unix" } -spcd_python_pip() { - if [ -n "${1}" ]; then - local name path target - name="$(basename "${1}")" - path="$(spcd_git_clone "${1}")" - path="${path}/${name}" - target="${SPCD_PYTHON_VENV_PACKAGES}" - cp --recursive "${path}" "${target}" - echo "${target}/${name}" - fi +spcd_f_pkg_git() { + spcd_step "Install Git" + spcd_f_pm_pkg_install "git" } -spcd_txt_locale() { - local action="${1}" - local chosen="${2}" - set -- \ - "LANG" \ - "LC_CTYPE" \ - "LC_NUMERIC" \ - "LC_TIME" \ - "LC_COLLATE" \ - "LC_MONETARY" \ - "LC_MESSAGES" - case "${SPCD_OS_ID}" in - "${SPCD_OS_ALPINE}") ;; - *) - set -- \ - "${@}" \ - "LANGUAGE" \ - "LC_PAPER" \ - "LC_NAME" \ - "LC_ADDRESS" \ - "LC_TELEPHONE" \ - "LC_MEASUREMENT" \ - "LC_IDENTIFICATION" - ;; - esac - local name - case "${action}" in - "list") - if ! locale; then - for name in "${@}"; do - spcd_os_printenv "${name}" - done - fi - ;; - "set") - spcd_txt_locale "list" - spcd_split - local locale long - if [ -n "${chosen}" ]; then - locale="${chosen}" - else - locale="${_SPCD_TXT_LOCALE_DEFAULT}" - fi - long="${locale}.${_SPCD_TXT_CHARSET}" - for name in "${@}"; do - if [ "${name}" != "LANGUAGE" ]; then - export "${name}=${long}" - else - export "${name}=$(spcd_txt_locales language "${chosen}")" - fi - done - spcd_split - spcd_txt_locale "list" - ;; - "show") - local regex - for name in "${@}"; do - unset regex - case "${name}" in - # LC_CTYPE - "LC_NUMERIC") regex="^\(decimal\|thousands\|grouping\)" ;; - "LC_TIME") regex="^\(day\|mon\)" ;; - # LC_COLLATE - "LC_MONETARY") - case "${SPCD_OS_ID}" in - "${SPCD_OS_ALPINE}") ;; - *) regex="^\(int_curr\|currency\|mon_\)" ;; - esac - ;; - "LC_MESSAGES") regex="^\(yes\|no\)" ;; - "LC_PAPER") regex="^\(height\|width\)" ;; - "LC_NAME") regex="^name_m" ;; - "LC_ADDRESS") regex="^\(country\|lang\)_name" ;; - "LC_TELEPHONE") regex="^int_" ;; - "LC_MEASUREMENT") regex="^measurement=" ;; - "LC_IDENTIFICATION") regex="^\(language\|territory\|title\)" ;; - *) ;; - esac - spcd_split - spcd_os_printenv "${name}" - if [ -n "${regex}" ]; then - locale --keyword-name "${name}" | grep "${regex}" - fi - done - ;; - *) ;; - esac -} +# ╭───┬──────────────────────╮ +# │ f │ pm = package manager │ +# ╰───┴──────────────────────╯ -spcd_txt_locales() { - local action="${1}" - local chosen="${2}" - set -- \ - "${SPCD_TXT_LOCALE_ENGLISH}" \ - "${SPCD_TXT_LOCALE_FRENCH}" - local name - case "${action}" in - "install") - spcd_txt_locales "list" - spcd_split - case "${SPCD_PM}" in - "${SPCD_PM_APK}") - spcd_f_pm_install "musl-locales" - export MUSL_LOCPATH="/usr/share/i18n/locales/musl" - ;; - "${SPCD_PM_APT}") - local text - for name in "${@}"; do - text="${text}\ -${name}.${_SPCD_TXT_CHARSET} ${_SPCD_TXT_CHARSET} +# ╭───┬────┬──────────────────╮ +# │ f │ pm │ conf = configure │ +# ╰───┴────┴──────────────────╯ + +spcd_f_pm_conf() { + 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 " - done - spcd_os_write "/etc/locale.gen" "${text}" - spcd_f_pm_install "locales" - ;; - "${SPCD_PM_DNF}") - local language - for name in "${@}"; do - language="$(echo "${name}" | cut -d _ -f 1)" - spcd_f_pm_install "glibc-langpack-${language}" - done - ;; - "${SPCD_PM_PACMAN}") spcd_f_pm_install "glibc-locales" ;; - "${SPCD_PM_ZYPPER}") spcd_f_pm_install "glibc-locale" ;; - *) ;; - esac - spcd_split - spcd_txt_locales "list" ;; - "language") - local text - if [ -n "${chosen}" ]; then - text="${chosen}" - fi - for name in "${@}"; do - if [ "${name}" != "${chosen}" ]; then - if [ -n "${text}" ]; then - text="${text}:${name}" - else - text="${name}" - fi - fi - done + "${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 \"\"; +" ;; - "list") - if ! spcd_run locale --all-locales; then - echo "No locales yet!" - fi - ;; - *) ;; - esac -} - -# ╭───┬────╮ -# │ f │ pm │ -# ╰───┴────╯ - -spcd_f_pm_clean() { - case "${SPCD_PM}" in - "${SPCD_PM_APK}") spcd_run apk cache purge ;; - "${SPCD_PM_APT}") spcd_run apt-get clean ;; - "${SPCD_PM_DNF}") spcd_run dnf clean all ;; - "${SPCD_PM_PACMAN}") spcd_run pacman --sync --clean --noconfirm ;; - "${SPCD_PM_ZYPPER}") spcd_run zypper clean ;; - *) ;; - esac -} - -spcd_f_pm_install() { - case "${SPCD_PM}" in - "${SPCD_PM_APK}") spcd_run apk add "${1}" ;; - "${SPCD_PM_APT}") spcd_run apt-get install --assume-yes "${1}" ;; - "${SPCD_PM_DNF}") spcd_run dnf install --assumeyes "${1}" ;; - "${SPCD_PM_PACMAN}") spcd_run pacman --sync --noconfirm "${1}" ;; - "${SPCD_PM_ZYPPER}") spcd_run zypper --non-interactive install "${1}" ;; - *) ;; - esac - spcd_f_pm_clean -} - -spcd_f_pm_query() { - 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 -} - -spcd_f_pm_update() { - spcd_step "Update" - case "${SPCD_PM}" in - "${SPCD_PM_APK}") spcd_run apk update ;; - "${SPCD_PM_APT}") spcd_run apt-get update ;; - "${SPCD_PM_DNF}") spcd_run dnf makecache ;; - "${SPCD_PM_PACMAN}") spcd_run pacman --sync --refresh ;; - "${SPCD_PM_ZYPPER}") spcd_run zypper refresh ;; - *) ;; - esac -} - -spcd_f_pm_upgrade() { - spcd_step "Upgrade" - case "${SPCD_PM}" in - "${SPCD_PM_APK}") spcd_run apk upgrade ;; - "${SPCD_PM_APT}") spcd_run apt-get upgrade --assume-yes ;; - "${SPCD_PM_DNF}") spcd_run dnf upgrade --assumeyes ;; - "${SPCD_PM_PACMAN}") spcd_run pacman --sync --sysupgrade --noconfirm ;; - "${SPCD_PM_ZYPPER}") spcd_run zypper --non-interactive update ;; - *) ;; - esac -} - -# ╭───┬────┬───────╮ -# │ f │ pm │ https │ -# ╰───┴────┴───────╯ - -spcd_f_pm_https_path() { - case "${SPCD_PM}" in - "${SPCD_PM_APK}") echo "/etc/apk/repositories.d/https" ;; - "${SPCD_PM_APT}") echo "/etc/apt/apt.conf.d/https" ;; - "${SPCD_PM_DNF}") echo "/etc/dnf/dnf.conf.d/https.conf" ;; - "${SPCD_PM_PACMAN}") echo "/etc/pacman.d/https.conf" ;; "${SPCD_PM_ZYPPER}") ;; *) ;; esac + case "${SPCD_OS_ID}" in + "${SPCD_OS_ARCH}") + spcd_run pacman-key --init + ;; + "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") + export DEBIAN_FRONTEND="noninteractive" + spcd_os_printenv DEBIAN_FRONTEND + ;; + *) ;; + esac } -spcd_f_pm_https_trust() { - spcd_step "Trust" - local path text - if [ -n "${SPCD_CA_1}" ] || [ "${SPCD_PM}" = "${SPCD_PM_APT}" ]; then - path="$(spcd_f_pm_https_path)" - if [ -n "${path}" ]; then - spcd_os_mkdir "$(dirname "${path}")" - case "${SPCD_PM}" in - "${SPCD_PM_APK}") text="\ ---no-verify -" ;; - "${SPCD_PM_APT}") text="\ -Acquire::https::Verify-Peer False; -" ;; - "${SPCD_PM_DNF}") text="\ -sslverify=False -" ;; - "${SPCD_PM_PACMAN}") text="\ -SSLVerify = No -" ;; - "${SPCD_PM_ZYPPER}") ;; - *) ;; - esac - [ -n "${text}" ] && - spcd_os_write "${path}" "${text}" - fi - fi -} - -spcd_f_pm_https_verify() { - spcd_step "Verify" - local path - path="$(spcd_f_pm_https_path)" - if [ -n "${path}" ]; then - spcd_os_rm "${path}" - fi -} - -# ╭───┬─────╮ -# │ s │ dns │ -# ╰───┴─────╯ - -spcd_step__dns() { - spcd_step "DNS" - spcd_dns "write" -} - -# ╭───┬──────────╮ -# │ s │ packages │ -# ╰───┴──────────╯ - -spcd_step__packages_set_repositories() { +spcd_f_pm_conf_repos() { spcd_step "Set repositories" local file case "${SPCD_OS_ID}" in @@ -1259,143 +1182,187 @@ deb ${SPCD_URL_UBUNTU} ${SPCD_OS_VERSION}-security main universe esac } -spcd_step__packages_set_configuration() { - spcd_step "Set configuration" +# ╭───┬────┬───────╮ +# │ f │ pm │ https │ +# ╰───┴────┴───────╯ + +spcd_f_pm_https_path() { 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_APK}") echo "/etc/apk/repositories.d/https" ;; + "${SPCD_PM_APT}") echo "/etc/apt/apt.conf.d/https" ;; + "${SPCD_PM_DNF}") echo "/etc/dnf/dnf.conf.d/https.conf" ;; + "${SPCD_PM_PACMAN}") echo "/etc/pacman.d/https.conf" ;; "${SPCD_PM_ZYPPER}") ;; *) ;; esac - case "${SPCD_OS_ID}" in - "${SPCD_OS_ARCH}") - spcd_run pacman-key --init - ;; - "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") - export DEBIAN_FRONTEND="noninteractive" - spcd_os_printenv DEBIAN_FRONTEND - ;; - *) ;; - esac } -spcd_step__packages_install_tools() { - spcd_step "Install tools" +spcd_f_pm_https_trust() { + spcd_step "Trust" + local path text + if [ -n "${SPCD_CA_1}" ] || [ "${SPCD_PM}" = "${SPCD_PM_APT}" ]; then + path="$(spcd_f_pm_https_path)" + if [ -n "${path}" ]; then + spcd_os_mkdir "$(dirname "${path}")" + case "${SPCD_PM}" in + "${SPCD_PM_APK}") text="\ +--no-verify +" ;; + "${SPCD_PM_APT}") text="\ +Acquire::https::Verify-Peer False; +" ;; + "${SPCD_PM_DNF}") text="\ +sslverify=False +" ;; + "${SPCD_PM_PACMAN}") text="\ +SSLVerify = No +" ;; + "${SPCD_PM_ZYPPER}") ;; + *) ;; + esac + [ -n "${text}" ] && + spcd_os_write "${path}" "${text}" + fi + fi +} + +spcd_f_pm_https_verify() { + spcd_step "Verify" + local path + path="$(spcd_f_pm_https_path)" + if [ -n "${path}" ]; then + spcd_os_rm "${path}" + fi +} + +# ╭───┬────┬─────╮ +# │ f │ pm │ pkg │ +# ╰───┴────┴─────╯ + +spcd_f_pm_pkg_clean() { case "${SPCD_PM}" in - "${SPCD_PM_APT}") spcd_f_pm_install "apt-utils" ;; + "${SPCD_PM_APK}") spcd_run apk cache purge ;; + "${SPCD_PM_APT}") spcd_run apt-get clean ;; + "${SPCD_PM_DNF}") spcd_run dnf clean all ;; + "${SPCD_PM_PACMAN}") spcd_run pacman --sync --clean --noconfirm ;; + "${SPCD_PM_ZYPPER}") spcd_run zypper clean ;; *) ;; esac } -spcd_step__packages_install_locales() { - spcd_step_in "Locales" - spcd_step "Install" - spcd_txt_locales "install" - spcd_step "Set" - spcd_txt_locale "set" "${SPCD_TXT_LOCALE}" - spcd_step "Show" - spcd_txt_locale "show" +spcd_f_pm_pkg_install() { + if [ -n "${1}" ]; then + local name + for name in "${@}"; do + case "${SPCD_PM}" in + "${SPCD_PM_APK}") spcd_run apk add "${1}" ;; + "${SPCD_PM_APT}") spcd_run apt-get install --assume-yes "${1}" ;; + "${SPCD_PM_DNF}") spcd_run dnf install --assumeyes "${1}" ;; + "${SPCD_PM_PACMAN}") spcd_run pacman --sync --noconfirm "${1}" ;; + "${SPCD_PM_ZYPPER}") + spcd_run zypper --non-interactive install "${1}" + ;; + *) ;; + esac + spcd_f_pm_pkg_clean + done + else + case "${SPCD_PM}" in + "${SPCD_PM_APT}") spcd_f_pm_pkg_install "apt-utils" ;; + "${SPCD_PM_DNF}") spcd_f_pm_pkg_install "dnf-plugins-core" ;; + *) ;; + esac + fi +} + +spcd_f_pm_pkg_query() { + 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 +} + +spcd_f_pm_pkg_update() { + spcd_step "Update" + case "${SPCD_PM}" in + "${SPCD_PM_APK}") spcd_run apk update ;; + "${SPCD_PM_APT}") spcd_run apt-get update ;; + "${SPCD_PM_DNF}") spcd_run dnf makecache ;; + "${SPCD_PM_PACMAN}") spcd_run pacman --sync --refresh ;; + "${SPCD_PM_ZYPPER}") spcd_run zypper refresh ;; + *) ;; + esac +} + +spcd_f_pm_pkg_upgrade() { + spcd_step "Upgrade" + case "${SPCD_PM}" in + "${SPCD_PM_APK}") spcd_run apk upgrade ;; + "${SPCD_PM_APT}") spcd_run apt-get upgrade --assume-yes ;; + "${SPCD_PM_DNF}") spcd_run dnf upgrade --assumeyes ;; + "${SPCD_PM_PACMAN}") spcd_run pacman --sync --sysupgrade --noconfirm ;; + "${SPCD_PM_ZYPPER}") spcd_run zypper --non-interactive update ;; + *) ;; + esac +} + +# ╭───┬─────────────╮ +# │ f │ py = python │ +# ╰───┴─────────────╯ + +spcd_f_py_clone() { + if [ -n "${1}" ]; then + local name path target + name="$(basename "${1}")" + path="$(spcd_f_git_clone "${1}")" + path="${path}/${name}" + target="${SPCD_PYTHON_VENV_PACKAGES}" + cp --recursive "${path}" "${target}" + echo "${target}/${name}" + fi +} + +spcd_f_py_download() { + spcd_step_in "Modules" + local target path script check + target="${SPCD_PYTHON_VENV_PACKAGES}" + spcd_step "List" + spcd_os_ls "${target}" + spcd_step "Main" + path="$(spcd_f_py_clone "${SPCD_GIT_SPCD}")" + # check matching of file and variable + spcd_step "Check" + script="${path}/bootstrap.sh" + ls -l "${script}" + check="${script}.${_SPCD_CMD_SUM}" + "${_SPCD_CMD_SUM}" "${script}" >"${check}" + printf "%s" "${SPCD}" >"${script}" + ls -l "${script}" + dos2unix "${script}" + ls -l "${script}" + "${_SPCD_CMD_SUM}" -c "${check}" || spcd_error_ci "SPCD" + spcd_step "Root" + spcd_f_py_clone "${SPCD_GIT_RWX}" + spcd_step "List" + spcd_os_ls "${target}" spcd_step_out } -# ╭───┬────╮ -# │ s │ ca │ -# ╰───┴────╯ - -spcd_step__ca_install_package() { +spcd_f_py_install() { spcd_step "Install package" - spcd_f_pm_install "ca-certificates" -} - -spcd_step__ca_write_certificates() { - spcd_step "Write certificates" - local root - case "${SPCD_OS_ID}" in - "${SPCD_OS_ALMA}" | "${SPCD_OS_FEDORA}" | "${SPCD_OS_ROCKY}") - root="/etc/pki/ca-trust/source/anchors" - ;; - "${SPCD_OS_ALPINE}" | "${SPCD_OS_DEBIAN}" | "${SPCD_OS_UBUNTU}") - root="/usr/local/share/ca-certificates" - ;; - "${SPCD_OS_ARCH}") - root="/etc/ca-certificates/trust-source/anchors" - ;; - "${SPCD_OS_OPENSUSE}") - root="/etc/pki/trust/anchors" - ;; - *) ;; - esac - spcd_os_mkdir "${root}" - spcd_ca "write" "${root}" -} - -spcd_step__ca_update_certificates() { - spcd_step "Update certificates" - case "${SPCD_OS_ID}" in - "${SPCD_OS_ARCH}" | \ - "${SPCD_OS_ALMA}" | \ - "${SPCD_OS_FEDORA}" | \ - "${SPCD_OS_ROCKY}") - spcd_run update-ca-trust - ;; - "${SPCD_OS_ALPINE}" | \ - "${SPCD_OS_DEBIAN}" | \ - "${SPCD_OS_OPENSUSE}" | \ - "${SPCD_OS_UBUNTU}") - spcd_run update-ca-certificates - ;; - *) ;; - esac -} - -# ╭───┬──────────╮ -# │ s │ packages │ -# ╰───┴──────────╯ - -spcd_step__packages_install_dos2unix() { - spcd_step "Install dos2unix" - spcd_f_pm_install "dos2unix" -} - -spcd_step__packages_install_git() { - spcd_step "Install Git" - spcd_f_pm_install "git" -} - -# ╭───┬────────╮ -# │ s │ python │ -# ╰───┴────────╯ - -spcd_step__python_install() { - spcd_step "Install package" - spcd_f_pm_install "${SPCD_PYTHON_PACKAGE}" + spcd_f_pm_pkg_install "${SPCD_PYTHON_PACKAGE}" spcd_step "Link alias to command" - spcd_python_ln "${SPCD_PYTHON_COMMAND}" + spcd_f_py_link "${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_f_pm_install "python3-venv" + spcd_f_pm_pkg_install "python3-venv" ;; *) ;; esac @@ -1412,115 +1379,17 @@ index-url = ${SPCD_URL_PYTHON}/simple spcd_step_out } -spcd_step__python_modules() { - spcd_step_in "Modules" - local target path script check - target="${SPCD_PYTHON_VENV_PACKAGES}" - spcd_step "List" - spcd_os_ls "${target}" - spcd_step "Main" - path="$(spcd_python_pip "${SPCD_GIT_SPCD}")" - # check matching of file and variable - spcd_step "Check" - script="${path}/bootstrap.sh" - ls -l "${script}" - check="${script}.${_SPCD_CMD_SUM}" - "${_SPCD_CMD_SUM}" "${script}" >"${check}" - printf "%s" "${SPCD}" >"${script}" - ls -l "${script}" - dos2unix "${script}" - ls -l "${script}" - "${_SPCD_CMD_SUM}" -c "${check}" || spcd_error_ci "SPCD" - spcd_step "Root" - spcd_python_pip "${SPCD_GIT_RWX}" - spcd_step "List" - spcd_os_ls "${target}" - spcd_step_out +spcd_f_py_link() { + local command="${1}" + if [ -n "${command}" ]; then + echo "→ ${SPCD_PYTHON_ALIAS} → ${command}" + ln -f -s "${command}" \ + "/usr/bin/${SPCD_PYTHON_ALIAS}" + fi } -spcd_step__install_packages() { - spcd_step_in "OS packages" - local file - # epel - spcd_step "EPEL" - case "${SPCD_OS_ID}" in - "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") - spcd_f_pm_install "epel-release" - case "${SPCD_OS_VERSION}" in - "9") - set -- \ - "-testing" \ - "" - ;; - "8") - set -- \ - "-modular" \ - "-testing-modular" \ - "-testing" \ - "" - ;; - *) ;; - esac - for file in "${@}"; do - spcd_os_sed "/etc/yum.repos.d/epel${file}.repo" \ - "|^metalink|#metalink|" \ - "|https://download.example/pub/epel|${SPCD_URL_EPEL}|" \ - "|^#baseurl|baseurl|" - done - file="/etc/yum.repos.d/epel-cisco-openh264.repo" - if [ -f "${file}" ]; then - spcd_os_sed "${file}" \ - "|^enabled=1|enabled=0|" - fi - ;; - *) ;; - esac - # graphviz - spcd_step "GraphViz" - spcd_f_pm_install "graphviz" - # openssh - spcd_step "OpenSSH" - case "${SPCD_PM}" in - "${SPCD_PM_APK}" | "${SPCD_PM_APT}") - spcd_f_pm_install "openssh-client" - ;; - "${SPCD_PM_DNF}" | "${SPCD_PM_ZYPPER}") - spcd_f_pm_install "openssh-clients" - ;; - "${SPCD_PM_PACMAN}") spcd_f_pm_install "openssh" ;; - *) ;; - esac - # plantuml - spcd_step "PlantUML" - spcd_f_pm_install "plantuml" - # rsync - spcd_step "Rsync" - spcd_f_pm_install "rsync" - # shell check - spcd_step "ShellCheck" - case "${SPCD_PM}" in - "${SPCD_PM_DNF}" | "${SPCD_PM_ZYPPER}") - spcd_f_pm_install "ShellCheck" - ;; - *) spcd_f_pm_install "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_f_pm_install "shfmt" ;; - esac - ;; - *) spcd_f_pm_install "shfmt" ;; - esac - spcd_step_out -} - -spcd_step__python_write_module() { - spcd_step "Write module" +spcd_f_py_save() { + spcd_step "Save" local variable value text index root for variable in \ OS_ID OS_VERSION \ @@ -1540,7 +1409,7 @@ SPCD_STEP = ${index} done } -spcd_step__python_switch() { +spcd_f_py_switch() { spcd_step "Switch" local name path name="$(basename "${SPCD_GIT_SPCD}")" @@ -1552,6 +1421,163 @@ ${SPCD_PYTHON_ALIAS} / ${name}" "${SPCD_PYTHON_ALIAS}" -m "${name}" } +# ╭───┬─────╮ +# │ f │ txt │ +# ╰───┴─────╯ + +spcd_f_txt_locale() { + local action="${1}" + local chosen="${2}" + set -- \ + "LANG" \ + "LC_CTYPE" \ + "LC_NUMERIC" \ + "LC_TIME" \ + "LC_COLLATE" \ + "LC_MONETARY" \ + "LC_MESSAGES" + case "${SPCD_OS_ID}" in + "${SPCD_OS_ALPINE}") ;; + *) + set -- \ + "${@}" \ + "LANGUAGE" \ + "LC_PAPER" \ + "LC_NAME" \ + "LC_ADDRESS" \ + "LC_TELEPHONE" \ + "LC_MEASUREMENT" \ + "LC_IDENTIFICATION" + ;; + esac + local name + case "${action}" in + "list") + if ! locale; then + for name in "${@}"; do + spcd_os_printenv "${name}" + done + fi + ;; + "set") + spcd_f_txt_locale "list" + spcd_split + local locale long + if [ -n "${chosen}" ]; then + locale="${chosen}" + else + locale="${_SPCD_TXT_LOCALE_DEFAULT}" + fi + long="${locale}.${_SPCD_TXT_CHARSET}" + for name in "${@}"; do + if [ "${name}" != "LANGUAGE" ]; then + export "${name}=${long}" + else + export "${name}=$(spcd_f_txt_locales language "${chosen}")" + fi + done + spcd_split + spcd_f_txt_locale "list" + ;; + "show") + local regex + for name in "${@}"; do + unset regex + case "${name}" in + # LC_CTYPE + "LC_NUMERIC") regex="^\(decimal\|thousands\|grouping\)" ;; + "LC_TIME") regex="^\(day\|mon\)" ;; + # LC_COLLATE + "LC_MONETARY") + case "${SPCD_OS_ID}" in + "${SPCD_OS_ALPINE}") ;; + *) regex="^\(int_curr\|currency\|mon_\)" ;; + esac + ;; + "LC_MESSAGES") regex="^\(yes\|no\)" ;; + "LC_PAPER") regex="^\(height\|width\)" ;; + "LC_NAME") regex="^name_m" ;; + "LC_ADDRESS") regex="^\(country\|lang\)_name" ;; + "LC_TELEPHONE") regex="^int_" ;; + "LC_MEASUREMENT") regex="^measurement=" ;; + "LC_IDENTIFICATION") regex="^\(language\|territory\|title\)" ;; + *) ;; + esac + spcd_split + spcd_os_printenv "${name}" + if [ -n "${regex}" ]; then + locale --keyword-name "${name}" | grep "${regex}" + fi + done + ;; + *) ;; + esac +} + +spcd_f_txt_locales() { + local action="${1}" + local chosen="${2}" + set -- \ + "${SPCD_TXT_LOCALE_ENGLISH}" \ + "${SPCD_TXT_LOCALE_FRENCH}" + local name + case "${action}" in + "install") + spcd_f_txt_locales "list" + spcd_split + case "${SPCD_PM}" in + "${SPCD_PM_APK}") + spcd_f_pm_pkg_install "musl-locales" + export MUSL_LOCPATH="/usr/share/i18n/locales/musl" + ;; + "${SPCD_PM_APT}") + local text + for name in "${@}"; do + text="${text}\ +${name}.${_SPCD_TXT_CHARSET} ${_SPCD_TXT_CHARSET} +" + done + spcd_os_write "/etc/locale.gen" "${text}" + spcd_f_pm_pkg_install "locales" + ;; + "${SPCD_PM_DNF}") + local language + for name in "${@}"; do + language="$(echo "${name}" | cut -d _ -f 1)" + spcd_f_pm_pkg_install "glibc-langpack-${language}" + done + ;; + "${SPCD_PM_PACMAN}") spcd_f_pm_pkg_install "glibc-locales" ;; + "${SPCD_PM_ZYPPER}") spcd_f_pm_pkg_install "glibc-locale" ;; + *) ;; + esac + spcd_split + spcd_f_txt_locales "list" + ;; + "language") + local text + if [ -n "${chosen}" ]; then + text="${chosen}" + fi + for name in "${@}"; do + if [ "${name}" != "${chosen}" ]; then + if [ -n "${text}" ]; then + text="${text}:${name}" + else + text="${name}" + fi + fi + done + ;; + "list") + if ! spcd_run locale --all-locales; then + echo "No locales yet!" + fi + ;; + *) ;; + esac +} + # ╭──────╮ # │ main │ # ╰──────╯ @@ -1561,46 +1587,56 @@ spcd_main() { spcd_step_in "Environment" spcd_step_in "Defaults" spcd_step "Print defined" - spcd_step__environment_print - spcd_step__environment_defaults_set + spcd_f_env_list + spcd_e_default spcd_step "Print effective" - spcd_step__environment_print + spcd_f_env_list spcd_step_out - spcd_step__environment_set_variables - spcd_step__environment_list_workspace + spcd_e_set + spcd_step "List workspace" + spcd_f_env_workspace spcd_step_out # dns - spcd_step__dns + spcd_step "DNS" + spcd_f_dns "write" # packages spcd_step_in "Packages" - spcd_step__packages_set_repositories - spcd_step__packages_set_configuration + spcd_f_pm_conf_repos + spcd_f_pm_conf spcd_f_pm_https_trust - spcd_f_pm_update - spcd_step__packages_install_tools - spcd_step__packages_install_locales + spcd_f_pm_pkg_update + spcd_f_pm_pkg_install + # locales + spcd_step_in "Locales" + spcd_step "Install" + spcd_f_txt_locales "install" + spcd_step "Set" + spcd_f_txt_locale "set" "${SPCD_TXT_LOCALE}" + spcd_step "Show" + spcd_f_txt_locale "show" + spcd_step_out spcd_step_out # ca spcd_step_in "CA" - spcd_step__ca_install_package - spcd_step__ca_write_certificates - spcd_step__ca_update_certificates + spcd_f_ca_install + spcd_f_ca "write" + spcd_f_ca_update spcd_step_out # packages spcd_step_in "Packages" spcd_f_pm_https_verify - spcd_f_pm_update - spcd_f_pm_upgrade - spcd_step__packages_install_dos2unix - spcd_step__packages_install_git + spcd_f_pm_pkg_update + spcd_f_pm_pkg_upgrade + spcd_f_pkg_dos2unix + spcd_f_pkg_git spcd_step_out # python spcd_step_in "Python" - spcd_step__python_install - spcd_step__python_modules - spcd_step__install_packages - spcd_step__python_write_module - spcd_step__python_switch + spcd_f_py_install + spcd_f_py_download + spcd_f_pkg + spcd_f_py_save + spcd_f_py_switch } spcd_main