initial setup
This commit is contained in:
commit
d7b4ee9d96
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.deb
|
103
README.md
Executable file
103
README.md
Executable file
@ -0,0 +1,103 @@
|
||||
# Driglibash
|
||||
Simple helper script for bash, in bash.
|
||||
Those scripts are not optimized at all, they may be slow and ressources consuming. They are made for simplicity.
|
||||
|
||||
## Installation
|
||||
```
|
||||
sudo wget https://raw.githubusercontent.com/adrian-amaglio/driglibash/master/driglibash-base -O /usr/bin/driglibash-base
|
||||
sudo wget https://raw.githubusercontent.com/adrian-amaglio/driglibash/master/driglibash-args -O /usr/bin/driglibash-args
|
||||
```
|
||||
|
||||
## Driglibash-base
|
||||
This file contains some very basic functions that are wildely used. Since bash is pain to read, you better do a lot of them.
|
||||
|
||||
### yell
|
||||
Print its arguments on stderr.
|
||||
|
||||
### die
|
||||
Like yell but clean and exit too.
|
||||
|
||||
### root_or_die
|
||||
Execute `die` if the user is not root
|
||||
|
||||
### clean
|
||||
Store its last argument as command and execute them all when called without arguments. Example :
|
||||
```
|
||||
$ clean "echo file"
|
||||
$ clean
|
||||
file
|
||||
```
|
||||
You can add a first argument in (pre/post/del) to add your command before/after the others or to remove it from the list
|
||||
Clean is automatically called on SIGINT and by `die`. You should call it at your scripts end to handle the cleaning.
|
||||
|
||||
### section
|
||||
Print a separation line that is the size of the terminal. If an argument is provided, it will be displayed in the middle of the line.
|
||||
```
|
||||
$ section 'Unit tests'
|
||||
====================================== Unit tests ======================================
|
||||
```
|
||||
|
||||
### run
|
||||
Execute a command. Run a clean and exit if it returns a non zero status.
|
||||
If you set the variable `driglibash_run_retry`, you will be asked to retry a failing command.
|
||||
|
||||
### start
|
||||
Execute a command in background, add a clean task that kill it, and returns the pid.
|
||||
Be careful ! Only the PID of the started process is returned. If the process forks, driglibash can’t stop it when needed.
|
||||
|
||||
### where
|
||||
Tells you where (in absolute path) is the script being executed. Useful when you want to access som files next to your executable. If the `--follow` argument is provided, `where` will follow symlinks and find the linked script file.
|
||||
MUST BE RUN BEFORE ANY `cd`
|
||||
|
||||
### repeat
|
||||
Print its first argument, the second argument times.
|
||||
```
|
||||
$ repeat '=' 10
|
||||
==========
|
||||
```
|
||||
|
||||
|
||||
## driglibash-args
|
||||
A little framework for argument parsing in bash. It already contains driglibash-base.
|
||||
Just fill the arrays `usage` et `varia` and the value
|
||||
Usage exemple :
|
||||
```
|
||||
# Thoses two lines are important for bash
|
||||
declare -A usage
|
||||
declare -A varia
|
||||
|
||||
version="alpha nightly 0.0.1 pre-release unstable"
|
||||
summary="$0 [options] <device>"
|
||||
|
||||
# if the script is called with -t option, tst will be set to true
|
||||
usage[t]="Start qemu after the installation"
|
||||
varia[t]=tst
|
||||
tst=false
|
||||
|
||||
# if the script is called with -i option, tst will be an array of every argument passed to -i (must repeat -i)
|
||||
usage[i]="Install the provided package. Not implemented"
|
||||
varia[i]=install
|
||||
declare -a install
|
||||
|
||||
. driglibash-args
|
||||
# After this line, driglibash-base is available and your variables are set according to arguments
|
||||
# Exemple. If you call :
|
||||
# ./this-script -i package2 -t -i package1
|
||||
# tst will be true and install will be an array containing (package2 package1)
|
||||
```
|
||||
|
||||
## Build .deb
|
||||
Expected output:
|
||||
```
|
||||
$ ./build
|
||||
dpkg-deb: building package 'driglibash' in 'driglibash.deb'.
|
||||
```
|
||||
|
||||
## Tests
|
||||
Expected output:
|
||||
```
|
||||
$ cd tests
|
||||
$ ./run.sh
|
||||
OK. PASSED.
|
||||
OK. PASSED.
|
||||
```
|
7
src/DEBIAN/control
Normal file
7
src/DEBIAN/control
Normal file
@ -0,0 +1,7 @@
|
||||
Package: driglibash
|
||||
Version: 1.0-0
|
||||
Priority: optional
|
||||
Depends: sed
|
||||
Maintainer: Adrian Amaglio <adrian@amaglio.fr>
|
||||
Architecture: all
|
||||
Description: Bash script helpers and arg framework
|
90
src/usr/bin/driglibash-args
Executable file
90
src/usr/bin/driglibash-args
Executable file
@ -0,0 +1,90 @@
|
||||
#!/bin/bash
|
||||
|
||||
###############################################################################
|
||||
# https://github.com/adrianamaglio/driglibash-arg
|
||||
###############################################################################
|
||||
|
||||
|
||||
# Usage :
|
||||
#
|
||||
# version="alpha nightly 0.0.1 pre-release unstable"
|
||||
# summary="$0 [options] <device>"
|
||||
#
|
||||
# usage[t]="Start qemu after the installation"
|
||||
# varia[t]=tst
|
||||
# tst=false
|
||||
#
|
||||
# usage[i]="Install the provided package. Not implemented"
|
||||
# varia[i]=install
|
||||
# declare -a install
|
||||
#
|
||||
# usage[k]="Keep the temporar mountpoints"
|
||||
# varia[k]=keep
|
||||
# keep=false
|
||||
#
|
||||
# usage[e]="bash command file to execute in the chroot. - to read from stdin"
|
||||
# varia[e]=execute
|
||||
# declare -a execute
|
||||
|
||||
. /usr/local/bin/driglibash-base
|
||||
|
||||
#TODO keep order usage options
|
||||
# Print usage and exit in error
|
||||
usage() {
|
||||
yell "Version: $version"
|
||||
yell "Usage: $summary"
|
||||
yell "Parameters:"
|
||||
yell " -h print this help, version and exit."
|
||||
for key in "${!usage[@]}" ; do
|
||||
if [ "$(driglibash_arg_type "$key")" == "single_value" ] ; then
|
||||
name="${varia[$key]}"
|
||||
default=" (default : ${!name})"
|
||||
else
|
||||
default=
|
||||
fi
|
||||
yell " -$key ${usage[$key]}$default"
|
||||
done
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Guess the variable type
|
||||
# Boolean, list or string
|
||||
driglibash_arg_type() {
|
||||
if [ $# -ne 1 ] ; then
|
||||
die "Bad driglibash_arg_type usage";
|
||||
fi
|
||||
|
||||
name="${varia[$1]}"
|
||||
if [ "$name" == "" ] ; then die "Variable name is empty for key $1" ; fi
|
||||
if [ "${!name}" == "false" ] ; then
|
||||
echo "boolean"
|
||||
elif [ -n "$( declare -p "$name" 2>/dev/null | grep 'declare \-a')" ] ; then
|
||||
echo "array"
|
||||
else
|
||||
echo "single_value"
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate getopts string #
|
||||
getopts_string=":h"
|
||||
for key in ${!usage[@]} ; do
|
||||
needs_parameter=
|
||||
if [ "$(driglibash_arg_type "$key")" != "boolean" ] ; then needs_parameter=":" ; fi
|
||||
getopts_string="$getopts_string$key$needs_parameter"
|
||||
done
|
||||
|
||||
# Loop throught options #
|
||||
while getopts "$getopts_string" opt; do
|
||||
case $opt in
|
||||
h) usage;;
|
||||
:) die "Option -$OPTARG requires an argument.";;
|
||||
\?) die "Invalid option: -$OPTARG";;
|
||||
*)
|
||||
name="${varia[$opt]}"
|
||||
if [ "${!name}" == "false" ] ; then eval $name=true
|
||||
elif [ -n "$( declare -p "$name" 2>/dev/null | grep 'declare \-a')" ] ; then safe="${!name} $OPTARG" ; eval $name=\$safe
|
||||
else eval $name=\$OPTARG
|
||||
fi;;
|
||||
esac
|
||||
done ; shift $((OPTIND-1))
|
||||
|
185
src/usr/bin/driglibash-base
Executable file
185
src/usr/bin/driglibash-base
Executable file
@ -0,0 +1,185 @@
|
||||
###############################################################################
|
||||
# Driglibash pack 1
|
||||
# Usual helper functions for bash scripts
|
||||
# https://github.com/adrianamaglio/driglibash
|
||||
###############################################################################
|
||||
|
||||
# Set to true to make a pause at each step
|
||||
if [ ! -v driglibash_step_by_step ] ; then
|
||||
driglibash_step_by_step=false
|
||||
fi
|
||||
|
||||
# Set to watever you want to have a prefix
|
||||
if [ ! -v driglibash_section_prefix ] ; then
|
||||
driglibash_section_prefix=""
|
||||
fi
|
||||
|
||||
|
||||
trap 'die "Received sigint"' INT
|
||||
|
||||
# Output on standard error output
|
||||
yell() {
|
||||
echo >&2 -e "$@"
|
||||
}
|
||||
|
||||
# Print an error, clean and exit
|
||||
die() {
|
||||
yell "$@"
|
||||
clean
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Exit on error if not root
|
||||
root_or_die() {
|
||||
if [ "$UID" -ne 0 ] ; then
|
||||
die "You need to be root"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Output first parameter, second parameter times
|
||||
repeat() {
|
||||
printf "$1"'%.s' $(eval "echo {1.."$(($2))"}")
|
||||
}
|
||||
|
||||
# Output a "section title" to visually separate different script part
|
||||
# TODO local variables
|
||||
# TODO fixed place left aligned
|
||||
section(){
|
||||
text="$driglibash_section_prefix$1"
|
||||
if [ -n "$text" ] ; then
|
||||
len="${#text}"
|
||||
max_len="$(($(tput cols)-2))"
|
||||
if [ "$len" -ge "$max_len" ] ; then
|
||||
right=5
|
||||
left=5
|
||||
else
|
||||
left="$((($max_len - $len)/2))"
|
||||
right="$left"
|
||||
fi
|
||||
else
|
||||
left=80
|
||||
right=0
|
||||
fi
|
||||
|
||||
# If the character number was rounded down
|
||||
if [ "$(($left + $right + $len +1 ))" -eq "$max_len" ] ; then
|
||||
left="$(($left+ 1))"
|
||||
fi
|
||||
|
||||
repeat '=' "$left"
|
||||
if [ "$right" -ge 1 ] ; then
|
||||
echo -n " $text "
|
||||
repeat '=' "$right"
|
||||
echo
|
||||
fi
|
||||
|
||||
if "$driglibash_step_by_step" ; then
|
||||
echo "Press enter to proceed"
|
||||
read
|
||||
fi
|
||||
}
|
||||
alias step=section
|
||||
|
||||
# Execute a command and die if it returns with error #
|
||||
run() {
|
||||
while true ; do
|
||||
"$@"
|
||||
code=$?
|
||||
if [ "$code" -ne 0 ] ; then
|
||||
yell "command [$*] failed with exit code '$code'"
|
||||
if [ -n "$driglibash_run_retry" ] ; then
|
||||
echo "Retry ? Retry (y), skip the command (s) or exit script(n) [Y/s/n] ?"
|
||||
read answer
|
||||
if [ "$answer" = "y" ] || [ "$answer" = "Y" ] || [ -z "$answer" ] ; then
|
||||
continue
|
||||
elif [ "$answer" = "s" ] || [ "$answer" = "S" ] ; then
|
||||
return "$code"
|
||||
fi
|
||||
fi
|
||||
die "Aborting"
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# Execute a commad in background and return its pid
|
||||
start(){
|
||||
"$@" &
|
||||
pid=$!
|
||||
clean pre "kill $pid"
|
||||
return $pid
|
||||
}
|
||||
|
||||
# Clean exit #
|
||||
# Record command lines passed as argument and execute them all when called without args #
|
||||
# One argument = One command #
|
||||
# TODO append or prepend according to arg
|
||||
declare -a driglibash_clean_actions
|
||||
clean() {
|
||||
if [ "$#" -eq 0 ] ; then
|
||||
echo "Cleaning"
|
||||
for action in "${driglibash_clean_actions[@]}" ; do
|
||||
echo "driglibash_clean> $action"
|
||||
$action
|
||||
done
|
||||
elif [ "$#" -eq 1 ] ; then
|
||||
driglibash_clean_actions+=("$1")
|
||||
elif [ "$#" -eq 2 ] ; then
|
||||
case "$1" in
|
||||
"pre")
|
||||
declare -a tmp
|
||||
tmp=("${driglibash_clean_actions[@]}")
|
||||
driglibash_clean_actions=("$2")
|
||||
driglibash_clean_actions+=("${tmp[@]}")
|
||||
;;
|
||||
"post")
|
||||
driglibash_clean_actions+=("$2")
|
||||
;;
|
||||
"del")
|
||||
for i in "${!driglibash_clean_actions[@]}" ; do
|
||||
if [ "$2" = "${driglibash_clean_actions[$i]}" ] ; then
|
||||
unset driglibash_clean_actions[$i]
|
||||
break
|
||||
fi
|
||||
done
|
||||
;;
|
||||
*)
|
||||
die "driglibash_clean: action '$1' not supported"
|
||||
esac
|
||||
else
|
||||
die "driglibash_clean : Bad clean usage, receveid more than two args"
|
||||
fi
|
||||
}
|
||||
|
||||
# tells where your executable is (absolute path). Follow simlinks if any argument provided
|
||||
# Must be called in first place
|
||||
where() {
|
||||
if [ ! -v "1" ] ; then
|
||||
cd -P "$(dirname "$( realpath "$0" )")" && pwd
|
||||
else
|
||||
SOURCE="$0"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
echo $DIR
|
||||
fi
|
||||
}
|
||||
|
||||
# Add the line $1 in file $2 if not present
|
||||
line_in_file() {
|
||||
if [ "$#" -ne 2 ] ; then die "Bad usage of 'line_in_file'. Got '$#' parameters : '$@'" ; fi
|
||||
if [ -z "$1" ] ; then die "Line arg is emtpy in 'line_in_file'" ; fi
|
||||
line="$1"
|
||||
if [ -z "$2" ] ; then die "File arg is emtpy in 'line_in_file'" ; fi
|
||||
file="$2"
|
||||
if [ ! -f "$file" ] ; then run touch "$file" ; fi
|
||||
|
||||
grep -q -x -F "$line" "$file" || echo "$line" >> "$file"
|
||||
}
|
50
tests/driglibash-args.sh
Executable file
50
tests/driglibash-args.sh
Executable file
@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
fail () {
|
||||
echo -e "$@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cat > script.sh <<- EOF
|
||||
declare -A usage
|
||||
declare -A varia
|
||||
|
||||
version="alpha nightly 0.0.1 pre-release unstable"
|
||||
summary="\$0 [options] <device>"
|
||||
|
||||
usage[t]="Start qemu after the installation"
|
||||
varia[t]=tst
|
||||
tst=false
|
||||
|
||||
usage[u]="u"
|
||||
varia[u]=u
|
||||
u=false
|
||||
|
||||
usage[i]="Install the provided package. Not implemented"
|
||||
varia[i]=install
|
||||
declare -a install
|
||||
|
||||
usage[e]="bash command file to execute in the chroot. - to read from stdin"
|
||||
varia[e]=execute
|
||||
execute="default"
|
||||
|
||||
usage[a]="bash command file to execute in the chroot. - to read from stdin"
|
||||
varia[a]=a
|
||||
a="default"
|
||||
|
||||
. ../src/usr/bin/driglibash-args
|
||||
|
||||
if [ "\$tst" != "true" ] ; then echo "\$tst tst not true" ; exit 1 ; fi
|
||||
if [ "\$u" != "false" ] ; then echo "\$u u not false" ; exit 1 ; fi
|
||||
if [ "\$install" != " in1 in2" ] ; then echo "\$install install not right" ;exit 1 ; fi
|
||||
if [ "\$execute" != "ex" ] ; then echo "\$execute execute not true" ;exit 1 ; fi
|
||||
if [ "\$a" != "default" ] ; then echo "\$a a not true" ;exit 1 ; fi
|
||||
EOF
|
||||
|
||||
bash script.sh -i in1 -e ex -i in2 -t
|
||||
s="$?"
|
||||
if [ "$s" -ne "0" ] ; then
|
||||
fail "The script exited with a non zero status : $s"
|
||||
fi
|
||||
rm script.sh
|
||||
echo "OK. PASSED."
|
83
tests/driglibash-base.sh
Executable file
83
tests/driglibash-base.sh
Executable file
@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
fail () {
|
||||
echo -e "$@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
here="$(pwd)"
|
||||
. "$driglibash_base"
|
||||
|
||||
|
||||
###############################################################################
|
||||
# here
|
||||
###############################################################################
|
||||
|
||||
# Test from this directory
|
||||
if [ "$(where)" != "$here" ] ; then
|
||||
echo $(where)
|
||||
echo $here
|
||||
fail "where != here"
|
||||
fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# yelle
|
||||
###############################################################################
|
||||
|
||||
bash > out 2> err <<-EOF
|
||||
. "$driglibash_base"
|
||||
yell "coucou"
|
||||
EOF
|
||||
|
||||
if [ "$?" -ne "0" ] ; then fail "'yell' does not exit with status 0" ; fi
|
||||
if [ "$(cat out)" != "" ] ; then fail "'yell' stdout is not empty (got $(cat out))" ; fi
|
||||
if [ "$(cat err)" != "coucou" ] ; then fail "'yell' stderr is not correct (got $(cat err))" ; fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# die
|
||||
###############################################################################
|
||||
|
||||
bash > out 2> err <<-EOF
|
||||
. "$driglibash_base"
|
||||
die "coucou"
|
||||
EOF
|
||||
|
||||
if [ "$?" -ne "1" ] ; then fail "'die' does not exit with status 1" ; fi
|
||||
if [ "$(cat out)" == "" ] ; then fail "'die' stdout is not empty" ; fi
|
||||
if [ "$(cat err)" != "coucou" ] ; then fail "'die' stderr is not correct :\n$(cat err | hexdump -c)" ; fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# clean
|
||||
###############################################################################
|
||||
|
||||
clean 'a a a a'
|
||||
if [ "${driglibash_clean_actions[@]}" != "a a a a" ] ; then fail "clean with only command does not work" ; fi
|
||||
|
||||
clean 'b b b'
|
||||
if [ "${driglibash_clean_actions[0]}" != "a a a a" ] ; then fail "clean append does not work 0" ; fi
|
||||
if [ "${driglibash_clean_actions[1]}" != "b b b" ] ; then fail "clean append does not work 1" ; fi
|
||||
|
||||
clean del 'b b b'
|
||||
if [ "${driglibash_clean_actions[0]}" != "a a a a" ] ; then fail "clean del does not work 0" ; fi
|
||||
if [ -n "${driglibash_clean_actions[1]}" ] ; then fail "clean del does not work 1" ; fi
|
||||
|
||||
clean post 'b b b'
|
||||
if [ "${driglibash_clean_actions[0]}" != "a a a a" ] ; then fail "clean post does not work 0 (got '${driglibash_clean_actions[0]}')" ; fi
|
||||
if [ "${driglibash_clean_actions[1]}" != "b b b" ] ; then fail "clean post does not work 1 (got '${driglibash_clean_actions[0]}')" ; fi
|
||||
|
||||
clean pre 'b b b'
|
||||
if [ "${driglibash_clean_actions[0]}" != "b b b" ] ; then fail "clean pre does not work 0 (got '${driglibash_clean_actions[0]}')" ; fi
|
||||
if [ "${driglibash_clean_actions[1]}" != "a a a a" ] ; then fail "clean pre does not work 1 (got '${driglibash_clean_actions[1]}')" ; fi
|
||||
if [ "${driglibash_clean_actions[2]}" != "b b b" ] ; then fail "clean pre does not work 2 (got '${driglibash_clean_actions[2]}')" ; fi
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
# end
|
||||
###############################################################################
|
||||
rm out err
|
||||
echo "OK. PASSED."
|
9
tests/run.sh
Executable file
9
tests/run.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -a
|
||||
driglibash_base=../src/usr/bin/driglibash-base
|
||||
driglibash_args=../src/usr/bin/driglibash-args
|
||||
set +a
|
||||
|
||||
./driglibash-base.sh
|
||||
./driglibash-args.sh
|
Loading…
Reference in New Issue
Block a user