summaryrefslogtreecommitdiff
path: root/src/util/shmk/shmk.sh
diff options
context:
space:
mode:
authordavidovski <david@davidovski.xyz>2026-10-01 10:34:33 +0100
committerdavidovski <david@davidovski.xyz>2026-10-01 10:34:33 +0100
commiteca55e60c29440c4e2e007b54ea1a1983e965954 (patch)
treea98173c09f69864cc25395bfdab67d682434854b /src/util/shmk/shmk.sh
parentf20bd9d6369c2e1246dcdd4af26b085da99c18e0 (diff)
Add libhbar to shmkHEADmaster
Diffstat (limited to 'src/util/shmk/shmk.sh')
-rwxr-xr-xsrc/util/shmk/shmk.sh283
1 files changed, 283 insertions, 0 deletions
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
+