lib.sh 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. #!/usr/bin/env bash
  2. # -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
  3. # SPDX-License-Identifier: AGPL-3.0-or-later
  4. # shellcheck disable=SC2059,SC1117
  5. # ubuntu, debian, arch, fedora ...
  6. DIST_ID=$(source /etc/os-release; echo $ID);
  7. # shellcheck disable=SC2034
  8. DIST_VERS=$(source /etc/os-release; echo $VERSION_ID);
  9. ADMIN_NAME="${ADMIN_NAME:-$(git config user.name)}"
  10. ADMIN_NAME="${ADMIN_NAME:-$USER}"
  11. ADMIN_EMAIL="${ADMIN_EMAIL:-$(git config user.email)}"
  12. ADMIN_EMAIL="${ADMIN_EMAIL:-$USER@$(hostname)}"
  13. if [[ -z "${REPO_ROOT}" ]]; then
  14. REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")
  15. while [ -h "${REPO_ROOT}" ] ; do
  16. REPO_ROOT=$(readlink "${REPO_ROOT}")
  17. done
  18. REPO_ROOT=$(cd "${REPO_ROOT}/.." && pwd -P )
  19. fi
  20. if [[ -z ${TEMPLATES} ]]; then
  21. TEMPLATES="${REPO_ROOT}/utils/templates"
  22. fi
  23. if [[ -z "$CACHE" ]]; then
  24. CACHE="${REPO_ROOT}/cache"
  25. fi
  26. if [[ -z ${DIFF_CMD} ]]; then
  27. DIFF_CMD="diff -u"
  28. if command -v colordiff >/dev/null; then
  29. DIFF_CMD="colordiff -u"
  30. fi
  31. fi
  32. DOT_CONFIG="${DOT_CONFIG:-${REPO_ROOT}/.config.sh}"
  33. source_dot_config() {
  34. if [[ ! -e "${DOT_CONFIG}" ]]; then
  35. err_msg "configuration does not extsts at: ${DOT_CONFIG}"
  36. return 42
  37. fi
  38. # shellcheck disable=SC1090
  39. source "${DOT_CONFIG}"
  40. }
  41. sudo_or_exit() {
  42. # usage: sudo_or_exit
  43. if [ ! "$(id -u)" -eq 0 ]; then
  44. err_msg "this command requires root (sudo) privilege!" >&2
  45. exit 42
  46. fi
  47. }
  48. required_commands() {
  49. # usage: required_commands [cmd1 ...]
  50. local exit_val=0
  51. while [ -n "$1" ]; do
  52. if ! command -v "$1" &>/dev/null; then
  53. err_msg "missing command $1"
  54. exit_val=42
  55. fi
  56. shift
  57. done
  58. return $exit_val
  59. }
  60. # colors
  61. # ------
  62. # shellcheck disable=SC2034
  63. set_terminal_colors() {
  64. _colors=8
  65. _creset='\e[0m' # reset all attributes
  66. _Black='\e[0;30m'
  67. _White='\e[1;37m'
  68. _Red='\e[0;31m'
  69. _Green='\e[0;32m'
  70. _Yellow='\e[0;33m'
  71. _Blue='\e[0;34m'
  72. _Violet='\e[0;35m'
  73. _Cyan='\e[0;36m'
  74. _BBlack='\e[1;30m'
  75. _BWhite='\e[1;37m'
  76. _BRed='\e[1;31m'
  77. _BGreen='\e[1;32m'
  78. _BYellow='\e[1;33m'
  79. _BBlue='\e[1;34m'
  80. _BPurple='\e[1;35m'
  81. _BCyan='\e[1;36m'
  82. }
  83. if [ ! -p /dev/stdout ]; then
  84. set_terminal_colors
  85. fi
  86. # reST
  87. # ----
  88. if command -v fmt >/dev/null; then
  89. export FMT="fmt -u"
  90. else
  91. export FMT="cat"
  92. fi
  93. rst_title() {
  94. # usage: rst_title <header-text> [part|chapter|section]
  95. case ${2-chapter} in
  96. part) printf "\n${_BGreen}${1//?/=}\n${_BCyan}${1}${_BGreen}\n${1//?/=}${_creset}\n";;
  97. chapter) printf "\n${_BCyan}${1}\n${_BGreen}${1//?/=}${_creset}\n";;
  98. section) printf "\n${_BCyan}${1}\n${_BGreen}${1//?/-}${_creset}\n";;
  99. *)
  100. err_msg "invalid argument '${2}' in line $(caller)"
  101. return 42
  102. ;;
  103. esac
  104. }
  105. rst_para() {
  106. # usage: RST_INDENT=1 rst_para "lorem ipsum ..."
  107. local prefix=''
  108. if [[ -n $RST_INDENT ]] && [[ $RST_INDENT -gt 0 ]]; then
  109. prefix="$(for i in $(seq 1 "$RST_INDENT"); do printf " "; done)"
  110. echo -en "\n$*\n" | $FMT | prefix_stdout "$prefix"
  111. else
  112. echo -en "\n$*\n" | $FMT
  113. fi
  114. }
  115. err_msg() { echo -e "${_BRed}ERROR:${_creset} $*" >&2; }
  116. warn_msg() { echo -e "${_BBlue}WARN:${_creset} $*" >&2; }
  117. info_msg() { echo -e "${_BYellow}INFO:${_creset} $*" >&2; }
  118. clean_stdin() {
  119. if [[ $(uname -s) != 'Darwin' ]]; then
  120. while read -r -n1 -t 0.1; do : ; done
  121. fi
  122. }
  123. wait_key(){
  124. # usage: waitKEY [<timeout in sec>]
  125. clean_stdin
  126. local _t=$1
  127. local msg="${MSG}"
  128. [[ -z "$msg" ]] && msg="${_Green}** press any [${_BCyan}KEY${_Green}] to continue **${_creset}"
  129. [[ -n $FORCE_TIMEOUT ]] && _t=$FORCE_TIMEOUT
  130. [[ -n $_t ]] && _t="-t $_t"
  131. printf "$msg"
  132. # shellcheck disable=SC2086
  133. read -r -s -n1 $_t
  134. echo
  135. clean_stdin
  136. }
  137. ask_yn() {
  138. # usage: ask_yn <prompt-text> [Ny|Yn] [<timeout in sec>]
  139. local EXIT_YES=0 # exit status 0 --> successful
  140. local EXIT_NO=1 # exit status 1 --> error code
  141. local _t=$3
  142. [[ -n $FORCE_TIMEOUT ]] && _t=$FORCE_TIMEOUT
  143. [[ -n $_t ]] && _t="-t $_t"
  144. case "${FORCE_SELECTION:-${2}}" in
  145. Y) return ${EXIT_YES} ;;
  146. N) return ${EXIT_NO} ;;
  147. Yn)
  148. local exit_val=${EXIT_YES}
  149. local choice="[${_BGreen}YES${_creset}/no]"
  150. local default="Yes"
  151. ;;
  152. *)
  153. local exit_val=${EXIT_NO}
  154. local choice="[${_BGreen}NO${_creset}/yes]"
  155. local default="No"
  156. ;;
  157. esac
  158. echo
  159. while true; do
  160. clean_stdin
  161. printf "$1 ${choice} "
  162. # shellcheck disable=SC2086
  163. read -r -n1 $_t
  164. if [[ -z $REPLY ]]; then
  165. printf "$default\n"; break
  166. elif [[ $REPLY =~ ^[Yy]$ ]]; then
  167. exit_val=${EXIT_YES}
  168. printf "\n"
  169. break
  170. elif [[ $REPLY =~ ^[Nn]$ ]]; then
  171. exit_val=${EXIT_NO}
  172. printf "\n"
  173. break
  174. fi
  175. _t=""
  176. err_msg "invalid choice"
  177. done
  178. clean_stdin
  179. return $exit_val
  180. }
  181. tee_stderr () {
  182. # usage::
  183. # tee_stderr 1 <<EOF | python -i
  184. # print("hello")
  185. # EOF
  186. # ...
  187. # >>> print("hello")
  188. # hello
  189. local _t="0";
  190. if [[ -n $1 ]] ; then _t="$1"; fi
  191. (while read -r line; do
  192. # shellcheck disable=SC2086
  193. sleep $_t
  194. echo -e "$line" >&2
  195. echo "$line"
  196. done)
  197. }
  198. prefix_stdout () {
  199. # usage: <cmd> | prefix_stdout [prefix]
  200. local prefix="${_BYellow}-->|${_creset}"
  201. if [[ -n $1 ]] ; then prefix="${_BYellow}$1${_creset}"; fi
  202. # shellcheck disable=SC2162
  203. (while IFS= read line; do
  204. echo -e "${prefix}$line"
  205. done)
  206. }
  207. append_line() {
  208. # usage: append_line <line> <file>
  209. #
  210. # Append line if not exists, create file if not exists. E.g::
  211. #
  212. # append_line 'source ~/.foo' ~/bashrc
  213. local LINE=$1
  214. local FILE=$2
  215. grep -qFs -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"
  216. }
  217. cache_download() {
  218. # usage: cache_download <url> <local-filename>
  219. local exit_value=0
  220. if [[ -n ${SUDO_USER} ]]; then
  221. sudo -u "${SUDO_USER}" mkdir -p "${CACHE}"
  222. else
  223. mkdir -p "${CACHE}"
  224. fi
  225. if [[ -f "${CACHE}/$2" ]] ; then
  226. info_msg "already cached: $1"
  227. info_msg " --> ${CACHE}/$2"
  228. fi
  229. if [[ ! -f "${CACHE}/$2" ]]; then
  230. info_msg "caching: $1"
  231. info_msg " --> ${CACHE}/$2"
  232. if [[ -n ${SUDO_USER} ]]; then
  233. sudo -u "${SUDO_USER}" wget --progress=bar -O "${CACHE}/$2" "$1" ; exit_value=$?
  234. else
  235. wget --progress=bar -O "${CACHE}/$2" "$1" ; exit_value=$?
  236. fi
  237. if [[ ! $exit_value = 0 ]]; then
  238. err_msg "failed to download: $1"
  239. fi
  240. fi
  241. }
  242. choose_one() {
  243. # usage:
  244. #
  245. # DEFAULT_SELECT= 2 \
  246. # choose_one <name> "your selection?" "Coffee" "Coffee with milk"
  247. local default=${DEFAULT_SELECT-1}
  248. local REPLY
  249. local env_name=$1 && shift
  250. local choice=$1;
  251. local max="${#@}"
  252. local _t
  253. [[ -n $FORCE_TIMEOUT ]] && _t=$FORCE_TIMEOUT
  254. [[ -n $_t ]] && _t="-t $_t"
  255. list=("$@")
  256. echo -e "${_BGreen}Menu::${_creset}"
  257. for ((i=1; i<= $((max -1)); i++)); do
  258. if [[ "$i" == "$default" ]]; then
  259. echo -e " ${_BGreen}$i.${_creset}) ${list[$i]} [default]"
  260. else
  261. echo -e " $i.) ${list[$i]}"
  262. fi
  263. done
  264. while true; do
  265. clean_stdin
  266. printf "$1 [${_BGreen}$default${_creset}] "
  267. if (( 10 > max )); then
  268. # shellcheck disable=SC2086
  269. read -r -n1 $_t
  270. else
  271. # shellcheck disable=SC2086,SC2229
  272. read -r $_t
  273. fi
  274. # selection fits
  275. [[ $REPLY =~ ^-?[0-9]+$ ]] && (( REPLY > 0 )) && (( REPLY < max )) && break
  276. # take default
  277. [[ -z $REPLY ]] && REPLY=$default && break
  278. _t=""
  279. err_msg "invalid choice"
  280. done
  281. eval "$env_name"='${list[${REPLY}]}'
  282. echo
  283. clean_stdin
  284. }
  285. install_template() {
  286. # usage:
  287. #
  288. # install_template [--no-eval] [--variant=<name>] \
  289. # {file} [{owner} [{group} [{chmod}]]]
  290. #
  291. # E.g. the origin of variant 'raw' of /etc/updatedb.conf is::
  292. #
  293. # ${TEMPLATES}/etc/updatedb.conf:raw
  294. #
  295. # To install variant 'raw' of /etc/updatedb.conf without evaluated
  296. # replacements you can use::
  297. #
  298. # install_template --variant=raw --no-eval \
  299. # /etc/updatedb.conf root root 644
  300. local _reply=""
  301. local do_eval=1
  302. local variant=""
  303. local pos_args=("$0")
  304. for i in "$@"; do
  305. case $i in
  306. --no-eval) do_eval=0; shift ;;
  307. --variant=*) variant=":${i#*=}"; shift ;;
  308. *) pos_args+=("$i") ;;
  309. esac
  310. done
  311. local dst="${pos_args[1]}"
  312. local template_origin="${TEMPLATES}${dst}${variant}"
  313. local template_file="${TEMPLATES}${dst}"
  314. local owner="${pos_args[2]-$(id -un)}"
  315. local group="${pos_args[3]-$(id -gn)}"
  316. local chmod="${pos_args[4]-644}"
  317. info_msg "install (eval=$do_eval): ${dst}"
  318. [[ -n $variant ]] && info_msg "variant: ${variant}"
  319. if [[ ! -f "${template_origin}" ]] ; then
  320. err_msg "${template_origin} does not exists"
  321. err_msg "... can't install $dst"
  322. wait_key 30
  323. return 42
  324. fi
  325. if [[ "$do_eval" == "1" ]]; then
  326. template_file="${CACHE}${dst}${variant}"
  327. info_msg "BUILD template ${template_file}"
  328. if [[ -n ${SUDO_USER} ]]; then
  329. sudo -u "${SUDO_USER}" mkdir -p "$(dirname "${template_file}")"
  330. else
  331. mkdir -p "$(dirname "${template_file}")"
  332. fi
  333. # shellcheck disable=SC2086
  334. eval "echo \"$(cat ${template_origin})\"" > "${template_file}"
  335. if [[ -n ${SUDO_USER} ]]; then
  336. chown "${SUDO_USER}:${SUDO_USER}" "${template_file}"
  337. fi
  338. else
  339. template_file=$template_origin
  340. fi
  341. mkdir -p "$(dirname "${dst}")"
  342. if [[ ! -f "${dst}" ]]; then
  343. info_msg "install: ${template_file}"
  344. sudo -H install -v -o "${owner}" -g "${group}" -m "${chmod}" \
  345. "${template_file}" "${dst}" | prefix_stdout
  346. return $?
  347. fi
  348. if [[ -f "${dst}" ]] && cmp --silent "${template_file}" "${dst}" ; then
  349. info_msg "file ${dst} allready installed"
  350. return 0
  351. fi
  352. info_msg "diffrent file ${dst} allready exists on this host"
  353. while true; do
  354. choose_one _reply "choose next step with file $dst" \
  355. "replace file" \
  356. "leave file unchanged" \
  357. "interactiv shell" \
  358. "diff files"
  359. case $_reply in
  360. "replace file")
  361. info_msg "install: ${template_file}"
  362. sudo -H install -v -o "${owner}" -g "${group}" -m "${chmod}" \
  363. "${template_file}" "${dst}" | prefix_stdout
  364. break
  365. ;;
  366. "leave file unchanged")
  367. break
  368. ;;
  369. "interactiv shell")
  370. echo "// edit ${dst} to your needs"
  371. echo -e "// exit with [${_BCyan}CTRL-D${_creset}]"
  372. sudo -H -u "${owner}" -i
  373. $DIFF_CMD "${dst}" "${template_file}"
  374. echo
  375. echo "${_BBlack}did you edit file ...${_creset}"
  376. printf " ${template_file}"
  377. if ask_yn "... to your needs?"; then
  378. break
  379. fi
  380. ;;
  381. "diff files")
  382. $DIFF_CMD "${dst}" "${template_file}" | prefix_stdout
  383. esac
  384. done
  385. }
  386. service_is_available() {
  387. # usage: service_is_available <URL>
  388. local URL="$1"
  389. if [[ -z $URL ]]; then
  390. err_msg "service_is_available: missing arguments"
  391. return 42
  392. fi
  393. http_code=$(curl -H 'Cache-Control: no-cache' \
  394. --silent -o /dev/null --head --write-out '%{http_code}' --insecure \
  395. "${URL}")
  396. exit_val=$?
  397. if [[ $exit_val = 0 ]]; then
  398. info_msg "got $http_code from ${URL}"
  399. fi
  400. case "$http_code" in
  401. 404|410|423) exit_val=$http_code;;
  402. esac
  403. return "$exit_val"
  404. }
  405. # golang
  406. # ------
  407. go_is_available() {
  408. # usage: go_is_available $SERVICE_USER && echo "go is installed!"
  409. sudo -i -u "${1}" which go &>/dev/null
  410. }
  411. install_go() {
  412. # usage: install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  413. local _svcpr=" |${3}| "
  414. rst_title "Install Go in user's HOME" section
  415. rst_para "download and install go binary .."
  416. cache_download "${1}" "${2}"
  417. tee_stderr 0.1 <<EOF | sudo -i -u "${3}" | prefix_stdout "$_svcpr"
  418. echo \$PATH
  419. echo \$GOPATH
  420. mkdir -p \$HOME/local
  421. rm -rf \$HOME/local/go
  422. tar -C \$HOME/local -xzf ${CACHE}/${2}
  423. EOF
  424. sudo -i -u "${3}" <<EOF | prefix_stdout
  425. ! which go >/dev/null && echo "ERROR - Go Installation not found in PATH!?!"
  426. which go >/dev/null && go version && echo "congratulations -- Go installation OK :)"
  427. EOF
  428. }
  429. # system accounts
  430. # ---------------
  431. service_account_is_available() {
  432. # usage: service_account_is_available "$SERVICE_USER" && echo "OK"
  433. sudo -i -u "$1" echo \$HOME &>/dev/null
  434. }
  435. drop_service_account() {
  436. # usage: drop_service_account "${SERVICE_USER}"
  437. rst_title "Drop ${1} HOME" section
  438. if ask_yn "Do you really want to drop ${1} home folder?"; then
  439. userdel -r -f "${1}" 2>&1 | prefix_stdout
  440. else
  441. rst_para "Leave HOME folder $(du -sh "${1}") unchanged."
  442. fi
  443. }
  444. interactive_shell(){
  445. # usage: interactive_shell "${SERVICE_USER}"
  446. echo -e "// exit with [${_BCyan}CTRL-D${_creset}]"
  447. sudo -H -u "${1}" -i
  448. }
  449. # systemd
  450. # -------
  451. SYSTEMD_UNITS="${SYSTEMD_UNITS:-/lib/systemd/system}"
  452. systemd_install_service() {
  453. # usage: systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  454. rst_title "Install System-D Unit ${1}" section
  455. echo
  456. install_template "${2}" root root 644
  457. wait_key
  458. systemd_activate_service "${1}"
  459. }
  460. systemd_remove_service() {
  461. # usage: systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  462. if ! ask_yn "Do you really want to deinstall systemd unit ${1}?"; then
  463. return 42
  464. fi
  465. systemd_deactivate_service "${1}"
  466. rm "${2}" 2>&1 | prefix_stdout
  467. }
  468. systemd_activate_service() {
  469. # usage: systemd_activate_service "${SERVICE_NAME}"
  470. rst_title "Activate ${1} (service)" section
  471. echo
  472. tee_stderr <<EOF | bash 2>&1
  473. systemctl enable ${1}.service
  474. systemctl restart ${1}.service
  475. EOF
  476. tee_stderr <<EOF | bash 2>&1
  477. systemctl status --no-pager ${1}.service
  478. EOF
  479. }
  480. systemd_deactivate_service() {
  481. # usage: systemd_deactivate_service "${SERVICE_NAME}"
  482. rst_title "De-Activate ${1} (service)" section
  483. echo
  484. tee_stderr <<EOF | bash 2>&1 | prefix_stdout
  485. systemctl stop ${1}.service
  486. systemctl disable ${1}.service
  487. EOF
  488. }
  489. systemd_restart_service() {
  490. # usage: systemd_restart_service "${SERVICE_NAME}"
  491. rst_title "Restart ${1} (service)" section
  492. echo
  493. tee_stderr <<EOF | bash 2>&1
  494. systemctl restart ${1}.service
  495. EOF
  496. tee_stderr <<EOF | bash 2>&1
  497. systemctl status --no-pager ${1}.service
  498. EOF
  499. }
  500. # Apache
  501. # ------
  502. # FIXME: Arch Linux & RHEL should be added
  503. if [[ -z "${APACHE_SITES_AVAILABE}" ]]; then
  504. APACHE_SITES_AVAILABE="/etc/apache2/sites-available"
  505. fi
  506. apache_is_installed() {
  507. (command -v apachectl \
  508. && command -v a2ensite \
  509. && command -v a2dissite ) &>/dev/null
  510. }
  511. apache_reload() {
  512. info_msg "reload apache .."
  513. echo
  514. sudo -H apachectl configtest
  515. sudo -H service apache2 force-reload
  516. }
  517. apache_install_site() {
  518. # usage: apache_install_site [<template option> ...] <mysite.conf>
  519. #
  520. # <template option>: see install_template
  521. local template_opts=()
  522. local pos_args=("$0")
  523. for i in "$@"; do
  524. case $i in
  525. -*) template_opts+=("$i");;
  526. *) pos_args+=("$i");;
  527. esac
  528. done
  529. install_template "${template_opts[@]}" \
  530. "${APACHE_SITES_AVAILABE}/${pos_args[1]}" \
  531. root root 644
  532. apache_enable_site "${pos_args[1]}"
  533. info_msg "installed apache site: ${pos_args[1]}"
  534. }
  535. apache_remove_site() {
  536. # usage: apache_remove_site <mysite.conf>
  537. info_msg "remove apache site: $1"
  538. apache_dissable_site "$1"
  539. rm -f "${APACHE_SITES_AVAILABE}/$1"
  540. }
  541. apache_enable_site() {
  542. # usage: apache_enable_site <mysite.conf>
  543. info_msg "enable apache site: $1"
  544. sudo -H a2ensite -q "$1"
  545. apache_reload
  546. }
  547. apache_dissable_site() {
  548. # usage: apache_disable_site <mysite.conf>
  549. info_msg "disable apache site: $1"
  550. sudo -H a2dissite -q "$1"
  551. apache_reload
  552. }
  553. # uWSGI
  554. # -----
  555. uWSGI_SETUP="${uWSGI_SETUP:=/etc/uwsgi}"
  556. uWSGI_restart() {
  557. # usage: uWSGI_restart()
  558. info_msg "restart uWSGI service"
  559. systemctl restart uwsgi
  560. }
  561. uWSGI_app_available() {
  562. # usage: uWSGI_app_available <myapp.ini>
  563. local CONF="$1"
  564. if [[ -z $CONF ]]; then
  565. err_msg "uWSGI_app_available: missing arguments"
  566. return 42
  567. fi
  568. [[ -f "${uWSGI_SETUP}/apps-available/${CONF}" ]]
  569. }
  570. uWSGI_install_app() {
  571. # usage: uWSGI_install_app [<template option> ...] <myapp.ini>
  572. #
  573. # <template option>: see install_template
  574. local pos_args=("$0")
  575. for i in "$@"; do
  576. case $i in
  577. -*) template_opts+=("$i");;
  578. *) pos_args+=("$i");;
  579. esac
  580. done
  581. install_template "${template_opts[@]}" \
  582. "${uWSGI_SETUP}/apps-available/${pos_args[1]}" \
  583. root root 644
  584. uWSGI_enable_app "${pos_args[1]}"
  585. uWSGI_restart
  586. info_msg "installed uWSGI app: ${pos_args[1]}"
  587. }
  588. uWSGI_remove_app() {
  589. # usage: uWSGI_remove_app <myapp.ini>
  590. local CONF="$1"
  591. info_msg "remove uWSGI app: ${CONF}"
  592. uWSGI_disable_app "${CONF}"
  593. uWSGI_restart
  594. rm -f "${uWSGI_SETUP}/apps-available/${CONF}"
  595. }
  596. uWSGI_app_enabled() {
  597. # usage: uWSGI_app_enabled <myapp.ini>
  598. local CONF="$1"
  599. if [[ -z $CONF ]]; then
  600. err_msg "uWSGI_app_enabled: missing arguments"
  601. return 42
  602. fi
  603. [[ -f "${uWSGI_SETUP}/apps-enabled/${CONF}" ]]
  604. }
  605. # shellcheck disable=SC2164
  606. uWSGI_enable_app() {
  607. # usage: uWSGI_enable_app <myapp.ini>
  608. local CONF="$1"
  609. if [[ -z $CONF ]]; then
  610. err_msg "uWSGI_enable_app: missing arguments"
  611. return 42
  612. fi
  613. pushd "${uWSGI_SETUP}/apps-enabled" >/dev/null
  614. rm -f "$CONF"
  615. # shellcheck disable=SC2226
  616. ln -s "../apps-available/${CONF}"
  617. info_msg "enabled uWSGI app: ${CONF} (restart uWSGI required)"
  618. popd >/dev/null
  619. }
  620. uWSGI_disable_app() {
  621. # usage: uWSGI_disable_app <myapp.ini>
  622. local CONF="$1"
  623. if [[ -z $CONF ]]; then
  624. err_msg "uWSGI_enable_app: missing arguments"
  625. return 42
  626. fi
  627. rm -f "${uWSGI_SETUP}/apps-enabled/${CONF}"
  628. # FIXME: restart uwsgi service won't stop wsgi forked processes of user searx.
  629. # I had to kill them manually here ...
  630. pkill -f "${uWSGI_SETUP}/apps-enabled/${CONF}" -9
  631. info_msg "disabled uWSGI app: ${CONF} (restart uWSGI required)"
  632. }
  633. # distro's package manager
  634. # ------------------------
  635. pkg_install() {
  636. # usage: TITEL='install foobar' pkg_install foopkg barpkg
  637. rst_title "${TITLE:-installation of packages}" section
  638. echo -en "\npackage(s)::\n\n $*\n" | $FMT
  639. if ! ask_yn "Should packages be installed?" Yn 30; then
  640. return 42
  641. fi
  642. case $DIST_ID in
  643. ubuntu|debian)
  644. # shellcheck disable=SC2068
  645. apt-get install -m -y $@
  646. ;;
  647. arch)
  648. # shellcheck disable=SC2068
  649. pacman -S --noconfirm $@
  650. ;;
  651. fedora)
  652. # shellcheck disable=SC2068
  653. dnf install -y $@
  654. ;;
  655. esac
  656. }
  657. pkg_remove() {
  658. # usage: TITEL='remove foobar' pkg_remove foopkg barpkg
  659. rst_title "${TITLE:-remove packages}" section
  660. echo -en "\npackage(s)::\n\n $*\n" | $FMT
  661. if ! ask_yn "Should packages be removed (purge)?" Yn 30; then
  662. return 42
  663. fi
  664. case $DIST_ID in
  665. ubuntu|debian)
  666. # shellcheck disable=SC2068
  667. apt-get purge --autoremove --ignore-missing -y $@
  668. ;;
  669. arch)
  670. # shellcheck disable=SC2068
  671. pacman -R --noconfirm $@
  672. ;;
  673. fedora)
  674. # shellcheck disable=SC2068
  675. dnf remove -y $@
  676. ;;
  677. esac
  678. }
  679. pkg_is_installed() {
  680. # usage: pkg_is_install foopkg || pkg_install foopkg
  681. case $DIST_ID in
  682. ubuntu|debian)
  683. dpkg -l "$1" &> /dev/null
  684. return $?
  685. ;;
  686. arch)
  687. pacman -Qsq "$1" &> /dev/null
  688. return $?
  689. ;;
  690. fedora)
  691. dnf list -q --installed "$1" &> /dev/null
  692. return $?
  693. ;;
  694. esac
  695. }
  696. # git tooling
  697. # -----------
  698. # shellcheck disable=SC2164
  699. git_clone() {
  700. # usage:
  701. #
  702. # git_clone <url> <name> [<branch> [<user>]]
  703. # git_clone <url> <path> [<branch> [<user>]]
  704. #
  705. # First form uses $CACHE/<name> as destination folder, second form clones
  706. # into <path>. If repository is allready cloned, pull from <branch> and
  707. # update working tree (if needed, the caller has to stash local changes).
  708. #
  709. # git clone https://github.com/asciimoo/searx searx-src origin/master searxlogin
  710. #
  711. local url="$1"
  712. local dest="$2"
  713. local branch="$3"
  714. local user="$4"
  715. local bash_cmd="bash"
  716. local remote="origin"
  717. if [[ ! "${dest:0:1}" = "/" ]]; then
  718. dest="$CACHE/$dest"
  719. fi
  720. [[ -z $branch ]] && branch=master
  721. [[ -z $user ]] && [[ -n "${SUDO_USER}" ]] && user="${SUDO_USER}"
  722. [[ -n $user ]] && bash_cmd="sudo -H -u $user -i"
  723. if [[ -d "${dest}" ]] ; then
  724. info_msg "already cloned: $dest"
  725. tee_stderr 0.1 <<EOF | $bash_cmd 2>&1 | prefix_stdout " |$user| "
  726. cd "${dest}"
  727. git checkout -m -B "$branch" --track "$remote/$branch"
  728. git pull --all
  729. EOF
  730. else
  731. info_msg "clone into: $dest"
  732. tee_stderr 0.1 <<EOF | $bash_cmd 2>&1 | prefix_stdout " |$user| "
  733. mkdir -p "$(dirname "$dest")"
  734. cd "$(dirname "$dest")"
  735. git clone --branch "$branch" --origin "$remote" "$url" "$(basename "$dest")"
  736. EOF
  737. fi
  738. }