2# -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
3# shellcheck disable=SC2059,SC1117,SC2162,SC2004
5ADMIN_NAME="${ADMIN_NAME:-$(git config user.name)}"
6ADMIN_NAME="${ADMIN_NAME:-$USER}"
8ADMIN_EMAIL="${ADMIN_EMAIL:-$(git config user.email)}"
9ADMIN_EMAIL="${ADMIN_EMAIL:-$USER@$(hostname)}"
11if [[ -z "${REPO_ROOT}" ]]; then
12 REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")
13 while [ -h "${REPO_ROOT}" ] ; do
14 REPO_ROOT=$(readlink "${REPO_ROOT}")
16 REPO_ROOT=$(cd "${REPO_ROOT}/.." && pwd -P )
19if [[ -z ${TEMPLATES} ]]; then
20 TEMPLATES="${REPO_ROOT}/utils/templates"
23if [[ -z "$CACHE" ]]; then
24 CACHE="${REPO_ROOT}/cache"
27if [[ -z "$SYSTEMD_UNITS" ]]; then
28 SYSTEMD_UNITS="/lib/systemd/system"
31if [[ -z ${DIFF_CMD} ]]; then
33 if command -v colordiff >/dev/null; then
34 DIFF_CMD="colordiff -u"
41 if [ ! "$(id -u)" -eq 0 ]; then
42 err_msg "this command requires root (sudo) privilege!" >&2
48 # usage: rst_title <header-text> [part|chapter|section]
51 part) printf "\n${1//?/=}\n$1\n${1//?/=}\n";;
52 chapter) printf "\n${1}\n${1//?/=}\n";;
53 section) printf "\n${1}\n${1//?/-}\n";;
55 err_msg "invalid argument '${2}' in line $(caller)"
61if command -v fmt >/dev/null; then
68 # usage: RST_INDENT=1 rst_para "lorem ipsum ..."
70 if ! [[ -z $RST_INDENT ]] && [[ $RST_INDENT -gt 0 ]]; then
71 prefix="$(for i in $(seq 1 "$RST_INDENT"); do printf " "; done)"
72 echo -en "\n$*\n" | $FMT | prefix_stdout "$prefix"
74 echo -en "\n$*\n" | $FMT
78err_msg() { echo -e "ERROR: $*" >&2; }
79warn_msg() { echo -e "WARN: $*" >&2; }
80info_msg() { echo -e "INFO: $*"; }
83 if [[ $(uname -s) != 'Darwin' ]]; then
84 while read -n1 -t 0.1; do : ; done
89 # usage: waitKEY [<timeout in sec>]
93 [[ ! -z $FORCE_TIMEOUT ]] && _t=$FORCE_TIMEOUT
94 [[ ! -z $_t ]] && _t="-t $_t"
95 # shellcheck disable=SC2086
96 read -s -n1 $_t -p "** press any [KEY] to continue **"
102 # usage: ask_yn <prompt-text> [Ny|Yn] [<timeout in sec>]
104 local EXIT_YES=0 # exit status 0 --> successful
105 local EXIT_NO=1 # exit status 1 --> error code
108 [[ ! -z $FORCE_TIMEOUT ]] && _t=$FORCE_TIMEOUT
109 [[ ! -z $_t ]] && _t="-t $_t"
112 local exit_val=${EXIT_YES}
113 local choice="[YES/no]"
117 local exit_val=${EXIT_NO}
118 local choice="[NO/yes]"
125 printf "$1 ${choice} "
126 # shellcheck disable=SC2086
128 if [[ -z $REPLY ]]; then
129 printf "$default\n"; break
130 elif [[ $REPLY =~ ^[Yy]$ ]]; then
134 elif [[ $REPLY =~ ^[Nn]$ ]]; then
140 err_msg "invalid choice"
149 # tee_stderr 1 <<EOF | python -i
157 if [[ ! -z $1 ]] ; then _t="$1"; fi
160 # shellcheck disable=SC2086
168 # usage: <cmd> | prefix_stdout [prefix]
172 if [[ ! -z $1 ]] ; then prefix="$1"; fi
174 (while IFS= read line; do
175 echo -e "${prefix}$line"
181 # usage: append_line <line> <file>
183 # Append line if not exists, create file if not exists. E.g::
185 # append_line 'source ~/.foo' ~/bashrc
189 grep -qFs -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"
194 # usage: cache_download <url> <local-filename>
198 if [[ ! -z ${SUDO_USER} ]]; then
199 sudo -u "${SUDO_USER}" mkdir -p "${CACHE}"
204 if [[ -f "${CACHE}/$2" ]] ; then
205 info_msg "already cached: $1"
206 info_msg " --> ${CACHE}/$2"
209 if [[ ! -f "${CACHE}/$2" ]]; then
210 info_msg "caching: $1"
211 info_msg " --> ${CACHE}/$2"
212 if [[ ! -z ${SUDO_USER} ]]; then
213 sudo -u "${SUDO_USER}" wget --progress=bar -O "${CACHE}/$2" "$1" ; exit_value=$?
215 wget --progress=bar -O "${CACHE}/$2" "$1" ; exit_value=$?
218 err_msg "failed to download: $1"
227 # DEFAULT_SELECT= 2 \
228 # choose_one <name> "your selection?" "Coffee" "Coffee with milk"
230 local default=${DEFAULT_SELECT-1}
232 local env_name=$1 && shift
236 [[ ! -z $FORCE_TIMEOUT ]] && _t=$FORCE_TIMEOUT
237 [[ ! -z $_t ]] && _t="-t $_t"
241 for ((i=1; i<= $(($max -1)); i++)); do
242 if [[ "$i" == "$default" ]]; then
243 echo -e " $i.) ${list[$i]} [default]"
245 echo -e " $i.) ${list[$i]}"
250 printf "$1 [$default] "
252 if (( 10 > $max )); then
253 # shellcheck disable=SC2086
256 # shellcheck disable=SC2086,SC2229
260 [[ $REPLY =~ ^-?[0-9]+$ ]] && (( $REPLY > 0 )) && (( $REPLY < $max )) && break
263 [[ -z $REPLY ]] && REPLY=$default && break
266 err_msg "invalid choice"
268 eval "$env_name"='${list[${REPLY}]}'
277 # install_template [--no-eval] {file} [{owner} [{group} [{chmod}]]]
279 # install_template --no-eval /etc/updatedb.conf root root 644
282 if [[ "$1" == "--no-eval" ]]; then
286 local owner=${2-$(id -un)}
287 local group=${3-$(id -gn)}
291 info_msg "install: ${dst}"
293 if [[ ! -f "${TEMPLATES}${dst}" ]] ; then
294 err_msg "${TEMPLATES}${dst} does not exists"
295 err_msg "... can't install $dst / exit installation with error 42"
300 local template_file="${TEMPLATES}${dst}"
301 if [[ "$do_eval" == "1" ]]; then
302 info_msg "BUILD template ${template_file}"
303 if [[ -f "${TEMPLATES}${dst}" ]] ; then
304 template_file="${CACHE}${dst}"
305 mkdir -p "$(dirname "${template_file}")"
306 # shellcheck disable=SC2086
307 eval "echo \"$(cat ${TEMPLATES}${dst})\"" > "${template_file}"
309 err_msg "failed ${template_file}"
314 mkdir -p "$(dirname "${dst}")"
316 if [[ ! -f "${dst}" ]]; then
317 info_msg "install: ${template_file}"
318 sudo -H install -v -o "${owner}" -g "${group}" -m "${chmod}" \
319 "${template_file}" "${dst}" | prefix_stdout
323 if [[ -f "${dst}" ]] && cmp --silent "${template_file}" "${dst}" ; then
324 info_msg "file ${dst} allready installed"
328 info_msg "file ${dst} allready exists on this host"
331 choose_one _reply "choose next step with file $dst" \
333 "leave file unchanged" \
339 info_msg "install: ${template_file}"
340 sudo -H install -v -o "${owner}" -g "${group}" -m "${chmod}" \
341 "${template_file}" "${dst}" | prefix_stdout
344 "leave file unchanged")
348 echo "// edit ${dst} to your needs"
349 echo "// exit with CTRL-D"
350 sudo -H -u "${owner}" -i
351 $DIFF_CMD "${dst}" "${template_file}"
352 if ask_yn "did you edit ${template_file} to your needs?"; then
357 $DIFF_CMD "${dst}" "${template_file}" | prefix_stdout
365# FIXME: Arch Linux & RHEL should be added
367if [[ -z "${APACHE_SITES_AVAILABE}" ]]; then
368 APACHE_SITES_AVAILABE="/etc/apache2/sites-available"
371apache_is_installed() {
372 (command -v apachectl \
373 && command -v a2ensite \
374 && command -v a2dissite ) &>/dev/null
379 info_msg "reload apache .."
381 sudo -H apachectl configtest
382 sudo -H service apache2 force-reload
385apache_install_site() {
387 # usage: apache_install_site [--no-eval] <mysite.conf>
392 if [[ "$1" == "--no-eval" ]]; then
396 # shellcheck disable=SC2086
397 install_template $no_eval "${APACHE_SITES_AVAILABE}/${CONF}" root root 644
399 apache_enable_site "${CONF}"
401 info_msg "installed apache site: ${CONF}"
404apache_enable_site() {
405 info_msg "enable apache site $1 .."
406 sudo -H a2ensite -q "$1"
410apache_dissable_site() {
411 info_msg "disable apache site $1 .."
412 sudo -H a2dissite -q "$1"
419uWSGI_SETUP="${uWSGI_SETUP:=/etc/uwsgi}"
423 # usage: uWSGI_restart()
425 info_msg "restart uWSGI service"
426 sudo -H systemctl restart uwsgi
429uWSGI_app_available() {
430 # usage: uWSGI_app_available <myapp.ini>
432 if [[ -z $CONF ]]; then
433 err_msg "uWSGI_app_available: missing arguments"
436 [[ -f "${uWSGI_SETUP}/apps-available/${CONF}" ]]
441 # usage: uWSGI_install_app [--no-eval] <myapp.ini>
446 if [[ "$1" == "--no-eval" ]]; then
450 # shellcheck disable=SC2086
451 install_template $no_eval "${uWSGI_SETUP}/apps-available/${CONF}" root root 644
452 uWSGI_enable_app "${CONF}"
454 info_msg "installed uWSGI app: ${CONF}"
459 # usage: uWSGI_remove_app <myapp.ini>
462 uWSGI_disable_app "${CONF}"
464 rm -f "${uWSGI_SETUP}/apps-available/${CONF}"
465 info_msg "removed uWSGI app: ${CONF}"
469 # usage: uWSGI_app_enabled <myapp.ini>
471 if [[ -z $CONF ]]; then
472 err_msg "uWSGI_app_enabled: missing arguments"
475 [[ -f "${uWSGI_SETUP}/apps-enabled/${CONF}" ]]
478# shellcheck disable=SC2164
481 # usage: uWSGI_enable_app <myapp.ini>
484 if [[ -z $CONF ]]; then
485 err_msg "uWSGI_enable_app: missing arguments"
488 pushd "${uWSGI_SETUP}/apps-enabled" >/dev/null
490 # shellcheck disable=SC2226
491 ln -s "../apps-available/${CONF}"
492 info_msg "enabled uWSGI app: ${CONF} (restart uWSGI required)"
498 # usage: uWSGI_disable_app <myapp.ini>
501 if [[ -z $CONF ]]; then
502 err_msg "uWSGI_enable_app: missing arguments"
505 rm -f "${uWSGI_SETUP}/apps-enabled/${CONF}"
506 info_msg "disabled uWSGI app: ${CONF} (restart uWSGI required)"
509# distro's package manager
510# ------------------------
512# FIXME: Arch Linux & RHEL should be added
517 # usage: TITEL='install foobar' pkg_install foopkg barpkg
519 rst_title "${TITLE:-installation of packages}" section
520 echo -en "\npackage(s)::\n\n $*\n" | $FMT
522 if ! ask_yn "Should packages be installed?" Yn 30; then
525 # shellcheck disable=SC2068
526 apt-get install -y $@
531 # usage: TITEL='remove foobar' pkg_remove foopkg barpkg
533 rst_title "${TITLE:-remove packages}" section
534 echo -en "\npackage(s)::\n\n $*\n" | $FMT
536 if ! ask_yn "Should packages be removed (purge)?" Yn 30; then
539 apt-get purge --autoremove --ignore-missing -y "$@"
544 # usage: pkg_is_install foopkg || pkg_install foopkg
546 dpkg -l "$1" &> /dev/null
553# shellcheck disable=SC2164
558 # git_clone <url> <name> [<branch> [<user>]]
559 # git_clone <url> <path> [<branch> [<user>]]
561 # First form uses $CACHE/<name> as destination folder, second form clones
562 # into <path>. If repository is allready cloned, pull from <branch> and
563 # update working tree (if needed, the caller has to stash local changes).
565 # git clone https://github.com/asciimoo/searx searx-src origin/master searxlogin
572 local bash_cmd="bash"
573 local remote="origin"
575 if [[ ! "${dest:0:1}" = "/" ]]; then
579 [[ -z $branch ]] && branch=master
580 [[ -z $user ]] && [[ ! -z "${SUDO_USER}" ]] && user="${SUDO_USER}"
581 [[ ! -z $user ]] && bash_cmd="sudo -H -u $user -i"
583 if [[ -d "${dest}" ]] ; then
584 info_msg "already cloned: $dest"
585 tee_stderr 0.1 <<EOF | $bash_cmd 2>&1 | prefix_stdout " |$user| "
587git checkout -m -B "$branch" --track "$remote/$branch"
591 info_msg "clone into: $dest"
592 tee_stderr 0.1 <<EOF | $bash_cmd 2>&1 | prefix_stdout " |$user| "
593mkdir -p "$(dirname "$dest")"
594cd "$(dirname "$dest")"
595git clone --branch "$branch" --origin "$remote" "$url" "$(basename "$dest")"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list