Browse Source

miaou-bash added

main
pvincent 2 weeks ago
parent
commit
53a144e0b4
  1. 284
      bash.bashrc
  2. 53
      bin/miaou-bash
  3. 44
      install.sh
  4. 123
      lib/functions.bash

284
bash.bashrc

@ -1,163 +1,169 @@
#!/bin/bash #!/bin/bash
function __prompt_command { function __prompt_command {
local EXIT="$?" # This needs to be first
local R='\[\e[0m\]'
local Red='\[\e[31m\]'
local Gre='\[\e[32m\]'
local Yel='\[\e[93m\]'
local Blu='\[\e[34m\]'
local Cya='\[\e[36m\]'
local Mag='\[\e[95m\]'
local Gra='\[\e[90m\]'
local DIVERGENT_GIT_SYMBOL="${Yel}➾${R}"
local SYNCHRONIZED_GIT_SYMBOL="${Gre}✔${R}"
local PUSHED_NEEDED_SYMBOL='⥱'
local TAG_NEEDED_SYMBOL='⤽'
# set xterm title
echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"
PS1=''
if [[ -n ${container_hostname:-} ]]; then
PS1+="${Gra}[LXC:${R}"
local host
host=$(builtin echo $container_hostname | tr ' ' ':')
case ${host:0:4} in
'beta')
PS1+="${Yel}"
;;
'prod')
PS1+="${Red}"
;;
*) ;;
esac
PS1+="${host}${Gra}] "
fi
if [[ "$(id -u)" -eq 0 ]]; then
PS1+="$Yel\u$R"
PROMPT='$'
else
PS1+="$Gre\u$R"
PROMPT='#'
fi
PS1+="${Gra}@"
case ${HOSTNAME:0:4} in
local EXIT="$?" # This needs to be first
local R='\[\e[0m\]'
local Red='\[\e[31m\]'
local Gre='\[\e[32m\]'
local Yel='\[\e[93m\]'
local Blu='\[\e[34m\]'
local Cya='\[\e[36m\]'
local Mag='\[\e[95m\]'
local Gra='\[\e[90m\]'
local DIVERGENT_GIT_SYMBOL="${Yel}➾${R}"
local SYNCHRONIZED_GIT_SYMBOL="${Gre}✔${R}"
local PUSHED_NEEDED_SYMBOL='⥱'
local TAG_NEEDED_SYMBOL='⤽'
# set xterm title
echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"
PS1=''
if [[ -n ${container_hostname:-} ]]; then
PS1+="${Gra}[LXC:${R}"
local host
host=$(builtin echo $container_hostname | tr ' ' ':')
case ${host:0:4} in
'beta') 'beta')
PS1+="${Yel}"
;;
PS1+="${Yel}"
;;
'prod') 'prod')
PS1+="${Red}"
;;
*)
PS1+="${R}"
;;
PS1+="${Red}"
;;
*) ;;
esac esac
PS1+="$HOSTNAME"
local pwd='~'
[ "$PWD" != "$HOME" ] && pwd=${PWD/#$HOME\//\~\/}
PS1+=" ${Cya}${pwd}$(__vte_osc7)${R}"
if hash git 2>&-; then
# git command exists
if git rev-parse --git-dir >/dev/null 2>&1; then
# current dir is version controlled
local branch tag_release dirty
branch=$(git branch 2>/dev/null | grep -e ^* | cut -d ' ' -f2)
PS1+=" ${R}[${Mag}${branch}${R}|"
tag_release=$(git describe --tags 2>/dev/null | cut -d'-' -f1)
dirty=$(git status -s | wc -l)
if [[ $dirty -ne 0 ]]; then
PS1+="${Yel}${DIVERGENT_GIT_SYMBOL}${R}|${tag_release}${Yel}…$dirty"
PS1+="${host}${Gra}] "
fi
if [[ "$(id -u)" -eq 0 ]]; then
PS1+="$Yel\u$R"
PROMPT='$'
else
PS1+="$Gre\u$R"
PROMPT='#'
fi
PS1+="${Gra}@"
case ${HOSTNAME:0:4} in
'beta')
PS1+="${Yel}"
;;
'prod')
PS1+="${Red}"
;;
*)
PS1+="${R}"
;;
esac
PS1+="$HOSTNAME"
local pwd='~'
[ "$PWD" != "$HOME" ] && pwd=${PWD/#$HOME\//\~\/}
PS1+=" ${Cya}${pwd}$(__vte_osc7)${R}"
if hash git 2>&-; then
# git command exists
if git rev-parse --git-dir >/dev/null 2>&1; then
# current dir is version controlled
local branch tag_release dirty
branch=$(git branch 2>/dev/null | grep -e ^* | cut -d ' ' -f2)
PS1+=" ${R}[${Mag}${branch}${R}|"
tag_release=$(git describe --tags 2>/dev/null | cut -d'-' -f1)
dirty=$(git status -s | wc -l)
if [[ $dirty -ne 0 ]]; then
PS1+="${Yel}${DIVERGENT_GIT_SYMBOL}${R}|${tag_release}${Yel}…$dirty"
else
local ahead
ahead=$(git rev-list --branches --not --remotes | wc -l)
if [[ $ahead -ne 0 ]]; then
PS1+="${DIVERGENT_GIT_SYMBOL}|${tag_release}${Yel}${PUSHED_NEEDED_SYMBOL}${ahead}"
else
if [[ -z $tag_release ]]; then
PS1+="${SYNCHRONIZED_GIT_SYMBOL}"
else
local commit_ahead
commit_ahead=$(git log "$tag_release"..HEAD --oneline | wc -l)
if [[ $commit_ahead -gt 0 ]]; then
PS1+="${DIVERGENT_GIT_SYMBOL}|${tag_release}${Cya}${TAG_NEEDED_SYMBOL}${commit_ahead}"
else else
local ahead
ahead=$(git rev-list --branches --not --remotes | wc -l)
if [[ $ahead -ne 0 ]]; then
PS1+="${DIVERGENT_GIT_SYMBOL}|${tag_release}${Yel}${PUSHED_NEEDED_SYMBOL}${ahead}"
else
if [[ -z $tag_release ]]; then
PS1+="${SYNCHRONIZED_GIT_SYMBOL}"
else
local commit_ahead
commit_ahead=$(git log "$tag_release"..HEAD --oneline | wc -l)
if [[ $commit_ahead -gt 0 ]]; then
PS1+="${DIVERGENT_GIT_SYMBOL}|${tag_release}${Cya}${TAG_NEEDED_SYMBOL}${commit_ahead}"
else
PS1+="${SYNCHRONIZED_GIT_SYMBOL}|${Cya}${tag_release}"
fi
fi
fi
PS1+="${SYNCHRONIZED_GIT_SYMBOL}|${Cya}${tag_release}"
fi fi
PS1+="${R}]"
fi
fi fi
fi
PS1+="${R}]"
fi fi
fi
if [ $EXIT != 0 ]; then
PS1+="$Mag" # Add red if exit code non 0
else
PS1+="$Gra"
fi
if [ $EXIT != 0 ]; then
PS1+="$Mag" # Add red if exit code non 0
else
PS1+="$Gra"
fi
PS1+=" $PROMPT ${R}"
PS1+=" $PROMPT ${R}"
} }
function __vte_osc7 { function __vte_osc7 {
# HINT: special character vte to get TILIX show proper hostname and pwd
# Use \[...\] around the parts of PS1 that have length 0.
# https://unix.stackexchange.com/questions/28827/why-is-my-bash-prompt-getting-bugged-when-i-browse-the-history#28828
VTE_INFO="${HOSTNAME:-}"
if [[ -n ${container_hostname:-} ]]; then
local host
host=$(builtin echo $container_hostname | tr ' ' ':')
VTE_INFO="$host:$HOSTNAME"
fi
printf "\[\033]7;file://%s%s\a\]" "${VTE_INFO}" "$(__vte_urlencode "${PWD}")"
# HINT: special character vte to get TILIX show proper hostname and pwd
# Use \[...\] around the parts of PS1 that have length 0.
# https://unix.stackexchange.com/questions/28827/why-is-my-bash-prompt-getting-bugged-when-i-browse-the-history#28828
VTE_INFO="${HOSTNAME:-}"
if [[ -n ${container_hostname:-} ]]; then
local host
host=$(builtin echo $container_hostname | tr ' ' ':')
VTE_INFO="$host:$HOSTNAME"
fi
printf "\[\033]7;file://%s%s\a\]" "${VTE_INFO}" "$(__vte_urlencode "${PWD}")"
} }
function __vte_urlencode { function __vte_urlencode {
# This is important to make sure string manipulation is handled
# byte-by-byte.
LC_ALL=C
str="$1"
while [ -n "$str" ]; do
safe="${str%%[!a-zA-Z0-9/:_\.\-\!\'\(\)~]*}"
printf "%s" "$safe"
str="${str#"$safe"}"
if [ -n "$str" ]; then
printf "%%%02X" "'$str"
str="${str#?}"
fi
done
# This is important to make sure string manipulation is handled
# byte-by-byte.
LC_ALL=C
str="$1"
while [ -n "$str" ]; do
safe="${str%%[!a-zA-Z0-9/:_\.\-\!\'\(\)~]*}"
printf "%s" "$safe"
str="${str#"$safe"}"
if [ -n "$str" ]; then
printf "%%%02X" "'$str"
str="${str#?}"
fi
done
} }
###------ ###------
### MAIN ### MAIN
###------ ###------
MIAOU_BASH_DIR=$(realpath /opt/miaou-bash)
export MIAOU_BASH_DIR
## Add path for TOOLBOX if any
[[ -d "/TOOLBOX" ]] && PATH=$PATH:/TOOLBOX || true
# Add path to any tools folder in /opt/miaou-*
for i in {/opt,$HOME}/miaou-*/tools; do [[ -d "$i" ]] && PATH=$PATH:$i; done || true
# If not running interactively, don't do anything # If not running interactively, don't do anything
case $- in case $- in
*i*) ;; *i*) ;;
*) return ;; *) return ;;
esac esac
MIAOU_BASH_DIR=$(realpath /opt/miaou-bash)
export MIAOU_BASH_DIR
HOSTNAME=$(hostname -f) HOSTNAME=$(hostname -f)
# don't put duplicate lines or lines starting with space in the history. # don't put duplicate lines or lines starting with space in the history.
@ -180,9 +186,9 @@ shopt -s checkwinsize
# set a fancy prompt (non-color, unless we know we "want" color) # set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in case "$TERM" in
xterm-color | *-256color) xterm-color | *-256color)
color_prompt=yes
export COLOR_OPTIONS=' --color=auto'
;;
color_prompt=yes
export COLOR_OPTIONS=' --color=auto'
;;
esac esac
export LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.sql.gz=01;35:*.mariadb.gz=01;35:*.postgres.gz=01;35:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:" export LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.sql.gz=01;35:*.mariadb.gz=01;35:*.postgres.gz=01;35:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:"
@ -192,11 +198,11 @@ export LESS="r"
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile # this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc). # sources /etc/bash.bashrc).
if ! shopt -oq posix; then if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi fi
# prevent CTRL+S to freeze in vim, CTRL+Q to unfreeze! # prevent CTRL+S to freeze in vim, CTRL+Q to unfreeze!
@ -232,9 +238,3 @@ alias ssu4="ss -ntel4p | perl -pne 'if(/uid:(\\d+)/){@a=getpwuid(\$1);s/uid:(\\d
# Alias definitions. # Alias definitions.
[[ -f "/etc/bash.aliases" ]] && source "/etc/bash.aliases" || true [[ -f "/etc/bash.aliases" ]] && source "/etc/bash.aliases" || true
[[ -f "$HOME/.bash_aliases" ]] && source "$HOME/.bash_aliases" || true [[ -f "$HOME/.bash_aliases" ]] && source "$HOME/.bash_aliases" || true
## Add path for TOOLBOX if any
[[ -d "/TOOLBOX" ]] && PATH=$PATH:/TOOLBOX || true
# Add path to any tools folder in /opt/miaou-*
for i in {/opt,$HOME}/miaou-*/tools; do [[ -d "$i" ]] && PATH=$PATH:$i; done || true

53
bin/miaou-bash

@ -1,14 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# CONSTANTS # CONSTANTS
BASH_BACK_ERROR=$(mktemp -t "$(basename $0).XXXXXXXX" --tmpdir=/run/user/$(id -u))
BASH_BACK_NAME=$(basename "${0}")
BASH_BACK_ERROR=$(mktemp -t "${BASH_BACK_NAME}.XXXXXXXX" --tmpdir="/run/user/$(id -u)")
BASH_BACK_DEBUG=${BASH_BACK_DEBUG:-false} BASH_BACK_DEBUG=${BASH_BACK_DEBUG:-false}
readonly BASH_BACK_NAME BASH_BACK_ERROR BASH_BACK_DEBUG
# FUNCTIONS # FUNCTIONS
function on_return { function on_return {
if [[ "${BASH_COMMAND}" == 'return '* ]]; then if [[ "${BASH_COMMAND}" == 'return '* ]]; then
code=$(echo "${BASH_COMMAND}" | cut -d' ' -f2) # regex does not work here unfortunately! thus use of basic cut
code=$(echo "${BASH_COMMAND}" | cut -d' ' -f2) # regex does not work here unfortunately!
if [[ -n "$code" ]] && [[ "$code" -ne 0 ]]; then if [[ -n "$code" ]] && [[ "$code" -ne 0 ]]; then
trap - DEBUG trap - DEBUG
>&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: return $code from ${FUNCNAME[1]}" >&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: return $code from ${FUNCNAME[1]}"
@ -16,12 +19,12 @@ function on_return {
fi fi
} }
# overridden function which permits stacktracing of original `return` statement
# overridden function which permits backtracing of original `return` statement
function exit { function exit {
code=${1:-0} code=${1:-0}
>&2 echo "${BASH_SOURCE[2]}:${BASH_LINENO[0]} exit $@"
# >&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: exit $@" # >&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: exit $@"
builtin exit $code
>&2 echo "${BASH_SOURCE[2]}:${BASH_LINENO[0]} exit $code"
builtin exit "$code"
} }
function on_exit { function on_exit {
@ -31,19 +34,19 @@ function on_exit {
stack_functions=("${FUNCNAME[@]}") stack_functions=("${FUNCNAME[@]}")
stack_sources=("${BASH_SOURCE[@]}") stack_sources=("${BASH_SOURCE[@]}")
unset stack_lines[-1]
unset stack_lines[-1]
unset stack_functions[0]
unset stack_functions[-1]
unset 'stack_lines[-1]'
unset 'stack_lines[-1]'
unset 'stack_functions[0]'
unset 'stack_functions[-1]'
stack_functions[-1]='<main>' stack_functions[-1]='<main>'
unset stack_sources[0]
unset stack_sources[-1]
unset 'stack_sources[0]'
unset 'stack_sources[-1]'
if [[ "${stack_functions[1]}" == exit && "${stack_sources[1]}" == "${BASH_SOURCE[0]}" ]]; then if [[ "${stack_functions[1]}" == exit && "${stack_sources[1]}" == "${BASH_SOURCE[0]}" ]]; then
# the exit case scenario # the exit case scenario
unset stack_functions[1]
unset stack_sources[1]
unset stack_lines[0]
unset 'stack_functions[1]'
unset 'stack_sources[1]'
unset 'stack_lines[0]'
fi fi
stack_lines=("${stack_lines[@]}") stack_lines=("${stack_lines[@]}")
@ -53,9 +56,9 @@ function on_exit {
stack_summary=() stack_summary=()
if [[ $code -gt 0 ]]; then if [[ $code -gt 0 ]]; then
last_error=$(tail -n1 $BASH_BACK_ERROR)
last_error=$(tail -n1 "$BASH_BACK_ERROR")
last_source=${stack_sources[0]} last_source=${stack_sources[0]}
last_source=${last_source//./"\."} # replace . by \.
last_source=${last_source//./"\."} # replace '.' with '\.'
regex1="^$last_source: line ([0-9]+): (.*)\$" regex1="^$last_source: line ([0-9]+): (.*)\$"
regex2="^$last_source:([0-9]+) (.*)\$" regex2="^$last_source:([0-9]+) (.*)\$"
if [[ "$last_error" =~ $regex1 || "$last_error" =~ $regex2 ]]; then if [[ "$last_error" =~ $regex1 || "$last_error" =~ $regex2 ]]; then
@ -92,7 +95,7 @@ function on_exit {
fi fi
cleanup cleanup
builtin exit $code
builtin exit "$code"
} }
function dump_summary { function dump_summary {
@ -104,8 +107,8 @@ function dump_summary {
function dump_stderr { function dump_stderr {
last_trim=${1:-false} last_trim=${1:-false}
mapfile -t tmp_error <$BASH_BACK_ERROR
$last_trim && unset tmp_error[-1] && tmp_error=("${tmp_error[@]}")
mapfile -t tmp_error <"$BASH_BACK_ERROR"
$last_trim && unset 'tmp_error[-1]' && tmp_error=("${tmp_error[@]}")
if [[ "${#tmp_error[@]}" -gt 0 ]]; then if [[ "${#tmp_error[@]}" -gt 0 ]]; then
$BASH_BACK_DEBUG && >/dev/tty echo '---stderr---' $BASH_BACK_DEBUG && >/dev/tty echo '---stderr---'
for i in "${tmp_error[@]}"; do for i in "${tmp_error[@]}"; do
@ -122,7 +125,7 @@ function success {
function cleanup { function cleanup {
trap - ERR TERM INT EXIT trap - ERR TERM INT EXIT
exec 3>&- 4>&- exec 3>&- 4>&-
rm $BASH_BACK_ERROR
rm "$BASH_BACK_ERROR"
} }
# MAIN # MAIN
@ -133,9 +136,13 @@ set -TEue -o pipefail
trap 'on_exit $?' ERR TERM INT EXIT trap 'on_exit $?' ERR TERM INT EXIT
trap 'on_return' DEBUG trap 'on_return' DEBUG
# magic FD
exec 3> >(tee $BASH_BACK_ERROR >/dev/null) 4>/dev/stderr
# magic FD + delayed tee
exec 3> >(tee "$BASH_BACK_ERROR" >/dev/null) 4>/dev/stderr
# magic $0
BASH_ARGV0="$1" # to pretend script runs by itself
$BASH_BACK_DEBUG && >/dev/tty echo '---stdout---' $BASH_BACK_DEBUG && >/dev/tty echo '---stdout---'
source $1 2>&3
# shellcheck source=/dev/null
source "$1" 2>&3
success success

44
install.sh

@ -3,21 +3,21 @@
## CONSTANTS ## CONSTANTS
readonly CURDIR=$PWD readonly CURDIR=$PWD
readonly REQUIRED_PKGS=(file git bc vim jq)
readonly REQUIRED_PKGS=(file git bc vim jq bat gum)
readonly MAIN_TAR_GZ_URL="https://git.artcode.re/miaou/miaou-bash/archive/main.tar.gz" readonly MAIN_TAR_GZ_URL="https://git.artcode.re/miaou/miaou-bash/archive/main.tar.gz"
## FUNCTIONS ## FUNCTIONS
function push_directory { function push_directory {
pushd "$1" || (echo "unable to push directory <$1>" && exit 1)
pushd "$1" || (echo "unable to push directory <$1>" && exit 1)
} }
function pop_directory { function pop_directory {
popd || (echo "unable to pop from previous directory" && exit 1)
popd || (echo "unable to pop from previous directory" && exit 1)
} }
function root_required { function root_required {
[ "$(id -u)" -ne 0 ] && echo 'root privilege required' && exit 1
[ "$(id -u)" -ne 0 ] && echo 'root privilege required' && exit 1
} }
## MAIN ## MAIN
@ -25,28 +25,28 @@ function root_required {
root_required root_required
if [[ $CURDIR != '/opt/miaou-bash' ]]; then if [[ $CURDIR != '/opt/miaou-bash' ]]; then
# download and fullfill /opt/miaou-bash, then run it from folder
# download and fullfill /opt/miaou-bash, then run it from folder
if [[ -L /opt/miaou-bash ]]; then
/opt/miaou-bash/install.sh
else
rm -rf /opt/miaou-bash
if [[ -L /opt/miaou-bash ]]; then
/opt/miaou-bash/install.sh
else
rm -rf /opt/miaou-bash
push_directory "$(mktemp -d)"
curl --no-progress-meter -O $MAIN_TAR_GZ_URL
tar -xzf main.tar.gz
mv miaou-bash /opt/
pop_directory
rm -rf "$TEMP"
push_directory "$(mktemp -d)"
curl --no-progress-meter -O $MAIN_TAR_GZ_URL
tar -xzf main.tar.gz
mv miaou-bash /opt/
pop_directory
rm -rf "$TEMP"
push_directory /opt/miaou-bash && ./install.sh
push_directory /opt/miaou-bash && ./install.sh
fi
fi
else else
MIAOU_BASH_DIR=$CURDIR
export MIAOU_BASH_DIR
source "$MIAOU_BASH_DIR/lib/functions.bash"
"$MIAOU_BASH_DIR/tools/idem_apt_install" "${REQUIRED_PKGS[@]}"
./init.sh
MIAOU_BASH_DIR=$CURDIR
export MIAOU_BASH_DIR
source "$MIAOU_BASH_DIR/lib/functions.bash"
"$MIAOU_BASH_DIR/tools/idem_apt_install" "${REQUIRED_PKGS[@]}"
./init.sh
fi fi

123
lib/functions.bash

@ -5,35 +5,35 @@
## =============== ## ===============
function _array_contains { function _array_contains {
local -n array=$1
local element=$2
[[ " ${array[@]} " =~ " ${element} " ]] && return 0 || return 1
local -n array=$1
local element=$2
[[ " ${array[@]} " =~ " ${element} " ]] && return 0 || return 1
} }
function _array_intersect { function _array_intersect {
local -n arr1=$1
local -n arr2=$2
local -n result=$3
local -n arr1=$1
local -n arr2=$2
local -n result=$3
declare -A include
for item in "${arr2[@]}"; do include["$item"]=1; done
declare -A include
for item in "${arr2[@]}"; do include["$item"]=1; done
result=()
for item in "${arr1[@]}"; do [[ -n ${include["$item"]} ]] && result+=("$item"); done
result=()
for item in "${arr1[@]}"; do [[ -n ${include["$item"]} ]] && result+=("$item"); done
} }
function _array_subtract { function _array_subtract {
local -n arr1=$1 # First array
local -n arr2=$2 # Array to subtract
local -n result=$3 # Output array
local -n arr1=$1 # First array
local -n arr2=$2 # Array to subtract
local -n result=$3 # Output array
[[ ${#arr2[@]} == 0 ]] && result=("${arr1[@]}") && return
[[ ${#arr2[@]} == 0 ]] && result=("${arr1[@]}") && return
declare -A exclude
for item in "${arr2[@]}"; do exclude["$item"]=1; done
declare -A exclude
for item in "${arr2[@]}"; do exclude["$item"]=1; done
result=()
for item in "${arr1[@]}"; do [[ -z ${exclude["$item"]} ]] && result+=("$item"); done
result=()
for item in "${arr1[@]}"; do [[ -z ${exclude["$item"]} ]] && result+=("$item"); done
} }
## ============== ## ==============
@ -41,8 +41,8 @@ function _array_subtract {
## ============== ## ==============
function _pluralize_simple { function _pluralize_simple {
echo -n "$1 "
[[ $1 -eq 1 || $1 -eq -1 ]] && echo ${2} || echo ${2}s
echo -n "$1 "
[[ $1 -eq 1 || $1 -eq -1 ]] && echo ${2} || echo ${2}s
} }
## ============== ## ==============
@ -50,13 +50,32 @@ function _pluralize_simple {
## ============== ## ==============
function _confirm_destructive { function _confirm_destructive {
local message="${1:-This cannot be undone!}"
echo "⚠️ WARNING: $message"
read -p "Type YES to confirm: " response
case "$response" in
[yY][eE][sS] | [yY]) return 0 ;;
*) echo "canceled!" && return 1 ;;
esac
local message="${1:-This cannot be undone!}"
echo "⚠️ WARNING: $message"
read -p "Type YES to confirm: " response
case "$response" in
[yY][eE][sS] | [yY]) return 0 ;;
*) echo "canceled!" && return 1 ;;
esac
}
## =================
## OPTIONS Functions
## =================
function _flatten_short_options {
local -n args=$1
local result=()
for word in ${args[@]}; do
[[ $word == -- ]] && break
if [[ $word =~ ^-[a-z][a-z] ]]; then
word=${word:1}
for ((i = 0; i < ${#word}; i++)); do result+=("-${word:i:1}"); done
else
result+=("$word")
fi
done
args=("${result[@]}")
} }
## ============== ## ==============
@ -69,45 +88,45 @@ function _confirm_destructive {
# ARRAY=( a b c ) # ARRAY=( a b c )
# containsElement ARRAY 'a' => 0 # containsElement ARRAY 'a' => 0
function containsElement { function containsElement {
isArray "$1" || (echo >&2 "ERROR: <$1> not an array!" && return 2)
array_inter="$1[@]"
array=("${!array_inter}")
for i in "${array[@]}"; do [[ "$i" == "$2" ]] && return 0; done
return 1
isArray "$1" || (echo >&2 "ERROR: <$1> not an array!" && return 2)
array_inter="$1[@]"
array=("${!array_inter}")
for i in "${array[@]}"; do [[ "$i" == "$2" ]] && return 0; done
return 1
} }
## return 0 (true) if arg1 (passed by name) is an array ## return 0 (true) if arg1 (passed by name) is an array
function isArray { function isArray {
[[ "$(declare -p "$1" 2>/dev/null)" =~ "declare -a" ]] || return 1
[[ "$(declare -p "$1" 2>/dev/null)" =~ "declare -a" ]] || return 1
} }
function isDebian { function isDebian {
grep ^ID=debian /etc/os-release
grep ^ID=debian /etc/os-release
} }
function isArch { function isArch {
grep ^ID=arch /etc/os-release
grep ^ID=arch /etc/os-release
} }
function os-release { function os-release {
grep ^ID= /etc/os-release | cut -d '=' -f2
grep ^ID= /etc/os-release | cut -d '=' -f2
} }
function askConfirmation { function askConfirmation {
case "$1" in
y | Y | yes | YES)
QUESTION="(Y/n)?"
DEFAULT=0
;;
*)
QUESTION="(y/N)?"
DEFAULT=1
;;
esac
read -rp "$QUESTION : " choice
case "$choice" in
y | Y | yes | YES) return 0 ;; #true
n | no | N | NO) return 1 ;; #false
*) return $DEFAULT ;;
esac
case "$1" in
y | Y | yes | YES)
QUESTION="(Y/n)?"
DEFAULT=0
;;
*)
QUESTION="(y/N)?"
DEFAULT=1
;;
esac
read -rp "$QUESTION : " choice
case "$choice" in
y | Y | yes | YES) return 0 ;; #true
n | no | N | NO) return 1 ;; #false
*) return $DEFAULT ;;
esac
} }
Loading…
Cancel
Save