lib.sh 21 KB

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