tools -> scripts
This commit is contained in:
111
scripts/helpers/arg-parser/README.md
Normal file
111
scripts/helpers/arg-parser/README.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Argument parser for bash scripts v1.6
|
||||
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
# 1. add these lines after shebang:
|
||||
|
||||
__RAW_ARGS__=("$@")
|
||||
source args.sh
|
||||
|
||||
# 2. read arguments as flags:
|
||||
|
||||
arg a 1 flag_a
|
||||
echo "Flag -a has value '$flag_a'"
|
||||
echo "Flag -a has value '$(arg a 1)'"
|
||||
|
||||
arg b 1 flag_b
|
||||
echo "Flag -b has value '$flag_b'"
|
||||
echo "Flag -b has value '$(arg b 1)'"
|
||||
|
||||
arg c 1 flag_c
|
||||
echo "Flag -c has value '$flag_c'"
|
||||
echo "Flag -c has value '$(arg c 1)'"
|
||||
|
||||
arg d 1 flag_d
|
||||
echo "Flag -d has value '$flag_d'"
|
||||
echo "Flag -d has value '$(arg d 1)'"
|
||||
|
||||
argl flag1 1 flag_1
|
||||
echo "Flag --flag1 has value '$flag_1'"
|
||||
echo "Flag --flag1 has value '$(argl flag1 1)'"
|
||||
|
||||
argl flag2 1 flag_2
|
||||
echo "Flag --flag2 has value '$flag_2'"
|
||||
echo "Flag --flag2 has value '$(argl flag2 1)'"
|
||||
|
||||
# 3. and/or read arguments' values:
|
||||
|
||||
arg a 0 arg_a
|
||||
echo "Arg -a has value '$arg_a'"
|
||||
echo "Arg -a has value '$(arg a 0)'"
|
||||
|
||||
arg b 0 arg_b
|
||||
echo "Arg -b has value '$arg_b'"
|
||||
echo "Arg -b has value '$(arg b 0)'"
|
||||
|
||||
argl arg1 0 arg_1
|
||||
echo "Arg --arg1 has value '$arg_1'"
|
||||
echo "Arg --arg1 has value '$(argl arg1 0)'"
|
||||
|
||||
argl arg2 0 arg_2
|
||||
echo "Arg --arg2 has value '$arg_2'"
|
||||
echo "Arg --arg2 has value '$(argl arg2 0)'"
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
1. Short arguments can be specified contiguously or separately
|
||||
and their order does not matter, but before each of them
|
||||
(or the first of them) one leading dash must be specified.
|
||||
|
||||
> Valid combinations: `-a -b -c`, `-cba`, `-b -azc "value of z"`
|
||||
|
||||
2. Short arguments can have values and if are - value must go
|
||||
next to argument itself.
|
||||
|
||||
> Valid combinations: `-ab avalue`, `-ba avalue`, `-a avalue -b`
|
||||
|
||||
3. Long arguments cannot be combined like short ones and each
|
||||
of them must be specified separately with two leading dashes.
|
||||
|
||||
> Valid combinations: `--foo --bar`, `--bar --foo`
|
||||
|
||||
4. Long arguments can have a value which must be specified after `=`.
|
||||
|
||||
> Valid combinations: `--foo value --bar`, `--bar --foo=value`
|
||||
|
||||
5. If arg value may contain space then value must be "double-quoted".
|
||||
|
||||
6. You can use arg() or argl() to check presence of any arg, no matter
|
||||
if it has value or not.
|
||||
|
||||
More info:
|
||||
* 🇷🇺 [axenov.dev/bash-args](https://axenov.dev/bash-args/)
|
||||
* 🇺🇸 [axenov.dev/en/bash-processing-arguments-in-a-script-when-called-from-the-shell/](https://axenov.dev/en/bash-processing-arguments-in-a-script-when-called-from-the-shell)
|
||||
|
||||
Tested in Ubuntu 20.04.2 LTS in:
|
||||
|
||||
```
|
||||
bash 5.0.17(1)-release (x86_64-pc-linux-gnu) and later
|
||||
zsh 5.8 (x86_64-ubuntu-linux-gnu) and later
|
||||
```
|
||||
|
||||
## Version history
|
||||
|
||||
```
|
||||
v1.0 - initial
|
||||
v1.1 - arg(): improved skipping uninteresting args
|
||||
- arg(): check next arg to be valid value
|
||||
v1.2 - removed all 'return' statements
|
||||
- arg(): error message corrected
|
||||
- new examples
|
||||
v1.3 - argl(): improved flag check
|
||||
- some text corrections
|
||||
v1.4 - new function argn()
|
||||
- some text corrections
|
||||
v1.5 - arg(), grep_match(): fixed searching for -e argument
|
||||
- grep_match(): redirect output into /dev/null
|
||||
v1.6 - removed useless argn()
|
||||
- arg() and argl() refactored and now support values with whitespaces
|
||||
```
|
||||
158
scripts/helpers/arg-parser/args.sh
Executable file
158
scripts/helpers/arg-parser/args.sh
Executable file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Argument parser for bash scripts
|
||||
#
|
||||
# Author: Anthony Axenov (Антон Аксенов)
|
||||
# Version: 1.6
|
||||
# License: MIT
|
||||
# Description: https://git.axenov.dev/anthony/shell/src/branch/master/helpers/arg-parser
|
||||
|
||||
#purpose Little helper to check if string matches PCRE
|
||||
#argument $1 - some string
|
||||
#argument $2 - regex
|
||||
#exitcode 0 - string valid
|
||||
#exitcode 1 - string is not valid
|
||||
grep_match() {
|
||||
printf "%s" "$1" | grep -qE "$2" >/dev/null
|
||||
}
|
||||
|
||||
#purpose Find short argument or its value
|
||||
#argument $1 - (string) argument (without leading dashes; only first letter will be processed)
|
||||
#argument $2 - (number) is it flag? 1 if is, otherwise 0 or nothing
|
||||
#argument $3 - (string) variable to return value into
|
||||
# (if not specified then it will be echo'ed in stdout)
|
||||
#returns (string) 1 (if $2 == 1), value (if correct and if $2 != 1) or nothing
|
||||
#usage To get value into var: arg v 0 myvar or myvalue=$(arg 'v')
|
||||
#usage To find flag into var: arg f 1 myvar or flag=$(arg 'f')
|
||||
#usage To echo value: arg v
|
||||
#usage To echo 1 if flag exists: arg f
|
||||
arg() {
|
||||
[ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
|
||||
local arg_name="${1:0:1}" # first character of argument name to find
|
||||
local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
|
||||
local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
|
||||
local value= # initialize empty value to check if we found one later
|
||||
local arg_found=0 # marker of found argument
|
||||
|
||||
for idx in "${!__RAW_ARGS__[@]}"; do # going through all args
|
||||
local arg_search=${__RAW_ARGS__[idx]} # get current argument
|
||||
|
||||
# skip $arg_search if it starts with '--' or letter
|
||||
grep_match "$arg_search" "^(\w|--)" && continue
|
||||
|
||||
# clear $arg_search from special and duplicate characters, e.g. 'fas-)dfs' will become 'fasd'
|
||||
local arg_chars="$(printf "%s" "$arg_search" \
|
||||
| tr -s "[$arg_search]" 2>/dev/null \
|
||||
| tr -d "[:punct:][:blank:]" 2>/dev/null)"
|
||||
|
||||
# if $arg_name is not one of $arg_chars the skip it
|
||||
grep_match "-$arg_name" "^-[$arg_chars]$" || continue
|
||||
arg_found=1
|
||||
|
||||
# then return '1'|'0' back into $value if we need flag or next arg value otherwise
|
||||
[ "$is_flag" = 1 ] && value=1 || value="${__RAW_ARGS__[idx+1]}"
|
||||
break
|
||||
done
|
||||
|
||||
[ "$is_flag" = 1 ] && [ -z "$value" ] && value=0;
|
||||
|
||||
# if value we found is empty or looks like another argument then exit with error message
|
||||
if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
|
||||
echo "ERROR: Argument '-$arg_name' must have correct value!" >&2 && exit 1
|
||||
fi
|
||||
|
||||
# return '$value' back into $var_name (if exists) or echo in stdout
|
||||
[ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
|
||||
}
|
||||
|
||||
#purpose Find long argument or its value
|
||||
#argument $1 - argument (without leading dashes)
|
||||
#argument $2 - (number) is it flag? 1 if is, otherwise 0 or nothing
|
||||
#argument $3 - (string) variable to return value into
|
||||
# (if not specified then it will be echo'ed in stdout)
|
||||
#returns (string) 1 (if $2 == 1), value (if correct and if $2 != 1) or nothing
|
||||
#usage To get value into var: arg v 0 myvar or myvalue=$(arg 'v')
|
||||
#usage To find flag into var: arg f 1 myvar or flag=$(arg 'f')
|
||||
#usage To echo value: arg v
|
||||
#usage To echo 1 if flag exists: arg f
|
||||
argl() {
|
||||
[ "$1" ] || { echo "Argument name is not specified!" >&2 && exit 1; }
|
||||
local arg_name="$1" # argument name to find
|
||||
local is_flag="$2" || 0 # 1 if we need just find a flag, 0 to get a value
|
||||
local var_name="$3" || 0 # variable name to return value into or 0 to echo it in stdout
|
||||
local value= # initialize empty value to check if we found one later
|
||||
local arg_found=0 # marker of found argument
|
||||
|
||||
for idx in "${!__RAW_ARGS__[@]}"; do # going through all args
|
||||
local arg_search="${__RAW_ARGS__[idx]}" # get current argument
|
||||
|
||||
if [ "$arg_search" = "--$arg_name" ]; then # if current arg begins with two dashes
|
||||
# then return '1' back into $value if we need flag or next arg value otherwise
|
||||
[ "$is_flag" = 1 ] && value=1 || value="${__RAW_ARGS__[idx+1]}"
|
||||
break # stop the loop
|
||||
elif grep_match "$arg_search" "^--$arg_name=.+$"; then # check if $arg like '--foo=bar'
|
||||
# then return '1' back into $value if we need flag or part from '=' to arg's end as value otherwise
|
||||
[ "$is_flag" = 1 ] && value=1 || value="${arg_search#*=}"
|
||||
break # stop the loop
|
||||
fi
|
||||
done
|
||||
|
||||
[ "$is_flag" = 1 ] && [ -z "$value" ] && value=0;
|
||||
|
||||
# if value we found is empty or looks like another argument then exit with error message
|
||||
if [ "$arg_found" = 1 ] && ! grep_match "$value" "^[[:graph:]]+$" || grep_match "$value" "^--?\w+$"; then
|
||||
echo "ERROR: Argument '--$arg_name' must have correct value!" >&2 && exit 1;
|
||||
fi
|
||||
|
||||
# return '$value' back into $var_name (if exists) or echo in stdout
|
||||
[ "$var_name" ] && eval "$var_name='$value'" || echo "$value"
|
||||
}
|
||||
|
||||
################################
|
||||
|
||||
# This is simple examples which you can play around with.
|
||||
# 1. uncomment code below
|
||||
# 2. call thi sscript to see what happens:
|
||||
# /args.sh -abcd --flag1 --flag2 -e evalue -f fvalue --arg1=value1 --arg2 value2
|
||||
|
||||
# __RAW_ARGS__=("$@")
|
||||
|
||||
# arg a 1 flag_a
|
||||
# echo "Flag -a has value '$flag_a'"
|
||||
# echo "Flag -a has value '$(arg a 1)'"
|
||||
|
||||
# arg b 1 flag_b
|
||||
# echo "Flag -b has value '$flag_b'"
|
||||
# echo "Flag -b has value '$(arg b 1)'"
|
||||
|
||||
# arg c 1 flag_c
|
||||
# echo "Flag -c has value '$flag_c'"
|
||||
# echo "Flag -c has value '$(arg c 1)'"
|
||||
|
||||
# arg d 1 flag_d
|
||||
# echo "Flag -d has value '$flag_d'"
|
||||
# echo "Flag -d has value '$(arg d 1)'"
|
||||
|
||||
# argl flag1 1 flag_1
|
||||
# echo "Flag --flag1 has value '$flag_1'"
|
||||
# echo "Flag --flag1 has value '$(argl flag1 1)'"
|
||||
|
||||
# argl flag2 1 flag_2
|
||||
# echo "Flag --flag2 has value '$flag_2'"
|
||||
# echo "Flag --flag2 has value '$(argl flag2 1)'"
|
||||
|
||||
# arg e 0 arg_e
|
||||
# echo "Arg -e has value '$arg_e'"
|
||||
# echo "Arg -e has value '$(arg e 0)'"
|
||||
|
||||
# arg f 0 arg_f
|
||||
# echo "Arg -f has value '$arg_f'"
|
||||
# echo "Arg -f has value '$(arg f 0)'"
|
||||
|
||||
# argl arg1 0 arg_1
|
||||
# echo "Arg --arg1 has value '$arg_1'"
|
||||
# echo "Arg --arg1 has value '$(argl arg1 0)'"
|
||||
|
||||
# argl arg2 0 arg_2
|
||||
# echo "Arg --arg2 has value '$arg_2'"
|
||||
# echo "Arg --arg2 has value '$(argl arg2 0)'"
|
||||
127
scripts/helpers/basic.sh
Normal file
127
scripts/helpers/basic.sh
Normal file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env bash
|
||||
source $( dirname $(readlink -e -- "${BASH_SOURCE}"))/io.sh || exit 255
|
||||
|
||||
########################################################
|
||||
# Little handy helpers for scripting
|
||||
########################################################
|
||||
|
||||
is_bash() {
|
||||
[[ "$(basename "$SHELL")" != "bash" ]]
|
||||
}
|
||||
|
||||
is_sourced() {
|
||||
[[ "${BASH_SOURCE[0]}" != "$0" ]]
|
||||
}
|
||||
|
||||
is_root() {
|
||||
[[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]
|
||||
}
|
||||
|
||||
get_os() {
|
||||
case "$(uname -s)" in
|
||||
Linux*) echo Linux ;;
|
||||
Darwin*) echo Macos ;;
|
||||
CYGWIN*) echo Cygwin ;;
|
||||
MINGW*) echo MinGw ;;
|
||||
MSYS_NT*) echo Git ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_os_id() {
|
||||
[ -f /etc/os-release ] && source /etc/os-release
|
||||
echo "$ID"
|
||||
}
|
||||
|
||||
# convert relative path $1 to full one
|
||||
abspath() {
|
||||
echo $(realpath -q "${1/#\~/$HOME}")
|
||||
}
|
||||
|
||||
# check if path $1 is writable
|
||||
is_writable() {
|
||||
[ -w "$(abspath $1)" ]
|
||||
}
|
||||
|
||||
# check if path $1 is a directory
|
||||
is_dir() {
|
||||
[ -d "$(abspath $1)" ]
|
||||
}
|
||||
|
||||
# check if path $1 is a file
|
||||
is_file() {
|
||||
[ -f "$(abspath $1)" ]
|
||||
}
|
||||
|
||||
# check if an argument is a shell function
|
||||
is_function() {
|
||||
declare -F "$1" > /dev/null
|
||||
}
|
||||
|
||||
# check if string $1 matches regex $2
|
||||
regex_match() {
|
||||
printf "%s" "$1" | grep -qP "$2"
|
||||
}
|
||||
|
||||
# check if array $2 contains string $1
|
||||
in_array() {
|
||||
local find=$1
|
||||
shift
|
||||
for e in "$@"; do
|
||||
[[ "$e" == "$find" ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# join all elements of array $2 with delimiter $1
|
||||
implode() {
|
||||
local d=${1-}
|
||||
local f=${2-}
|
||||
if shift 2; then
|
||||
printf %s "$f" "${@/#/$d}"
|
||||
fi
|
||||
}
|
||||
|
||||
# open url $1 in system web-browser
|
||||
open_url() {
|
||||
if which xdg-open > /dev/null; then
|
||||
xdg-open "$1" </dev/null >/dev/null 2>&1 & disown
|
||||
elif which gnome-open > /dev/null; then
|
||||
gnome-open "$1" </dev/null >/dev/null 2>&1 & disown
|
||||
fi
|
||||
}
|
||||
|
||||
# unpack .tar.gz file $1 into path $2
|
||||
unpack_targz() {
|
||||
require tar
|
||||
tar -xzvf "$1" -C "$2"
|
||||
}
|
||||
|
||||
# make soft symbolic link of path $1 to path $2
|
||||
symlink() {
|
||||
ln -sf "$1" "$2"
|
||||
}
|
||||
|
||||
# download file $1 into path $2 using wget
|
||||
download() {
|
||||
require wget
|
||||
wget "$1" -O "$2"
|
||||
}
|
||||
|
||||
# download file $1 into path $2 using curl
|
||||
cdownload() {
|
||||
require curl
|
||||
curl -fsSL "$1" -o "$2"
|
||||
}
|
||||
|
||||
is_int() {
|
||||
[[ "$1" =~ ^[0-9]+$ ]]
|
||||
}
|
||||
|
||||
is_number() {
|
||||
[[ "$1" =~ ^[0-9]+([.,][0-9]+)?$ ]]
|
||||
}
|
||||
|
||||
trim() {
|
||||
echo "$1" | xargs
|
||||
}
|
||||
3
scripts/helpers/debug.sh
Normal file
3
scripts/helpers/debug.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
source $( dirname $(readlink -e -- "${BASH_SOURCE}"))/io.sh || exit 255
|
||||
|
||||
79
scripts/helpers/docker.sh
Normal file
79
scripts/helpers/docker.sh
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################
|
||||
# Docker wrappers
|
||||
########################################################
|
||||
|
||||
# Вызывает корректную команду docker compose
|
||||
docker.compose() {
|
||||
require docker
|
||||
|
||||
argl profiles 0 profiles
|
||||
args=${*/--profiles=[a-zA-Z_,0-9]*/}
|
||||
|
||||
if $(docker compose &>/dev/null); then
|
||||
local cmd="docker compose $args"
|
||||
elif installed_pkg "docker-compose"; then
|
||||
local cmd="docker-compose $args"
|
||||
warn
|
||||
warn "docker-compose v1 устарел и не поддерживается, его поведение непредсказуемо."
|
||||
warn "Обнови docker согласно документации: https://docs.docker.com/engine/install/"
|
||||
warn
|
||||
else
|
||||
error "Должен быть установлен docker-compose-plugin!"
|
||||
die "Установи docker согласно документации: https://docs.docker.com/engine/install/" 2
|
||||
fi
|
||||
|
||||
if [[ "$profiles" ]]; then
|
||||
export COMPOSE_PROFILES=$profiles
|
||||
debug "Выполнено: export COMPOSE_PROFILES=$profiles"
|
||||
fi
|
||||
|
||||
debug "Команда: $cmd"
|
||||
$cmd
|
||||
}
|
||||
|
||||
# Выводит информацию о контейнере
|
||||
docker.inspect() {
|
||||
cmd="docker inspect $*"
|
||||
debug "Команда: $cmd"
|
||||
$cmd 2>/dev/null
|
||||
}
|
||||
|
||||
# Выполняет команду в контейнере от имени root
|
||||
docker.exec() {
|
||||
cmd="docker exec -u root -it $*"
|
||||
debug "Команда: $cmd"
|
||||
$cmd
|
||||
}
|
||||
|
||||
# Выводит информацию о контейнере
|
||||
docker.inspect() {
|
||||
cmd="docker inspect $*"
|
||||
debug "Команда: $cmd"
|
||||
$cmd 2>/dev/null
|
||||
}
|
||||
|
||||
docker.ip() { # not finished
|
||||
if [ "$1" ]; then
|
||||
if [ "$1" = "-a" ]; then
|
||||
docker ps -aq \
|
||||
| xargs -n 1 docker inspect --format '{{.Name}}{{range .NetworkSettings.Networks}} {{.IPAddress}}{{end}}' \
|
||||
| sed -e 's#^/##' \
|
||||
| column -t
|
||||
elif [ "$1" = "-c" ]; then
|
||||
docker-compose ps -q \
|
||||
| xargs -n 1 docker inspect --format '{{.Name}}{{range .NetworkSettings.Networks}} {{.IPAddress}}{{end}}' \
|
||||
| sed -e 's#^/##' \
|
||||
| column -t
|
||||
else
|
||||
docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$1"
|
||||
docker port "$1"
|
||||
fi
|
||||
else
|
||||
docker ps -q \
|
||||
| xargs -n 1 docker inspect --format '{{.Name}}{{range .NetworkSettings.Networks}} {{.IPAddress}}{{end}}' \
|
||||
| sed -e 's#^/##' \
|
||||
| column -t
|
||||
fi
|
||||
}
|
||||
178
scripts/helpers/git.sh
Normal file
178
scripts/helpers/git.sh
Normal file
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env bash
|
||||
_dir=$( dirname $(readlink -e -- "${BASH_SOURCE}"))
|
||||
source "$_dir/io.sh" || exit 255
|
||||
source "$_dir/basic.sh" || exit 255
|
||||
source "$_dir/packages.sh" || exit 255
|
||||
|
||||
########################################################
|
||||
# Shorthands for git
|
||||
########################################################
|
||||
|
||||
git.clone_quick() {
|
||||
require git
|
||||
git clone --depth=1 --single-branch "$@"
|
||||
}
|
||||
|
||||
git.is_repo() {
|
||||
require git
|
||||
[ "$1" ] || die "Path is not specified" 101
|
||||
require_dir "$1/"
|
||||
check_dir "$1/.git"
|
||||
}
|
||||
|
||||
git.require_repo() {
|
||||
require git
|
||||
git.is_repo "$1" || die "'$1' is not git repository!" 10
|
||||
}
|
||||
|
||||
git.cfg() {
|
||||
require git
|
||||
[ "$1" ] || die "Key is not specified" 101
|
||||
if [[ "$2" ]]; then
|
||||
git config --global --replace-all "$1" "$2"
|
||||
else
|
||||
echo $(git config --global --get-all "$1")
|
||||
fi
|
||||
}
|
||||
|
||||
git.set_user() {
|
||||
require git
|
||||
[ "$1" ] || die "git.set_user: Repo is not specified" 100
|
||||
git.cfg "$1" "user.name" "$2"
|
||||
git.cfg "$1" "user.email" "$3"
|
||||
success "User set to '$name <$email>' in ${FWHITE}$1"
|
||||
}
|
||||
|
||||
git.fetch() {
|
||||
require git
|
||||
if [ "$1" ]; then
|
||||
if git.remote_branch_exists "origin/$1"; then
|
||||
git fetch origin "refs/heads/$1:refs/remotes/origin/$1" --progress --prune --quiet 2>&1 || die "Could not fetch $1 from origin" 12
|
||||
else
|
||||
warn "Tried to fetch branch 'origin/$1' but it does not exist."
|
||||
fi
|
||||
else
|
||||
git fetch origin --progress --prune --quiet 2>&1 || exit 12
|
||||
fi
|
||||
}
|
||||
|
||||
git.reset() {
|
||||
require git
|
||||
git reset --hard HEAD
|
||||
git clean -fd
|
||||
}
|
||||
|
||||
git.clone() {
|
||||
require git
|
||||
git clone "$*" 2>&1
|
||||
}
|
||||
|
||||
git.co() {
|
||||
require git
|
||||
git checkout "$*" 2>&1
|
||||
}
|
||||
|
||||
git.is_it_current_branch() {
|
||||
require git
|
||||
[ "$1" ] || die "git.is_it_current_branch: Branch is not specified" 19
|
||||
[[ "$(git.current_branch)" = "$1" ]]
|
||||
}
|
||||
|
||||
git.pull() {
|
||||
require git
|
||||
[ "$1" ] && BRANCH=$1 || BRANCH=$(git.current_branch)
|
||||
# note "Updating branch $BRANCH..."
|
||||
git pull origin "refs/heads/$BRANCH:refs/remotes/origin/$BRANCH" --prune --force --quiet 2>&1 || exit 13
|
||||
git pull origin --tags --force --quiet 2>&1 || exit 13
|
||||
# [ "$1" ] || die "git.pull: Branch is not specified" 19
|
||||
# if [ "$1" ]; then
|
||||
# note "Updating branch $1..."
|
||||
# git pull origin "refs/heads/$1:refs/remotes/origin/$1" --prune --force --quiet 2>&1 || exit 13
|
||||
# else
|
||||
# note "Updating current branch..."
|
||||
# git pull
|
||||
# fi
|
||||
}
|
||||
|
||||
git.current_branch() {
|
||||
require git
|
||||
git branch --show-current || exit 18
|
||||
}
|
||||
|
||||
git.local_branch_exists() {
|
||||
require git
|
||||
[ -n "$(git for-each-ref --format='%(refname:short)' refs/heads/$1)" ]
|
||||
}
|
||||
|
||||
git.update_refs() {
|
||||
require git
|
||||
info "Updating local refs..."
|
||||
git remote update origin --prune 1>/dev/null 2>&1 || exit 18
|
||||
}
|
||||
|
||||
git.delete_remote_branch() {
|
||||
require git
|
||||
[ "$1" ] || die "git.remote_branch_exists: Branch is not specified" 19
|
||||
if git.remote_branch_exists "origin/$1"; then
|
||||
git push origin :"$1" # || die "Could not delete the remote $1 in $ORIGIN"
|
||||
return 0
|
||||
else
|
||||
warn "Trying to delete the remote branch $1, but it does not exists in origin"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
git.is_clean_worktree() {
|
||||
require git
|
||||
git rev-parse --verify HEAD >/dev/null || exit 18
|
||||
git update-index -q --ignore-submodules --refresh
|
||||
git diff-files --quiet --ignore-submodules || return 1
|
||||
git diff-index --quiet --ignore-submodules --cached HEAD -- || return 2
|
||||
return 0
|
||||
}
|
||||
|
||||
git.is_branch_merged_into() {
|
||||
require git
|
||||
[ "$1" ] || die "git.remote_branch_exists: Branch1 is not specified" 19
|
||||
[ "$2" ] || die "git.remote_branch_exists: Branch2 is not specified" 19
|
||||
git.update_refs
|
||||
local merge_hash=$(git merge-base "$1"^{} "$2"^{})
|
||||
local base_hash=$(git rev-parse "$1"^{})
|
||||
[ "$merge_hash" = "$base_hash" ]
|
||||
}
|
||||
|
||||
git.remote_branch_exists() {
|
||||
require git
|
||||
[ "$1" ] || die "git.remote_branch_exists: Branch is not specified" 19
|
||||
git.update_refs
|
||||
[ -n "$(git for-each-ref --format='%(refname:short)' refs/remotes/$1)" ]
|
||||
}
|
||||
|
||||
git.new_branch() {
|
||||
require git
|
||||
[ "$1" ] || die "git.new_branch: Branch is not specified" 19
|
||||
if [ "$2" ] && ! git.local_branch_exists "$2" && git.remote_branch_exists "origin/$2"; then
|
||||
git.co -b "$1" origin/"$2"
|
||||
else
|
||||
git.co -b "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
git.require_clean_worktree() {
|
||||
require git
|
||||
if ! git.is_clean_worktree; then
|
||||
warn "Your working tree is dirty! Look at this:"
|
||||
git status -bs
|
||||
_T="What should you do now?\n"
|
||||
_T="${_T}\t${BOLD}${FWHITE}0.${RESET} try to continue as is\t- errors may occur!\n"
|
||||
_T="${_T}\t${BOLD}${FWHITE}1.${RESET} hard reset\t\t\t- clear current changes and new files\n"
|
||||
_T="${_T}\t${BOLD}${FWHITE}2.${RESET} stash changes (default)\t- save all changes in safe to apply them later via 'git stash pop'\n"
|
||||
_T="${_T}\t${BOLD}${FWHITE}3.${RESET} cancel\n"
|
||||
ask "${_T}${BOLD}${FWHITE}Your choice [0-3]" reset_answer
|
||||
case $reset_answer in
|
||||
1 ) warn "Clearing your work..." && git.reset ;;
|
||||
3 ) exit ;;
|
||||
* ) git stash -a -u -m "WIP before switch to $branch_task" ;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
28
scripts/helpers/help.sh
Normal file
28
scripts/helpers/help.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
#TODO source basic.sh
|
||||
#TODO source args-parser/args.sh
|
||||
|
||||
########################################################
|
||||
# Help functions
|
||||
########################################################
|
||||
|
||||
process_help_arg() {
|
||||
command="${FUNCNAME[1]}"
|
||||
need_help=$(arg help 1)
|
||||
[[ "$need_help" -eq 0 ]] && need_help=$(argl help 1)
|
||||
[[ "$need_help" -eq 1 ]] && help "$command"
|
||||
}
|
||||
|
||||
help() {
|
||||
is_function "help.$1" && help."$1" && exit
|
||||
echo "Main help message"
|
||||
}
|
||||
|
||||
help.example() {
|
||||
echo "Example help message"
|
||||
}
|
||||
|
||||
example() {
|
||||
process_help_arg
|
||||
echo "Example command"
|
||||
}
|
||||
393
scripts/helpers/io.sh
Normal file
393
scripts/helpers/io.sh
Normal file
@@ -0,0 +1,393 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################
|
||||
# Simple and fancy input & output
|
||||
########################################################
|
||||
|
||||
which tput > /dev/null 2>&1 && [[ $(tput -T$TERM colors) -gt 8 ]] && CAN_USE_COLORS=1 || CAN_USE_COLORS=0
|
||||
USE_COLORS=${USE_COLORS:-$CAN_USE_COLORS}
|
||||
|
||||
# Icons (message prefixes)
|
||||
[[ "$USE_COLORS" == 1 ]] && IINFO="( i )" || IINFO=''
|
||||
[[ "$USE_COLORS" == 1 ]] && INOTE="( * )" || INOTE=''
|
||||
[[ "$USE_COLORS" == 1 ]] && IWARN="( # )" || IWARN=''
|
||||
[[ "$USE_COLORS" == 1 ]] && IERROR="( ! )" || IERROR=''
|
||||
[[ "$USE_COLORS" == 1 ]] && IFATAL="( @ )" || IFATAL=''
|
||||
[[ "$USE_COLORS" == 1 ]] && ISUCCESS="( ! )" || ISUCCESS=''
|
||||
[[ "$USE_COLORS" == 1 ]] && IASK="( ? )" || IASK=''
|
||||
[[ "$USE_COLORS" == 1 ]] && IDEBUG="(DBG)" || IDEBUG=''
|
||||
[[ "$USE_COLORS" == 1 ]] && IVRB="( + )" || IVRB=''
|
||||
|
||||
# Text attributes
|
||||
[[ "$USE_COLORS" == 1 ]] && FRESET="$(tput sgr0)" || FRESET='' # Normal
|
||||
[[ "$USE_COLORS" == 1 ]] && FBOLD="$(tput bold)" || FBOLD='' # Bold
|
||||
[[ "$USE_COLORS" == 1 ]] && FDIM="$(tput dim)" || FDIM='' # Dimmed
|
||||
[[ "$USE_COLORS" == 1 ]] && FLINE="$(tput smul)" || FLINE='' # Underlined
|
||||
[[ "$USE_COLORS" == 1 ]] && FENDLINE="$(tput rmul)" || FENDLINE='' # End of underlined
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLINK="$(tput blink)" || FBLINK='' # Blink
|
||||
[[ "$USE_COLORS" == 1 ]] && FREV="$(tput rev)" || FREV='' # Reversed
|
||||
|
||||
# Text colors - normal
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLACK="$(tput setaf 0)" || FBLACK='' # Black
|
||||
[[ "$USE_COLORS" == 1 ]] && FRED="$(tput setaf 1)" || FRED='' # Red
|
||||
[[ "$USE_COLORS" == 1 ]] && FGREEN="$(tput setaf 2)" || FGREEN='' # Green
|
||||
[[ "$USE_COLORS" == 1 ]] && FYELLOW="$(tput setaf 3)" || FYELLOW='' # Yellow
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLUE="$(tput setaf 4)" || FBLUE='' # Blue
|
||||
[[ "$USE_COLORS" == 1 ]] && FPURPLE="$(tput setaf 5)" || FPURPLE='' # Purple
|
||||
[[ "$USE_COLORS" == 1 ]] && FCYAN="$(tput setaf 6)" || FCYAN='' # Cyan
|
||||
[[ "$USE_COLORS" == 1 ]] && FWHITE="$(tput setaf 7)" || FWHITE='' # White
|
||||
|
||||
# Text colors - bright
|
||||
[[ "$USE_COLORS" == 1 ]] && FLBLACK="$(tput setaf 8)" || FLBLACK='' # Black
|
||||
[[ "$USE_COLORS" == 1 ]] && FLRED="$(tput setaf 9)" || FLRED='' # Red
|
||||
[[ "$USE_COLORS" == 1 ]] && FLGREEN="$(tput setaf 10)" || FLGREEN='' # Green
|
||||
[[ "$USE_COLORS" == 1 ]] && FLYELLOW="$(tput setaf 11)" || FLYELLOW='' # Yellow
|
||||
[[ "$USE_COLORS" == 1 ]] && FLBLUE="$(tput setaf 12)" || FLBLUE='' # Blue
|
||||
[[ "$USE_COLORS" == 1 ]] && FLPURPLE="$(tput setaf 13)" || FLPURPLE='' # Purple
|
||||
[[ "$USE_COLORS" == 1 ]] && FLCYAN="$(tput setaf 14)" || FLCYAN='' # Cyan
|
||||
[[ "$USE_COLORS" == 1 ]] && FLWHITE="$(tput setaf 15)" || FLWHITE='' # White
|
||||
|
||||
# Background colors - normal
|
||||
[[ "$USE_COLORS" == 1 ]] && FBBLACK="$(tput setab 0)" || FBBLACK='' # Black
|
||||
[[ "$USE_COLORS" == 1 ]] && FBRED="$(tput setab 1)" || FBRED='' # Red
|
||||
[[ "$USE_COLORS" == 1 ]] && FBGREEN="$(tput setab 2)" || FBGREEN='' # Green
|
||||
[[ "$USE_COLORS" == 1 ]] && FBYELLOW="$(tput setab 3)" || FBYELLOW='' # Yellow
|
||||
[[ "$USE_COLORS" == 1 ]] && FBBLUE="$(tput setab 4)" || FBBLUE='' # Blue
|
||||
[[ "$USE_COLORS" == 1 ]] && FBPURPLE="$(tput setab 5)" || FBPURPLE='' # Purple
|
||||
[[ "$USE_COLORS" == 1 ]] && FBCYAN="$(tput setab 6)" || FBCYAN='' # Cyan
|
||||
[[ "$USE_COLORS" == 1 ]] && FBWHITE="$(tput setab 7)" || FBWHITE='' # White
|
||||
|
||||
# Background colors - bright
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLBLACK="$(tput setab 8)" || FBLBLACK='' # Black
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLRED="$(tput setab 9)" || FBLRED='' # Red
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLGREEN="$(tput setab 10)" || FBLGREEN='' # Green
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLYELLOW="$(tput setab 11)" || FBLYELLOW='' # Yellow
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLBLUE="$(tput setab 12)" || FBLBLUE='' # Blue
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLPURPLE="$(tput setab 13)" || FBLPURPLE='' # Purple
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLCYAN="$(tput setab 14)" || FBLCYAN='' # Cyan
|
||||
[[ "$USE_COLORS" == 1 ]] && FBLWHITE="$(tput setab 15)" || FBLWHITE='' # White
|
||||
|
||||
now() {
|
||||
echo "[$(date +'%H:%M:%S')] "
|
||||
}
|
||||
|
||||
ask() {
|
||||
IFS= read -rp "$(print ${FBOLD}${FBBLUE}${FWHITE}${IASK}${FRESET}\ ${FBOLD}$1 ): " $2
|
||||
}
|
||||
|
||||
print() {
|
||||
# if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID > /dev/null; then kill $SPINNER_PID > /dev/null; fi
|
||||
echo -e "$*${FRESET}"
|
||||
}
|
||||
|
||||
link() {
|
||||
echo -e "\e]8;;$2\a$1\e]8;;\a"
|
||||
}
|
||||
|
||||
debug() {
|
||||
if [ "$2" ]; then
|
||||
print "${FDIM}${FBOLD}${FRESET}${FDIM}$(now)${IDEBUG} ${FUNCNAME[1]:-?}():${BASH_LINENO:-?}\t$1 " >&2
|
||||
else
|
||||
print "${FDIM}${FBOLD}${FRESET}${FDIM}$(now)${IDEBUG} $1 " >&2
|
||||
fi
|
||||
}
|
||||
|
||||
var_dump() {
|
||||
debug "$1 = ${!1}"
|
||||
}
|
||||
|
||||
print_stacktrace() {
|
||||
STACK=""
|
||||
local i
|
||||
local stack_size=${#FUNCNAME[@]}
|
||||
debug "Callstack:"
|
||||
# for (( i=$stack_size-1; i>=1; i-- )); do
|
||||
for (( i=1; i<$stack_size; i++ )); do
|
||||
local func="${FUNCNAME[$i]}"
|
||||
[ x$func = x ] && func=MAIN
|
||||
local linen="${BASH_LINENO[$(( i - 1 ))]}"
|
||||
local src="${BASH_SOURCE[$i]}"
|
||||
[ x"$src" = x ] && src=non_file_source
|
||||
debug " at $func $src:$linen"
|
||||
done
|
||||
}
|
||||
|
||||
verbose() {
|
||||
print "${FBOLD}$(now)${IVRB}${FRESET}${FYELLOW} $1 "
|
||||
}
|
||||
|
||||
info() {
|
||||
print "${FBOLD}$(now)${FWHITE}${FBLBLUE}${IINFO}${FRESET}${FWHITE} $1 "
|
||||
}
|
||||
|
||||
note() {
|
||||
print "${FBOLD}$(now)${FDIM}${FWHITE}${INOTE}${FRESET} $1 "
|
||||
}
|
||||
|
||||
success() {
|
||||
print "${FBOLD}$(now)${FBGREEN}${FWHITE}${ISUCCESS}${FRESET}$FGREEN $1 "
|
||||
}
|
||||
|
||||
warn() {
|
||||
print "${FBOLD}$(now)${FBYELLOW}${FBLACK}${IWARN}${FRESET}${FYELLOW} Warning:${FRESET} $1 "
|
||||
}
|
||||
|
||||
error() {
|
||||
print "${FBOLD}$(now)${FBLRED}${FWHITE}${IERROR} Error: ${FRESET}${FLRED} $1 " >&2
|
||||
}
|
||||
|
||||
fatal() {
|
||||
print "${FBOLD}$(now)${FBRED}${FWHITE}${IFATAL} FATAL: $1 " >&2
|
||||
print_stacktrace
|
||||
}
|
||||
|
||||
die() {
|
||||
error "${1:-halted}"
|
||||
exit ${2:-255}
|
||||
}
|
||||
|
||||
# var='test var_dump'
|
||||
# var_dump var
|
||||
# debug 'test debug'
|
||||
# verbose 'test verbose'
|
||||
# info 'test info'
|
||||
# note 'test note'
|
||||
# success 'test success'
|
||||
# warn 'test warn'
|
||||
# error 'test error'
|
||||
# fatal 'test fatal'
|
||||
# die 'test die'
|
||||
|
||||
# experiments ==============================================================================
|
||||
|
||||
# spinner() {
|
||||
# local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
||||
# local spin_i=0
|
||||
# local interval=0.1
|
||||
# printf "\e[?25l"
|
||||
|
||||
# local color="${FGREEN}"
|
||||
|
||||
# while true; do
|
||||
# printf "\r ${color}%s${CL}" "${frames[spin_i]}"
|
||||
# spin_i=$(( (spin_i + 1) % ${#frames[@]} ))
|
||||
# sleep "$interval"
|
||||
# done
|
||||
# }
|
||||
|
||||
# echo "lorem ipsum dolor sit amet"
|
||||
# spinner &
|
||||
# SPINNER_PID=$!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ===========
|
||||
|
||||
|
||||
# https://unix.stackexchange.com/a/269085
|
||||
# https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
|
||||
# https://linuxcommand.org/lc3_adv_tput.php
|
||||
# https://gist.github.com/nowmilano/4055d6df5b6e4ea87c5a72dc2d604193
|
||||
# https://gist.github.com/nick3499/402a6d7dccd474f2bdb679f4311b1238
|
||||
# https://gist.github.com/connorjan/2b02126868157c2b69f9aa0a052cdc86
|
||||
|
||||
# tput setaf 0
|
||||
# echo "BLACK FOREGROUND"
|
||||
# tput setaf 1
|
||||
# echo "RED FOREGROUND"
|
||||
# tput setaf 2
|
||||
# echo "GREEN FOREGROUND"
|
||||
# tput setaf 3
|
||||
# echo "YELLOW FOREGROUND"
|
||||
# tput setaf 4
|
||||
# echo "BLUE FOREGROUND"
|
||||
# tput setaf 5
|
||||
# echo "MAGENTA FOREGROUND"
|
||||
# tput setaf 6
|
||||
# echo "CYAN FOREGROUND"
|
||||
# tput setaf 7
|
||||
# echo "WHITE FOREGROUND"
|
||||
# tput reset
|
||||
|
||||
# ===========
|
||||
|
||||
|
||||
# ===========
|
||||
|
||||
# tohex(){
|
||||
# dec=$(($1%256)) ### input must be a number in range 0-255.
|
||||
# if [ "$dec" -lt "16" ]; then
|
||||
# bas=$(( dec%16 ))
|
||||
# mul=128
|
||||
# [ "$bas" -eq "7" ] && mul=192
|
||||
# [ "$bas" -eq "8" ] && bas=7
|
||||
# [ "$bas" -gt "8" ] && mul=255
|
||||
# a="$(( (bas&1) *mul ))"
|
||||
# b="$(( ((bas&2)>>1)*mul ))"
|
||||
# c="$(( ((bas&4)>>2)*mul ))"
|
||||
# printf 'dec= %3s basic= #%02x%02x%02x\n' "$dec" "$a" "$b" "$c"
|
||||
# elif [ "$dec" -gt 15 ] && [ "$dec" -lt 232 ]; then
|
||||
# b=$(( (dec-16)%6 )); b=$(( b==0?0: b*40 + 55 ))
|
||||
# g=$(( (dec-16)/6%6)); g=$(( g==0?0: g*40 + 55 ))
|
||||
# r=$(( (dec-16)/36 )); r=$(( r==0?0: r*40 + 55 ))
|
||||
# printf 'dec= %3s color= #%02x%02x%02x\n' "$dec" "$r" "$g" "$b"
|
||||
# else
|
||||
# gray=$(( (dec-232)*10+8 ))
|
||||
# printf 'dec= %3s gray= #%02x%02x%02x\n' "$dec" "$gray" "$gray" "$gray"
|
||||
# fi
|
||||
# }
|
||||
|
||||
# for i in $(seq 0 255); do
|
||||
# tohex ${i}
|
||||
# done
|
||||
|
||||
# ===========
|
||||
|
||||
# fromhex(){
|
||||
# hex=${1#"#"}
|
||||
# r=$(printf '0x%0.2s' "$hex")
|
||||
# g=$(printf '0x%0.2s' ${hex#??})
|
||||
# b=$(printf '0x%0.2s' ${hex#????})
|
||||
# printf '%03d' "$(( (r<75?0:(r-35)/40)*6*6 +
|
||||
# (g<75?0:(g-35)/40)*6 +
|
||||
# (b<75?0:(b-35)/40) + 16 ))"
|
||||
# }
|
||||
|
||||
# fromhex 00fc7b
|
||||
|
||||
# ===========
|
||||
|
||||
# mode2header(){
|
||||
# #### For 16 Million colors use \e[0;38;2;R;G;Bm each RGB is {0..255}
|
||||
# printf '\e[mR\n' # reset the colors.
|
||||
# printf '\n\e[m%59s\n' "Some samples of colors for r;g;b. Each one may be 000..255"
|
||||
# printf '\e[m%59s\n' "for the ansi option: \e[0;38;2;r;g;bm or \e[0;48;2;r;g;bm :"
|
||||
# }
|
||||
|
||||
# mode2colors(){
|
||||
# # foreground or background (only 3 or 4 are accepted)
|
||||
# local fb="$1"
|
||||
# [[ $fb != 3 ]] && fb=4
|
||||
# local samples=(0 63 127 191 255)
|
||||
# for r in "${samples[@]}"; do
|
||||
# for g in "${samples[@]}"; do
|
||||
# for b in "${samples[@]}"; do
|
||||
# printf '\e[0;%s8;2;%s;%s;%sm%03d;%03d;%03d ' "$fb" "$r" "$g" "$b" "$r" "$g" "$b"
|
||||
# done; printf '\e[m\n'
|
||||
# done; printf '\e[m'
|
||||
# done; printf '\e[mReset\n'
|
||||
# }
|
||||
# mode2header
|
||||
# mode2colors 3
|
||||
# mode2colors 4
|
||||
|
||||
# ===========
|
||||
|
||||
# printf '\e[48;5;%dm ' {0..255}; printf '\e[0m \n'
|
||||
# for r in {200..255..5}; do
|
||||
# fb=4
|
||||
# g=1
|
||||
# b=1
|
||||
# printf '\e[0;%s8;2;%s;%s;%sm ' "$fb" "$r" "$g" "$b"
|
||||
# done
|
||||
# echo
|
||||
|
||||
# ===========
|
||||
|
||||
# color(){
|
||||
# for c; do
|
||||
# printf '\e[48;5;%dm%03d' $c $c
|
||||
# done
|
||||
# printf '\e[0m \n'
|
||||
# }
|
||||
|
||||
# IFS=$' \t\n'
|
||||
# color {0..15}
|
||||
# for ((i=0;i<6;i++)); do
|
||||
# color $(seq $((i*36+16)) $((i*36+51)))
|
||||
# done
|
||||
# color {232..255}
|
||||
|
||||
# ===========
|
||||
|
||||
# for ((i=0; i<256; i++)) ;do
|
||||
# echo -n ' '
|
||||
# tput setab $i
|
||||
# tput setaf $(( ( (i>231&&i<244 ) || ( (i<17)&& (i%8<2)) ||
|
||||
# (i>16&&i<232)&& ((i-16)%6 <(i<100?3:2) ) && ((i-16)%36<15) )?7:16))
|
||||
# printf " C %03d " $i
|
||||
# tput op
|
||||
# (( ((i<16||i>231) && ((i+1)%8==0)) || ((i>16&&i<232)&& ((i-15)%6==0)) )) &&
|
||||
# printf "\n" ''
|
||||
# done
|
||||
|
||||
# ===========
|
||||
|
||||
# echo "tput character test"
|
||||
# echo "==================="
|
||||
# echo
|
||||
|
||||
# tput bold; echo "This text has the bold attribute."; tput sgr0
|
||||
|
||||
# tput smul; echo "This text is underlined (smul)."; tput rmul
|
||||
|
||||
# # Most terminal emulators do not support blinking text (though xterm
|
||||
# # does) because blinking text is considered to be in bad taste ;-)
|
||||
# tput blink; echo "This text is blinking (blink)."; tput sgr0
|
||||
|
||||
# tput rev; echo "This text has the reverse attribute"; tput sgr0
|
||||
|
||||
# # Standout mode is reverse on many terminals, bold on others.
|
||||
# tput smso; echo "This text is in standout mode (smso)."; tput rmso
|
||||
|
||||
# tput sgr0
|
||||
# echo
|
||||
|
||||
|
||||
# experiments ==============================================================================
|
||||
|
||||
# function delay_spinner(){
|
||||
# ##
|
||||
# ## Usage:
|
||||
# ##
|
||||
# ## $ long-running-command &
|
||||
# ## $ delay_spinner " Please wait msg..."
|
||||
# ##
|
||||
# ## Spinner exists when long-running-command completes
|
||||
# ##
|
||||
# local PROGRESSTXT
|
||||
# if [ ! "$1" ]; then
|
||||
# PROGRESSTXT=" Please wait..."
|
||||
# else
|
||||
# PROGRESSTXT="$1"
|
||||
# fi
|
||||
# # visual progress marker function
|
||||
# # http://stackoverflow.com/users/2869509/wizurd
|
||||
# # vars
|
||||
# local pid=$!
|
||||
# local delay=0.1
|
||||
# local spinstr='|/-\'
|
||||
# echo -e "\n\n"
|
||||
# while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do
|
||||
# local temp=${spinstr#?}
|
||||
# printf "\r$PROGRESSTXT[%c] " "$spinstr"
|
||||
# local spinstr=$temp${spinstr%"$temp"}
|
||||
# sleep $delay
|
||||
# printf "\b\b\b\b\b\b"
|
||||
# done
|
||||
# printf -- '\n\n'
|
||||
# #
|
||||
# # <-- end function ec2cli_spinner -->
|
||||
# #
|
||||
# }
|
||||
# sleep 10 && echo 'test' &
|
||||
# delay_spinner "Please wait msg..."
|
||||
13
scripts/helpers/log.sh
Normal file
13
scripts/helpers/log.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################
|
||||
# Logging functions
|
||||
########################################################
|
||||
|
||||
# write some message $1 in log file and stdout with timestamp
|
||||
log_path="/home/$USER/logs"
|
||||
log() {
|
||||
[ ! -d "$log_path" ] && log_path="./log"
|
||||
[ ! -d "$log_path" ] && mkdir -p "$log_path"
|
||||
echo -e "[$(date '+%H:%M:%S')] $*" | tee -a "$log_path/$(date '+%Y%m%d').log"
|
||||
}
|
||||
29
scripts/helpers/misc.sh
Normal file
29
scripts/helpers/misc.sh
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################
|
||||
# Misc
|
||||
########################################################
|
||||
|
||||
# https://askubuntu.com/a/30414
|
||||
is_full_screen() {
|
||||
local WINDOW=$(xwininfo -id "$(xdotool getactivewindow)" -stats \
|
||||
| grep -E '(Width|Height):' \
|
||||
| awk '{print $NF}' \
|
||||
| sed -e 's/ /x/')
|
||||
local SCREEN=$(xdpyinfo | grep -m1 dimensions | awk '{print $2}')
|
||||
if [ "$WINDOW" = "$SCREEN" ]; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
ytm() {
|
||||
youtube-dl \
|
||||
--extract-audio \
|
||||
--audio-format flac \
|
||||
--audio-quality 0 \
|
||||
--format bestaudio \
|
||||
--write-info-json \
|
||||
--output "$HOME/Downloads/ytm/%(playlist_title)s/%(channel)s - %(title)s.%(ext)s" \
|
||||
"$@"
|
||||
}
|
||||
51
scripts/helpers/net.sh
Normal file
51
scripts/helpers/net.sh
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################
|
||||
# Networking functions
|
||||
########################################################
|
||||
|
||||
get_current_ip() {
|
||||
local CURRENT_IP
|
||||
[ -f /etc/os-release ] && source /etc/os-release
|
||||
case "$ID" in
|
||||
debian|ubuntu) CURRENT_IP=$(hostname -I | awk '{print $1}') ;;
|
||||
alpine) CURRENT_IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1) ;;
|
||||
*) CURRENT_IP="Unknown" ;;
|
||||
esac
|
||||
echo "$CURRENT_IP"
|
||||
}
|
||||
|
||||
get_external_ip() {
|
||||
local ip="$(curl -s https://api.myip.com | jq .ip)"
|
||||
echo "$ip" | tr -d '"'
|
||||
}
|
||||
|
||||
is_valid_ipv4() {
|
||||
local ip="$1"
|
||||
local regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
|
||||
|
||||
if [[ $ip =~ $regex ]]; then
|
||||
IFS='.' read -r -a parts <<< "$ip"
|
||||
for part in "${parts[@]}"; do
|
||||
if ! [[ $part =~ ^[0-9]+$ ]] || ((part < 0 || part > 255)); then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
curltime() {
|
||||
curl -w @- -o /dev/null -s "$@" <<'EOF'
|
||||
time_namelookup: %{time_namelookup} sec\n
|
||||
time_connect: %{time_connect} sec\n
|
||||
time_appconnect: %{time_appconnect} sec\n
|
||||
time_pretransfer: %{time_pretransfer} sec\n
|
||||
time_redirect: %{time_redirect} sec\n
|
||||
time_starttransfer: %{time_starttransfer} sec\n
|
||||
---------------\n
|
||||
time_total: %{time_total} sec\n
|
||||
EOF
|
||||
}
|
||||
|
||||
63
scripts/helpers/notif.sh
Normal file
63
scripts/helpers/notif.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
########################################################
|
||||
# Notifications
|
||||
########################################################
|
||||
|
||||
TITLE="$0"
|
||||
NTFY_CHANNEL="example"
|
||||
|
||||
# отправляет простую нотификацию
|
||||
ntfy_info() {
|
||||
require ntfy
|
||||
ntfy send \
|
||||
--title "$TITLE" \
|
||||
--message "$1" \
|
||||
--priority 1 \
|
||||
"$NTFY_CHANNEL"
|
||||
}
|
||||
|
||||
# отправляет нотификацию с предупреждением
|
||||
ntfy_warn() {
|
||||
require ntfy
|
||||
ntfy send \
|
||||
--title "$TITLE" \
|
||||
--tags "warning" \
|
||||
--message "$1" \
|
||||
--priority 5 \
|
||||
"$NTFY_CHANNEL"
|
||||
}
|
||||
|
||||
|
||||
notify () {
|
||||
if ! installed "notify-send"; then
|
||||
warning "Notifications toggled on, but 'notify-send' is not installed!"
|
||||
return 1
|
||||
fi
|
||||
[ -n "$1" ] && local title="$1"
|
||||
local text="$2"
|
||||
local level="$3"
|
||||
local icon="$4"
|
||||
case "$level" in
|
||||
critical) local timeout=0 ;;
|
||||
low) local timeout=5000 ;;
|
||||
*) local timeout=10000 ;;
|
||||
esac
|
||||
debug "$title / $text / $level / $icon / $timeout"
|
||||
notify-send "$title" "$text" -a "$0" -u "$level" -i "$icon" -t $timeout
|
||||
}
|
||||
|
||||
# TODO: docblock
|
||||
notify_error() {
|
||||
notify "Error" "$1" "critical" "dialog-error"
|
||||
}
|
||||
|
||||
# TODO: docblock
|
||||
notify_warning() {
|
||||
notify "Warning" "$1" "normal" "dialog-warning"
|
||||
}
|
||||
|
||||
# TODO: docblock
|
||||
notify_info() {
|
||||
notify "" "$1" "low" "dialog-information"
|
||||
}
|
||||
32
scripts/helpers/notifications.sh
Normal file
32
scripts/helpers/notifications.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
source $( dirname $(readlink -e -- "${BASH_SOURCE}"))/packages.sh || exit 255
|
||||
|
||||
########################################################
|
||||
# Desktop notifications
|
||||
########################################################
|
||||
|
||||
notify () {
|
||||
require "notify-send"
|
||||
[ -n "$1" ] && local title="$1" || local title="My notification"
|
||||
local text="$2"
|
||||
local level="$3"
|
||||
local icon="$4"
|
||||
case $level in
|
||||
"critical") local timeout=0 ;;
|
||||
"low") local timeout=5000 ;;
|
||||
*) local timeout=10000 ;;
|
||||
esac
|
||||
notify-send "$title" "$text" -a "MyScript" -u "$level" -i "$icon" -t $timeout
|
||||
}
|
||||
|
||||
notify_error() {
|
||||
notify "Error" "$1" "critical" "dialog-error"
|
||||
}
|
||||
|
||||
notify_warning() {
|
||||
notify "Warning" "$1" "normal" "dialog-warning"
|
||||
}
|
||||
|
||||
notify_info() {
|
||||
notify "" "$1" "low" "dialog-information"
|
||||
}
|
||||
72
scripts/helpers/packages.sh
Normal file
72
scripts/helpers/packages.sh
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
source $( dirname $(readlink -e -- "${BASH_SOURCE}"))/io.sh || exit 255
|
||||
|
||||
########################################################
|
||||
# Functions to control system packages
|
||||
########################################################
|
||||
|
||||
installed() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
installed_pkg() {
|
||||
dpkg --list | grep -qw "ii $1"
|
||||
}
|
||||
|
||||
apt_ppa_add() {
|
||||
sudo add-apt-repository -y $*
|
||||
}
|
||||
|
||||
apt_ppa_remove() {
|
||||
sudo add-apt-repository -ry $*
|
||||
}
|
||||
|
||||
apt_update() {
|
||||
sudo apt update $*
|
||||
}
|
||||
|
||||
apt_install() {
|
||||
sudo apt install -y $*
|
||||
}
|
||||
|
||||
apt_remove() {
|
||||
sudo apt purge -y $*
|
||||
}
|
||||
|
||||
dpkg_install() {
|
||||
sudo dpkg -i $*
|
||||
}
|
||||
|
||||
dpkg_remove() {
|
||||
sudo dpkg -r $*
|
||||
}
|
||||
|
||||
dpkg_arch() {
|
||||
dpkg --print-architecture
|
||||
}
|
||||
|
||||
require() {
|
||||
sw=()
|
||||
for package in "$@"; do
|
||||
if ! installed "$package" && ! installed_pkg "$package"; then
|
||||
sw+=("$package")
|
||||
fi
|
||||
done
|
||||
if [ ${#sw[@]} -gt 0 ]; then
|
||||
info "These packages will be installed in your system:\n${sw[*]}"
|
||||
apt_install ${sw[*]}
|
||||
[ $? -gt 0 ] && die "installation cancelled" 201
|
||||
fi
|
||||
}
|
||||
|
||||
require_pkg() {
|
||||
sw=()
|
||||
for package in "$@"; do
|
||||
if ! installed "$package" && ! installed_pkg "$package"; then
|
||||
sw+=("$package")
|
||||
fi
|
||||
done
|
||||
if [ ${#sw[@]} -gt 0 ]; then
|
||||
die "These packages must be installed in your system:\n${sw[*]}" 200
|
||||
fi
|
||||
}
|
||||
89
scripts/helpers/testing.sh
Normal file
89
scripts/helpers/testing.sh
Normal file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
source $( dirname $(readlink -e -- "${BASH_SOURCE}"))/io.sh || exit 255
|
||||
|
||||
########################################################
|
||||
# Testing functions
|
||||
########################################################
|
||||
|
||||
# $1 - command to exec
|
||||
assert_exec() {
|
||||
[ "$1" ] || exit 1
|
||||
local prefix="$(dt)${BOLD}${FWHITE}[TEST EXEC]"
|
||||
if $($1 1>/dev/null 2>&1); then
|
||||
local text="${BGREEN} PASSED"
|
||||
else
|
||||
local text="${BLRED} FAILED"
|
||||
fi
|
||||
print "${prefix} ${text} ${BRESET} ($?):${RESET} $1"
|
||||
}
|
||||
# usage:
|
||||
|
||||
# func1() {
|
||||
# return 0
|
||||
# }
|
||||
# func2() {
|
||||
# return 1
|
||||
# }
|
||||
# assert_exec "func1" # PASSED
|
||||
# assert_exec "func2" # FAILED
|
||||
# assert_exec "whoami" # PASSED
|
||||
|
||||
|
||||
# $1 - command to exec
|
||||
# $2 - expected output
|
||||
assert_output() {
|
||||
[ "$1" ] || exit 1
|
||||
[ "$2" ] && local expected="$2" || local expected=''
|
||||
local prefix="$(dt)${BOLD}${FWHITE}[TEST OUTP]"
|
||||
local output=$($1 2>&1)
|
||||
local code=$?
|
||||
if [[ "$output" == *"$expected"* ]]; then
|
||||
local text="${BGREEN} PASSED"
|
||||
else
|
||||
local text="${BLRED} FAILED"
|
||||
fi
|
||||
print "${prefix} ${text} ${BRESET} (${code}|${expected}):${RESET} $1"
|
||||
# print "\tOutput > $output"
|
||||
}
|
||||
# usage:
|
||||
|
||||
# func1() {
|
||||
# echo "some string"
|
||||
# }
|
||||
# func2() {
|
||||
# echo "another string"
|
||||
# }
|
||||
# expect_output "func1" "string" # PASSED
|
||||
# expect_output "func2" "some" # FAILED
|
||||
# expect_output "func2" "string" # PASSED
|
||||
|
||||
|
||||
# $1 - command to exec
|
||||
# $2 - expected exit-code
|
||||
assert_code() {
|
||||
[ "$1" ] || exit 1
|
||||
[ "$2" ] && local expected=$2 || local expected=0
|
||||
local prefix="$(dt)${BOLD}${FWHITE}[TEST CODE]"
|
||||
$($1 1>/dev/null 2>&1)
|
||||
local code=$?
|
||||
if [[ $code -eq $expected ]]; then
|
||||
local text="${BGREEN} PASSED"
|
||||
else
|
||||
local text="${BLRED} FAILED"
|
||||
fi
|
||||
print "${prefix} ${text} ${BRESET} (${code}|${expected}):${RESET} $1"
|
||||
}
|
||||
# usage:
|
||||
|
||||
# func1() {
|
||||
# # exit 0
|
||||
# return 0
|
||||
# }
|
||||
# func2() {
|
||||
# # exit 1
|
||||
# return 1
|
||||
# }
|
||||
# expect_code "func1" 0 # PASSED
|
||||
# expect_code "func1" 1 # FAILED
|
||||
# expect_code "func2" 0 # FAILED
|
||||
# expect_code "func2" 1 # PASSED
|
||||
21
scripts/helpers/traps.sh
Normal file
21
scripts/helpers/traps.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
#TODO source basic.sh
|
||||
#TODO source args-parser/args.sh
|
||||
|
||||
########################################################
|
||||
# Trap usage examples
|
||||
########################################################
|
||||
|
||||
# for sig in SIGHUP SIGINT SIGQUIT SIGABRT SIGKILL SIGTERM SIGTSTP; do
|
||||
# # shellcheck disable=SC2064
|
||||
# trap "set +x && echo && echo && echo '*** Прервано сигналом $sig, остановка ***' && exit" $sig
|
||||
# done
|
||||
|
||||
for sig in SIGHUP SIGINT SIGQUIT SIGABRT SIGKILL SIGTERM SIGTSTP; do
|
||||
trap "myfunc" $sig
|
||||
done
|
||||
|
||||
myfunc() {
|
||||
echo "trapped!"
|
||||
exit
|
||||
}
|
||||
Reference in New Issue
Block a user