From eca55e60c29440c4e2e007b54ea1a1983e965954 Mon Sep 17 00:00:00 2001 From: davidovski Date: Thu, 1 Oct 2026 10:34:33 +0100 Subject: Add libhbar to shmk --- Makefile | 15 ++- build.shmk | 27 +++-- shmk.shmk | 9 +- src/lib/colors.h | 45 ------- src/lib/colors.list | 42 ------- src/lib/colors.sh | 44 ------- src/lib/generate_colors.sh | 44 ------- src/lib/libhbar.sh | 116 ++++++++++++++++++ src/tools/colors.list | 42 +++++++ src/tools/generate_colors.sh | 45 +++++++ src/util/hbar.sh | 104 +--------------- src/util/parseconf.sh | 42 +++---- src/util/shmk.README | 121 ------------------ src/util/shmk.sh | 257 --------------------------------------- src/util/shmk/shmk.README | 129 ++++++++++++++++++++ src/util/shmk/shmk.sh | 283 +++++++++++++++++++++++++++++++++++++++++++ test/hbar.sh | 19 +-- 17 files changed, 678 insertions(+), 706 deletions(-) delete mode 100644 src/lib/colors.h delete mode 100644 src/lib/colors.list delete mode 100644 src/lib/colors.sh delete mode 100644 src/lib/generate_colors.sh create mode 100644 src/lib/libhbar.sh create mode 100644 src/tools/colors.list create mode 100644 src/tools/generate_colors.sh delete mode 100644 src/util/shmk.README delete mode 100755 src/util/shmk.sh create mode 100644 src/util/shmk/shmk.README create mode 100755 src/util/shmk/shmk.sh diff --git a/Makefile b/Makefile index 7a70af9..df648fb 100755 --- a/Makefile +++ b/Makefile @@ -4,23 +4,22 @@ PREFIX=/usr export PATH := .:$(PATH) -shmk0: +shmk0: clean @echo shmk stage0 - @install -m755 src/util/shmk.sh shmk + @install -m755 src/util/shmk/shmk.sh shmk -bootstrap: shmk0 +shmk1: shmk0 @echo shmk stage1 @./shmk.shmk build @install -m755 dist/shmk shmk -build: bootstrap +build: shmk1 @echo all xiutils @./build.shmk build -clean: shmk0 - @rm -r dist - @rm -r shmk - @./build.shmk clean +clean: + @rm -rf dist + @rm -f shmk check: build @./build.shmk check diff --git a/build.shmk b/build.shmk index 55ba601..d53b1e7 100755 --- a/build.shmk +++ b/build.shmk @@ -4,21 +4,26 @@ CC=gcc -LIBS="src/lib/*.sh" +LIBS=" + src/lib/xilib.sh + src/lib/libhbar.sh + src/lib/xitui.sh + src/lib/glyphs.sh + src/lib/glyphs.sh +" PROGS=" -src/util/shmk.sh -src/util/hbar.sh -src/util/shtests.sh -src/util/parseconf.sh -src/tools/xichroot.sh -src/tools/default-jvm.sh + src/util/shmk/shmk.sh + src/util/shtests.sh + src/util/parseconf.sh + src/tools/xichroot.sh + src/tools/default-jvm.sh + src/util/hbar.sh " -#prog_hbar () { - #cp src/lib/colors.h ${DIST} - #${CC} -I${DIST} -o ${DIST}/hbar src/util/hbar.c -#} +lib_colors () { + sh src/tools/generate_colors.sh "$DIST" "src/tools/colors.list" +} check_shtests () { ${DIST}/shtests test/parseconf.sh diff --git a/shmk.shmk b/shmk.shmk index 4bcce48..ea05056 100755 --- a/shmk.shmk +++ b/shmk.shmk @@ -3,9 +3,14 @@ # shmk file to build shmk itself LIBS=" -src/lib/colors.sh + src/lib/libhbar.sh " PROGS=" -src/util/shmk.sh + src/util/shmk/shmk.sh " + + +lib_colors () { + sh src/tools/generate_colors.sh "$DIST" "src/tools/colors.list" +} diff --git a/src/lib/colors.h b/src/lib/colors.h deleted file mode 100644 index e7bc26d..0000000 --- a/src/lib/colors.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * colors.h - * - * list of ansi color codes - * provided by xiutils - * - */ - -#define RESET "" -#define BOLD "" -#define BLACK "" -#define RED "" -#define GREEN "" -#define YELLOW "" -#define BLUE "" -#define MAGENTA "" -#define CYAN "" -#define WHITE "" -#define DEFAULT "" -#define BG_BLACK "" -#define BG_RED "" -#define BG_GREEN "" -#define BG_YELLOW "" -#define BG_BLUE "" -#define BG_MAGENTA "" -#define BG_CYAN "" -#define BG_WHITE "" -#define BG_DEFAULT "" -#define LIGHT_BLACK "" -#define LIGHT_RED "" -#define LIGHT_GREEN "" -#define LIGHT_YELLOW "" -#define LIGHT_BLUE "" -#define LIGHT_MAGENTA "" -#define LIGHT_CYAN "" -#define LIGHT_WHITE "" -#define LIGHT_DEFAULT "" -#define BOLDBLACK "" -#define BOLDRED "" -#define BOLDGREEN "" -#define BOLDYELLOW "" -#define BOLDBLUE "" -#define BOLDMAGENTA "" -#define BOLDCYAN "" -#define BOLDWHITE "" diff --git a/src/lib/colors.list b/src/lib/colors.list deleted file mode 100644 index 0829a63..0000000 --- a/src/lib/colors.list +++ /dev/null @@ -1,42 +0,0 @@ -RESET "\033[0m" - -BOLD "\033[0;1m" - -BLACK "\033[0;30m" -RED "\033[0;31m" -GREEN "\033[0;32m" -YELLOW "\033[0;33m" -BLUE "\033[0;34m" -MAGENTA "\033[0;35m" -CYAN "\033[0;36m" -WHITE "\033[0;37m" -DEFAULT "\033[0;39m" - -BG_BLACK "\033[40m" -BG_RED "\033[41m" -BG_GREEN "\033[42m" -BG_YELLOW "\033[43m" -BG_BLUE "\033[44m" -BG_MAGENTA "\033[45m" -BG_CYAN "\033[46m" -BG_WHITE "\033[47m" -BG_DEFAULT "\033[49m" - -LIGHT_BLACK "\033[0;90m" -LIGHT_RED "\033[0;91m" -LIGHT_GREEN "\033[0;92m" -LIGHT_YELLOW "\033[0;93m" -LIGHT_BLUE "\033[0;94m" -LIGHT_MAGENTA "\033[0;95m" -LIGHT_CYAN "\033[0;96m" -LIGHT_WHITE "\033[0;97m" -LIGHT_DEFAULT "\033[0;99m" - -BOLDBLACK "\033[1;30m" -BOLDRED "\033[1;31m" -BOLDGREEN "\033[1;32m" -BOLDYELLOW "\033[1;33m" -BOLDBLUE "\033[1;34m" -BOLDMAGENTA "\033[1;35m" -BOLDCYAN "\033[1;36m" -BOLDWHITE "\033[1;37m" diff --git a/src/lib/colors.sh b/src/lib/colors.sh deleted file mode 100644 index 8e5de11..0000000 --- a/src/lib/colors.sh +++ /dev/null @@ -1,44 +0,0 @@ -# -# colors.h -# -# list of ansi color codes -# provided by xiutils -# - -export RESET=$(printf "") -export BOLD=$(printf "") -export BLACK=$(printf "") -export RED=$(printf "") -export GREEN=$(printf "") -export YELLOW=$(printf "") -export BLUE=$(printf "") -export MAGENTA=$(printf "") -export CYAN=$(printf "") -export WHITE=$(printf "") -export DEFAULT=$(printf "") -export BG_BLACK=$(printf "") -export BG_RED=$(printf "") -export BG_GREEN=$(printf "") -export BG_YELLOW=$(printf "") -export BG_BLUE=$(printf "") -export BG_MAGENTA=$(printf "") -export BG_CYAN=$(printf "") -export BG_WHITE=$(printf "") -export BG_DEFAULT=$(printf "") -export LIGHT_BLACK=$(printf "") -export LIGHT_RED=$(printf "") -export LIGHT_GREEN=$(printf "") -export LIGHT_YELLOW=$(printf "") -export LIGHT_BLUE=$(printf "") -export LIGHT_MAGENTA=$(printf "") -export LIGHT_CYAN=$(printf "") -export LIGHT_WHITE=$(printf "") -export LIGHT_DEFAULT=$(printf "") -export BOLDBLACK=$(printf "") -export BOLDRED=$(printf "") -export BOLDGREEN=$(printf "") -export BOLDYELLOW=$(printf "") -export BOLDBLUE=$(printf "") -export BOLDMAGENTA=$(printf "") -export BOLDCYAN=$(printf "") -export BOLDWHITE=$(printf "") diff --git a/src/lib/generate_colors.sh b/src/lib/generate_colors.sh deleted file mode 100644 index 6e01d58..0000000 --- a/src/lib/generate_colors.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -DIST=$1 - -headerfile=${DIST}/colors.h -shlib=${DIST}/colors.sh - -cat > $shlib << "EOF" -# -# colors.h -# -# list of ansi color codes -# provided by xiutils -# - -EOF - -cat > $headerfile << "EOF" -/* - * colors.h - * - * list of ansi color codes - * provided by xiutils - * - */ - -EOF - -append_header() { - echo "#define $1 $2" >> $headerfile -} - -append_sh() { - printf 'export %s=$(printf %s)\n' $1 $2 >> $shlib -} - -while IFS= read -r line; do - echo "$line" | grep -q "." || continue - name=$(echo $line | awk '{ print $1 }') - code=$(echo $line | awk '{ print $2 }') - - append_header $name $code - append_sh $name $code - -done < "$2" diff --git a/src/lib/libhbar.sh b/src/lib/libhbar.sh new file mode 100644 index 0000000..4489f09 --- /dev/null +++ b/src/lib/libhbar.sh @@ -0,0 +1,116 @@ +#!/bin/mksh -U +#include colors +#include xilib + +ADVANCE=" " + +move_up () { + [ ! "$1" = "0" ] && + printf "\033[%dA" "$1" "0" +} + +move_down () { + [ ! "$1" = "0" ] && + printf "\033[%dB" "$1" +} + +count_string () { + local c t + $human && { + c=$(format_bytes $completed) + t=$(format_bytes $total) + } || { + c=$1 + t=$2 + } + printf "[%s/%s]" $c $t +} + +hbar () { + local width terminate human text color reset unit line count + width=$(tput cols) + color="$BLACK$BG_WHITE" + reset="$WHITE$BG_DEFAULT" + terminate=false + human=false + # dont write any real characters ya + notext=false + line=0 + + while getopts "T:c:r:u:l:hnt" opt; do + case "$opt" in + T) + text="$OPTARG" + ;; + c) + color="$OPTARG" + ;; + r) + reset="$OPTARG" + ;; + u) + unit="$OPTARG" + ;; + t) + terminate=true + ;; + h) + human=true + ;; + l) + line="$OPTARG" + ;; + n) + notext=true + esac + done + + shift $((OPTIND-1)) + + [ "$#" -lt 2 ] && { + return 1 + } + + completed="$1" + total="$2" + + move_up $line + + count=$(count_string $completed $total) + #printf "\r$text" + printf "$RESET\r" + printf "$color" + reset_at=0 + + [ "$total" -gt "0" ] && reset_at=$(((completed*width)/total)) + + _x=0 + while [ "$_x" -lt "$width" ]; do + + if $notext; then + [ "$_x" -gt "$reset_at" ] && printf "$reset" || printf "$color" + printf "%s" "$ADVANCE" + else + [ "$_x" = "$reset_at" ] && printf "$reset" + if [ "${#text}" -gt 0 ]; then + printf "%s" "${text%%${text#?}}" + text="${text#?}" + else + if [ "$((width-${#count}))" = "$_x" ]; then + printf "%s" "${count%%${count#?}}" + + count="${count#?}" + else + printf "$ADVANCE" + fi + fi + fi + _x=$((_x+1)) + done + + move_down $line + + printf "$RESET" + $terminate && printf "\n" +} + diff --git a/src/tools/colors.list b/src/tools/colors.list new file mode 100644 index 0000000..0829a63 --- /dev/null +++ b/src/tools/colors.list @@ -0,0 +1,42 @@ +RESET "\033[0m" + +BOLD "\033[0;1m" + +BLACK "\033[0;30m" +RED "\033[0;31m" +GREEN "\033[0;32m" +YELLOW "\033[0;33m" +BLUE "\033[0;34m" +MAGENTA "\033[0;35m" +CYAN "\033[0;36m" +WHITE "\033[0;37m" +DEFAULT "\033[0;39m" + +BG_BLACK "\033[40m" +BG_RED "\033[41m" +BG_GREEN "\033[42m" +BG_YELLOW "\033[43m" +BG_BLUE "\033[44m" +BG_MAGENTA "\033[45m" +BG_CYAN "\033[46m" +BG_WHITE "\033[47m" +BG_DEFAULT "\033[49m" + +LIGHT_BLACK "\033[0;90m" +LIGHT_RED "\033[0;91m" +LIGHT_GREEN "\033[0;92m" +LIGHT_YELLOW "\033[0;93m" +LIGHT_BLUE "\033[0;94m" +LIGHT_MAGENTA "\033[0;95m" +LIGHT_CYAN "\033[0;96m" +LIGHT_WHITE "\033[0;97m" +LIGHT_DEFAULT "\033[0;99m" + +BOLDBLACK "\033[1;30m" +BOLDRED "\033[1;31m" +BOLDGREEN "\033[1;32m" +BOLDYELLOW "\033[1;33m" +BOLDBLUE "\033[1;34m" +BOLDMAGENTA "\033[1;35m" +BOLDCYAN "\033[1;36m" +BOLDWHITE "\033[1;37m" diff --git a/src/tools/generate_colors.sh b/src/tools/generate_colors.sh new file mode 100644 index 0000000..4d1e08f --- /dev/null +++ b/src/tools/generate_colors.sh @@ -0,0 +1,45 @@ +#!/bin/bash +DIST=$1 +mkdir -p ${DIST} + +headerfile=${DIST}/colors.h +shlib=${DIST}/colors.sh + +cat > $shlib << "EOF" +# +# colors.h +# +# list of ansi color codes +# provided by xiutils +# + +EOF + +cat > $headerfile << "EOF" +/* + * colors.h + * + * list of ansi color codes + * provided by xiutils + * + */ + +EOF + +append_header() { + echo "#define $1 $2" >> $headerfile +} + +append_sh() { + printf 'export %s=$(printf %s)\n' $1 $2 >> $shlib +} + +while IFS= read -r line; do + echo "$line" | grep -q "." || continue + name=$(echo $line | awk '{ print $1 }') + code=$(echo $line | awk '{ print $2 }') + + append_header $name $code + append_sh $name $code + +done < "$2" diff --git a/src/util/hbar.sh b/src/util/hbar.sh index 9518e66..230ff5d 100755 --- a/src/util/hbar.sh +++ b/src/util/hbar.sh @@ -1,108 +1,6 @@ #!/bin/mksh -U -#include colors -#include xilib -move_up () { - [ ! "$1" = "0" ] && - printf "\033[%dA" "$1" "0" -} - -move_down () { - [ ! "$1" = "0" ] && - printf "\033[%dB" "$1" -} - -count_string () { - local c t - $human && { - c=$(format_bytes $completed) - t=$(format_bytes $total) - } || { - c=$1 - t=$2 - } - printf "[%s/%s]" $c $t -} - -hbar () { - local width terminate human text color reset unit line count - width=$(tput cols) - color="$BLACK$BG_WHITE" - reset="$WHITE$BG_DEFAULT" - terminate=false - human=false - line=0 - - while getopts "T:c:r:u:l:ht" opt; do - case "$opt" in - T) - text="$OPTARG" - ;; - c) - color="$OPTARG" - ;; - r) - reset="$OPTARG" - ;; - u) - unit="$OPTARG" - ;; - t) - terminate=true - ;; - h) - human=true - ;; - l) - line="$OPTARG" - ;; - esac - done - - shift $((OPTIND-1)) - - [ "$#" -lt 2 ] && { - return 1 - } - - completed="$1" - total="$2" - - move_up $line - - count=$(count_string $completed $total) - #printf "\r$text" - printf "$RESET\r" - printf "$color" - - reset_at=0 - [ "$total" -gt "0" ] && reset_at=$(((completed*width)/total)) - - i=0 - while [ "$i" -lt "$width" ]; do - [ "$i" = "$reset_at" ] && printf "$reset" - - [ "${#text}" -gt 0 ] && { - printf "%s" "${text%%${text#?}}" - text="${text#?}" - } || { - [ "$((width-${#count}))" = "$i" ] && { - printf "%s" "${count%%${count#?}}" - count="${count#?}" - } || { - printf " " - } - } - i=$((i+1)) - done - - move_down $line - - printf "$RESET" - $terminate && printf "\n" - - exit 0 -} +#include libhbar [ "$#" -eq "0" ] && { printf "$RESET\n" diff --git a/src/util/parseconf.sh b/src/util/parseconf.sh index d215a99..17cb0ce 100644 --- a/src/util/parseconf.sh +++ b/src/util/parseconf.sh @@ -1,37 +1,37 @@ #!/bin/sh usage () { - printf "Usage $0 " - echo << "EOF" +printf "Usage $0 " +echo << "EOF" OPTIONS... [FILTER] Print the parsed config file filtering by the keys Arguments: - -f file read configuration from a file, uses /dev/sdtin otherwise - -v only print values - -c n print the last [n] +-f file read configuration from a file, uses /dev/sdtin otherwise +-v only print values +-c n print the last [n] EOF } # parse a single config file line # parse_line() { - [ "$#" = 0 ] && return - - local line="$@" - local key=$1 - - shift - local value="$@" - value=${value%#*} - - case $key in - "include") - cat $value | parse - return - ;; - "]") - IFS=. +[ "$#" = 0 ] && return + +local line="$@" +local key=$1 + +shift +local value="$@" +value=${value%#*} + +case $key in + "include") + cat $value | parse + return + ;; + "]") + IFS=. set -- $list list="${*%${!#}}" IFS=" " diff --git a/src/util/shmk.README b/src/util/shmk.README deleted file mode 100644 index a359fbc..0000000 --- a/src/util/shmk.README +++ /dev/null @@ -1,121 +0,0 @@ -# shmk - -shmk is a simple utility to build complicated shell projects - -## Usage - -### single file - -shmk can be invoked on a single sh file to "build" it: - -```sh -$ shmk myprog.sh file_output.sh -``` - -### in a wider project - -shmk can also serve as a "make" tool, building libraries and executables, running tests (checks) and installing your project to a path. - -see [shmk project](#shmk project) for more info - -## Directives - -Shmk will take each file and parse it before making an output. Most of the file will remain unchanged, however some directives will be parsed: - - -### `#include file` - -Will include a file 'in place'. Will not include a file more than once within the output - -The first file with the given name will be used. The search path by default follows this order: - -``` -./ -$DIST/ -/usr/lib/ -/usr/local/lib/ -/usr/share/shmk/ -``` - -Using the `-I` option will prepend a file to this list. If no `.sh` extension is given, both the `filenanme` and the `filename.sh` will be checked - -# shmk project - -A shmk project is typically built using a `build.shmk` file - -An example build shmk file could like this (chek this project's shmk file for more examples): - -```sh -#!/usr/bin/env shmk - -LIBS=" - src/lib/mylibrary.sh - src/lib/second_library.sh -" - -PROGS=" - src/myutil.sh -" - -CHECKS=" - tests/test_myutil.sh -" -``` - -By making this file executable, shmk will be invoked via its shebang and it will parse this file as a project fille. - -The difference between a lib and a prog (library and program) is functionally only in where the files get installed. Programs should be intsalled to a `bin/` directory and are inteded to be run directly. Libraries, even though they are functionally shell programs, are intended to be included by other shell programs and provide variables and functions that are to be used. - -## stages - -When shmk builds a project, it is able to execute the following steps: (by default in the given order) - -- **clean** - - cleans the project files - - removes outputted files, executables etc -- **build** - - builds all libraries and programs using shmk -- **check** - - run all the available tests -- **install** - - install binaries and libraries - - by default will install progs to `/usr/local/bin/` and libraries to `/usr/local/lib/` - - `/usr/local/` can be changed using the env var `$PREFIX` - - instead of installing to system, package maintainers may use `$DESTDIR` to choose where to install shmk -- **uninstall** - - this stage is not run by default - - opposite of install, will follow the same install path and remove any libraries or programs it would have installed - -## custom build stages - -If desired, a custom build stage can be created: - -```sh - -prog_mycprog () { - gcc -o ${DIST}/myprog src/myprog.c -} - -``` - -Any function prefixed with `prog_` or `lib_` will be treated as an extra program or library to be built, and said function will be run after handling all of the files mentioned in `LIBS` and `PROGS` variables. This will not override anything from these lists. -These - -As per the example, this can be useful for incorporating non-shmk build stages. As shmk is interpreted like a normal shell file, the syntax should be the same as a shell allowing for extensible configuration of build stages. - -The prefix `check_` can also be used for custom check stages. These will not override the exsiting checks - -### Checks and tests - -A test in shmk is called a `check` (since test is already a shell command). The testing framework is rather rudimentary, and currenty can only be used with custom `check_` prefixed fucntions in the shmk build. Alternatively binaries from the `$CHECKS` variable will also be run. These are not to be confused with other build stages where the programs are never executed themselves: checks are run as-is. - -Checks are run consecutively until either all checks reutrn 0 (success) or a single check returns 1. - -This feature is intended to be used with the `shtests` tool. - - -## Syntax and formatting - -shmk is intended to be as portable as possible, following exclusively POSIX shell syntax. This means that unlike in bash or csh, there is no formal structure for lists, instead whitespace separated strings are used. New lines or spaces both work, however for the sake of simplicity, newlines are prefered. The "standard" shmk syntax for a list is as follows - -` diff --git a/src/util/shmk.sh b/src/util/shmk.sh deleted file mode 100755 index b4c040d..0000000 --- a/src/util/shmk.sh +++ /dev/null @@ -1,257 +0,0 @@ -#!/bin/sh -# -# A tool to build a single executable from a collection of shell scripts - -#include colors - -PREFIX=${PREFIX:-/usr} - -usage () { - cat << EOF -${BLUE}Available Options: - -EOF -} - -# find a file in the search tree -# -# _find_file filename -# -_find_file () { - for p in $search_path; do - for f in $p/$1.sh $p/$1; do - $verbose \ - && printf "${LIGHT_BLACK}checking: $f\n" 1>&2 - - [ -f "$f" ] && { - echo "$f" - return 0 - } - done - done - return 1 -} - -# parse the lines of a file -# -# _parse_lines < file -# -_parse_lines () { - - # keep a running log of which files we've already included - included="" - - # go through the lines - while IFS= read -r line; do - case "$line" in - "#include "*) - # find the file - file="$(_find_file ${line#\#include})" - - # if we have already included this file, do not parse it - case "$included" in - *"$file"*) ;; - *) - cat $file | _parse_lines - included="$included $file" - esac - ;; - - "#>"*) - eval ${line#'#>'} - ;; - "#!"*) - printf "%s\n" "$line" - ;; - "#"*);; - *) - printf "%s\n" "$line" - ;; - esac - done -} - -# 'build' a shell file too an output -# goes through the file without running it and interprets all shmk commands -# -# build_shmk file [output] -# -build_shmk () { - [ -f "$1" ] || return 1 - [ ! -z "$2" ] && output="$2" - [ -z "$output" ] && output=$(basename $1) - output=./${output%.*} - - $clean && { - rm -f $output - exit - } - - $verbose && echo "building $1 to $output" - - [ ! -d "${output%/*}" ] && mkdir -p "${output%/*}" - - cat $1 \ - | _parse_lines > ${output} && - [ ! -z ${entry_function} ] && echo "$entry_function" >> ${output} - chmod +x ${output} -} - -# take a .shmk file and build it -# -interpret_shmk () { - . $1 - local cmdlist="" - - DIST="./dist" - PROGS="$PROGS $(sed -rn "s/^prog_(.*)\s*\(\)\s*\{/\1/p" $1)" - LIBS="$LIBS $(sed -rn "s/^lib_(.*)\s*\(\)\s*\{/\1/p" $1)" - CHECKS="$CHECKS $(sed -rn "s/^check_(.*)\s*\(\)\s*\{/\1/p" $1)" - - shift - [ -z "$1" ] && set -- clean build check install - while [ ! -z "$1" ]; do - case "$1" in - install) - for prog in $PROGS; do - prog=$(basename $prog) - prog="${prog%.*}" - cmdlist="$cmdlist - install -Dm755 $DIST/$prog ${DESTDIR}/${PREFIX}/bin/$prog #Install program $prog" - done - for lib in $LIBS; do - lib=$(basename $lib) - lib="${lib%.*}" - cmdlist="$cmdlist - install -Dm755 $DIST/$lib ${DESTDIR}/${PREFIX}/lib/$lib.sh #Install library $lib" - done - ;; - uninstall) - for prog in $PROGS; do - prog=$(basename $prog) - prog="${prog%.*}" - cmdlist="$cmdlist - rm ${DESTDIR}/${PREFIX}/bin/$prog #Uninstall program $prog" - done - for lib in $LIBS; do - lib=$(basename $lib) - lib="${lib%.*}" - cmdlist="$cmdlist - rm $DIST/$lib ${DESTDIR}/${PREFIX}/lib/$lib.sh #Uninstall library $lib" - done - ;; - clean) - [ -d "$DIST" ] && cmdlist="$cmdlist - rm -r $DIST #Clean" - ;; - check) - for check in $CHECKS; do - command -v check_$check > /dev/null 2>&1 && cmdlist="$cmdlist - check_$check #Check $check" - done - ;; - *) # build all programs - search_path="$DIST $search_path" - - for lib in $LIBS; do - name=$(basename $lib) - build_cmd=lib_$lib - command -v $build_cmd > /dev/null 2>&1 || { - build_cmd="build_shmk $lib $DIST/$name" - } - cmdlist="$cmdlist - $build_cmd #Build library $name" - done - - for prog in $PROGS; do - name=$(basename $prog) - build_cmd=prog_$prog - command -v $build_cmd > /dev/null 2>&1 || { - build_cmd="build_shmk $prog $DIST/$name" - } - cmdlist="$cmdlist - $build_cmd #Build program $name" - done - - # build all libs - ;; - esac - shift - done - - local out len i - $verbose && out=/dev/stdout || out=/dev/null - len=$(($(echo "$cmdlist" | wc -l)-1)) - i=-1 - echo "$cmdlist" | while read -r cmd; do - i=$((i+1)) - printf "${LIGHT_BLACK}[${LIGHT_BLUE}%s${LIGHT_BLACK}/${LIGHT_BLUE}%s${LIGHT_BLACK}] ${LIGHT_WHITE}%s${RESET}%s" "$i" "$len" "${cmd#*#}" "$($verbose && printf "\n" || printf "\r")" - ${cmd%#*} 2>&1 > $out || { - printf "\n${RED}Error $?\n" - exit 1 - } - done - printf "\n" -} - -search_path=". -$DIST/ -/usr/lib/ -/usr/local/lib/ -/usr/share/shmk/ -" - -verbose=false -clean=false - -# test shmk was invoked on a file if so put the filename at the end because it will break getopts -# this is a sketchy workaround because the shebang will always put the -# filename of the project file as the first arg, so this way we can -# happily introduce more arguments -[ -f "$1" ] && { - set -- $* $1 -} - -while getopts ":e:I:o:chv" opt; do - case "${opt}" in - e) - entry_function="$OPTARG" - ;; - o) - output="$OPTARG" - ;; - c) - clean=true - ;; - I) - search_path="$OPTARG - $search_path" - ;; - v) - verbose=true - ;; - h) - usage && exit 0 - ;; - esac -done - -shift $((OPTIND-1)) - -[ -z $1 ] && { - exit 1 -} - -echo "$0 $*" - -[ -f "$1" ] && shebang="$(head -1 $1)" - -case "$shebang" in - "#!"*"shmk"*) - interpret_shmk $@ - ;; - *) - build_shmk $@ - ;; -esac - diff --git a/src/util/shmk/shmk.README b/src/util/shmk/shmk.README new file mode 100644 index 0000000..43671ac --- /dev/null +++ b/src/util/shmk/shmk.README @@ -0,0 +1,129 @@ +# shmk + +shmk is a simple utility to build complicated shell projects + +## Usage + +### single file + +shmk can be invoked on a single sh file to "build" it: + +```sh +$ shmk myprog.sh file_output.sh +``` + +### in a wider project + +shmk can also serve as a "make" tool, building libraries and executables, running tests (checks) and installing your project to a path. + +see [shmk project](#shmk project) for more info + +## Directives + +Shmk will take each file and parse it before making an output. Most of the file will remain unchanged, however some directives will be parsed: + + +### `#include file` + +Will include a file 'in place'. Will not include a file more than once within the output + +The first file with the given name will be used. The search path by default follows this order: + +``` +./ +$DIST/ +/usr/lib/ +/usr/local/lib/ +/usr/share/shmk/ +``` + +Using the `-I` option will prepend a file to this list. If no `.sh` extension is given, both the `filenanme` and the `filename.sh` will be checked + +# shmk project + +A shmk project is typically built using a `build.shmk` file + +An example build shmk file could like this (chek this project's shmk file for more examples): + +```sh +#!/usr/bin/env shmk + +LIBS=" + src/lib/mylibrary.sh + src/lib/second_library.sh +" + +PROGS=" + src/myutil.sh +" + +CHECKS=" + tests/test_myutil.sh +" +``` + +By making this file executable, shmk will be invoked via its shebang and it will parse this file as a project fille. + +The difference between a lib and a prog (library and program) is functionally only in where the files get installed. Programs should be intsalled to a `bin/` directory and are inteded to be run directly. Libraries, even though they are functionally shell programs, are intended to be included by other shell programs and provide variables and functions that are to be used. + +## stages + +When shmk builds a project, it is able to execute the following steps: (by default in the given order) + +- **clean** + - cleans the project files + - removes outputted files, executables etc +- **build** + - builds all libraries and programs using shmk +- **check** + - run all the available tests +- **install** + - install binaries and libraries + - by default will install progs to `/usr/local/bin/` and libraries to `/usr/local/lib/` + - `/usr/local/` can be changed using the env var `$PREFIX` + - instead of installing to system, package maintainers may use `$DESTDIR` to choose where to install shmk +- **uninstall** + - this stage is not run by default + - opposite of install, will follow the same install path and remove any libraries or programs it would have installed + +## custom build stages + +If desired, a custom build stage can be created: + +```sh + +prog_mycprog () { + gcc -o ${DIST}/myprog src/myprog.c +} + +``` + +Any function prefixed with `prog_` or `lib_` will be treated as an extra program or library to be built, and said function will be run after handling all of the files mentioned in `LIBS` and `PROGS` variables. This will not override anything from these lists. +These + +As per the example, this can be useful for incorporating non-shmk build stages. As shmk is interpreted like a normal shell file, the syntax should be the same as a shell allowing for extensible configuration of build stages. + +The prefix `check_` can also be used for custom check stages. These will not override the exsiting checks + +### Checks and tests + +A test in shmk is called a `check` (since test is already a shell command). The testing framework is rather rudimentary, and currenty can only be used with custom `check_` prefixed fucntions in the shmk build. Alternatively binaries from the `$CHECKS` variable will also be run. These are not to be confused with other build stages where the programs are never executed themselves: checks are run as-is. + +Checks are run consecutively until either all checks reutrn 0 (success) or a single check returns 1. + +This feature is intended to be used with the `shtests` tool. + + +## Syntax and formatting + + +### shell features + +shmk is intended to be as portable as possible, following exclusively POSIX shell syntax. This means that unlike in bash or csh, there is no formal structure for lists, instead whitespace separated strings are used. New lines or spaces both work, however for the sake of simplicity, newlines are prefered. + +### env vars + +shmk exposes a few different environment variables in the build environment (ie to be used in custom build stages): + +- `${DIST}` - temporary "out" directory where libraries and binaries are placed. +- `${PREFIX}` - where things will be installed diff --git a/src/util/shmk/shmk.sh b/src/util/shmk/shmk.sh new file mode 100755 index 0000000..be5f00b --- /dev/null +++ b/src/util/shmk/shmk.sh @@ -0,0 +1,283 @@ +#!/bin/sh +# +# A tool to build a single executable from a collection of shell scripts + +#include colors +#include libhbar + +PREFIX=${PREFIX:-/usr} + +usage () { + cat << EOF +${BLUE}Available Options: + +EOF +} + +# find a file in the search tree +# +# _find_file filename +# +_find_file () { + for p in $search_path; do + for f in $p/$1.sh $p/$1; do + $verbose \ + && printf "${LIGHT_BLACK}checking: $f\n" 1>&2 + + [ -f "$f" ] && { + $verbose \ + && printf "${LIGHT_BLACK}found: $f for $1\n" 1>&2 + echo "$f" + return 0 + } + done + done + return 1 +} + +# parse the lines of a file +# +# _parse_lines < file +# +_parse_lines () { + + # keep a running log of which files we've already included + included="" + + # go through the lines + while IFS= read -r line; do + case "$line" in + "#include "*) + # find the file + file="$(_find_file ${line#\#include})" + + # if we have already included this file, do not parse it + case "$included" in + *"$file"*) + $verbose \ + && printf "${LIGHT_BLACK}already included $file, won't include twice\n" 1>&2 + ;; + *) + cat $file | _parse_lines + included="$included $file" + esac + ;; + + "#>"*) + eval ${line#'#>'} + ;; + "#!"*) + printf "%s\n" "$line" + ;; + "#"*);; + *) + printf "%s\n" "$line" + ;; + esac + done +} + +# 'build' a shell file too an output +# goes through the file without running it and interprets all shmk commands +# +# build_shmk file [output] +# +build_shmk () { + [ -f "$1" ] || return 1 + [ ! -z "$2" ] && output="$2" + [ -z "$output" ] && output=$(basename $1) + output=./${output%.*} + + $clean && { + rm -f $output + exit + } + + $verbose && echo "building $1 to $output" + + [ ! -d "${output%/*}" ] && mkdir -p "${output%/*}" + + cat $1 \ + | _parse_lines > ${output} && + [ ! -z ${entry_function} ] && echo "$entry_function" >> ${output} + chmod +x ${output} +} + +# take a .shmk file and build it +# +interpret_shmk () { + . $1 + local cmdlist="" + + ## TODO override if already set + DIST="./dist" + BUILDS="$(sed -rn "s/^build_(.*)\s*\(\)\s*\{/\1/p" $1) $BUILDS" + PROGS="$(sed -rn "s/^prog_(.*)\s*\(\)\s*\{/\1/p" $1) $PROGS " + LIBS="$(sed -rn "s/^lib_(.*)\s*\(\)\s*\{/\1/p" $1) $LIBS" + CHECKS="$(sed -rn "s/^check_(.*)\s*\(\)\s*\{/\1/p" $1) $CHECKS" + + shift + [ -z "$1" ] && set -- clean build check + while [ ! -z "$1" ]; do + case "$1" in + # install programs and libraries to system + # + install) + for prog in $PROGS; do + prog=$(basename $prog) + prog="${prog%.*}" + cmdlist="$cmdlist + install -Dm755 $DIST/$prog ${DESTDIR}/${PREFIX}/bin/$prog #Install program $prog" + done + for lib in $LIBS; do + lib=$(basename $lib) + lib="${lib%.*}" + cmdlist="$cmdlist + install -Dm755 $DIST/$lib ${DESTDIR}/${PREFIX}/lib/$lib.sh #Install library $lib" + done + ;; + + # install programs and libraries to system + # + uninstall) + for prog in $PROGS; do + prog=$(basename $prog) + prog="${prog%.*}" + cmdlist="$cmdlist + rm ${DESTDIR}/${PREFIX}/bin/$prog #Uninstall program $prog" + done + for lib in $LIBS; do + lib=$(basename $lib) + lib="${lib%.*}" + cmdlist="$cmdlist + rm $DIST/$lib ${DESTDIR}/${PREFIX}/lib/$lib.sh #Uninstall library $lib" + done + ;; + + clean) + [ -d "$DIST" ] && cmdlist="$cmdlist + rm -r $DIST #Clean" + ;; + + check) + for check in $CHECKS; do + command -v check_$check > /dev/null 2>&1 && cmdlist="$cmdlist + check_$check #Check $check" + done + ;; + + *) # build all programs + search_path="$DIST $search_path" + + for lib in $LIBS; do + name=$(basename $lib) + build_cmd=lib_$lib + command -v $build_cmd > /dev/null 2>&1 || { + build_cmd="build_shmk $lib $DIST/$name" + } + cmdlist="$cmdlist + $build_cmd #Build library $name" + done + + for prog in $PROGS; do + name=$(basename $prog) + build_cmd=prog_$prog + command -v $build_cmd > /dev/null 2>&1 || { + build_cmd="build_shmk $prog $DIST/$name" + } + cmdlist="$cmdlist + $build_cmd #Build program $name" + done + + # build all libs + ;; + esac + shift + done + + local out len i + $verbose && out=/dev/stdout || out=/dev/null + len=$(($(echo "$cmdlist" | wc -l)-1)) + i=-1 + echo "$cmdlist" | while read -r cmd; do + i=$((i+1)) + outstring="$(printf "${LIGHT_BLACK}[${LIGHT_BLUE}%s${LIGHT_BLACK}/${LIGHT_BLUE}%s${LIGHT_BLACK}] ${LIGHT_WHITE}%s" \ + "$i" "$len" "${cmd#*#}")" + + printf "\r%s\r" "${outstring}" #"$($verbose && printf "\n\n" || printf "\n")" + if ! $verbose && command -v hbar > /dev/null 2>&1; then + printf "\n" + hbar -l 1 -r "${RESET}" -c "${BG_BLUE}" -n "$i" "$len" + fi + + ${cmd%#*} 2>&1 > $out || { + printf "\n${RED}Error $?\n" + exit 1 + } + done + printf "\n" +} + +search_path=". +$DIST/ +/usr/lib/ +/usr/local/lib/ +/usr/share/shmk/ +" + +verbose=false +clean=false + +# test shmk was invoked on a file if so put the filename at the end because it will break getopts +# this is a sketchy workaround because the shebang will always put the +# filename of the project file as the first arg, so this way we can +# happily introduce more arguments +[ -f "$1" ] && { + set -- $* $1 +} + +while getopts ":e:I:o:chv" opt; do + case "${opt}" in + e) + entry_function="$OPTARG" + ;; + o) + output="$OPTARG" + ;; + c) + clean=true + ;; + I) + search_path=" + $OPTARG + $search_path + " + ;; + v) + verbose=true + ;; + h) + usage && exit 0 + ;; + esac +done + +shift $((OPTIND-1)) + +[ -z $1 ] && { + exit 1 +} + +echo "$0 $*" + +[ -f "$1" ] && shebang="$(head -1 $1)" + +case "$shebang" in + "#!"*"shmk"*) + interpret_shmk $@ + ;; + *) + build_shmk $@ + ;; +esac + diff --git a/test/hbar.sh b/test/hbar.sh index c01ee25..31b3a83 100755 --- a/test/hbar.sh +++ b/test/hbar.sh @@ -4,12 +4,6 @@ HBAR=./dist/hbar UNIT="mb" MAX=100 -TEXT="✓ Привет World Привет World Привет World Привет World Привет World Привет World " -for x in $(seq $MAX); do - ${HBAR} -T "${TEXT}" -u ${UNIT} $x $MAX - #sleep 0.01 -done - sleep 1 clear echo Doing hello there bar @@ -18,8 +12,7 @@ sleep 1 TEXT="Hello there" for x in $(seq $MAX); do - ${HBAR} -T "${TEXT}" -u ${UNIT} $x $MAX - #sleep 0.01 + time ${HBAR} -l 2 -T "${TEXT}" -u ${UNIT} $x $MAX done ${HBAR} -t -T "${TEXT}" -u ${UNIT} $x $MAX @@ -50,3 +43,13 @@ for x in $(seq 0 991 $MAX); do ${HBAR} -h -T "${TEXT}" $((x*1000000)) $((MAX*1000000)) done ${HBAR} -ht -T "${TEXT}" $x $MAX + +sleep 1 +clear +echo testing unicode +sleep 1 +TEXT="✓ Привет World Привет World Привет World Привет World Привет World Привет World " +for x in $(seq $MAX); do + ${HBAR} -T "${TEXT}" -u ${UNIT} $x $MAX + #sleep 0.01 +done -- cgit v1.2.3