diff --git a/Bakefile b/Bakefile new file mode 100644 index 0000000..bfee87a --- /dev/null +++ b/Bakefile @@ -0,0 +1,24 @@ + + +install() { # Install bake: required prefix as argument + # Prefix is ~/.local/ or /usr/local/ + # The executable is put under PREFIX/bin/ and should be in PATH + if [[ -z "$1" ]]; then + echo "Prefix required, e.g. ~/.local/ or /usr/local/" + exit 1 + fi + + bakepath="$1/bin/bake" + bakepath=${bakepath//\/\//\/} + mkdir -p "$prefix"/bin + cp -v bake "$bakepath" + chmod -v 755 "$bakepath" + if [[ ! "$( which bake )" = "$bakepath" ]]; then + echo "'bake' in path seems to be different than installed version. PATH finds: " + which bake + fi + echo "Add autocompletion: + + echo \"if [[ -x $bakepath ]]; then . <( $bakepath __autocomplete__ ); fi\" >> ~/.bashrc + " +} diff --git a/README.md b/README.md index e7df774..53471f3 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,62 @@ Bash make, with very lightweight approach -This is very similar to https://github.com/rumkin/bake project, but -slightly simpler implementation. No additional folders or files, +This is very similar to https://github.com/rumkin/bake project, but +slightly simpler implementation. No additional folders or files, just a Bakefile with functions required. -If you want to use the interactive menu, install https://github.com/p-gen/smenu +If you want to use the interactive menu, install https://github.com/p-gen/smenu `smenu` is installable via apt-get in debian/ubuntu based distros. +# Install + +Run the command: `./bake` in this folder. Installation prefix is required +to install, for example: `./bake install ~/.local/` +Finally, insert the autocomplete as explained in installer. + +Note: you can also just take the `bake` executable, and place in PATH. + +# Usage + +Create a Bakefile: + +``` +help() { # This help. Note the exact function declaration + docs format. + _menu +} + +default() { # Default function will be run if present, and no target passed + # Extra help to be read with -h + echo "I'm running!" +} + +build() { # Build by project + echo building.. + echo I can get arguments: "$1" + echo I have global variables: "$somevar" +} + +deploy() { # Deploy project + build # I dont have similar dependency tree as GNU make, all commands are run + if [[ ! -f somebinary.bin ]]; then + # if build produces a file, we can check and not run building again.. + build + fi + echo Now deploying... + _subcommand +} + +_subcommand() { + # if function starts with _, it's not listed as target, and + # can be called by other functions + echo subcommand called somewhere +} + +echo foo # NOTE: Bakefile gets sourced when read! +somevar=value + + +``` + +- run `bake` to get list of targets. +- run `bake build argument` to launch target with arguments diff --git a/bake b/bake new file mode 100755 index 0000000..24bfff9 --- /dev/null +++ b/bake @@ -0,0 +1,120 @@ +#!/bin/bash +## BASH-MAKE ========================================================== +## Utility to mimick some of GNU Make behavior, but run in a single +## bash shell. This executable can be used as the Bakefile, too, +## by adding the functions under this text, and setting +## STANDALONE=true +## +# Target functions MUST be of format: "name() { # Menu description" +set -e +# In standalone mode, this script also contains targets +STANDALONE=false + +if [[ $STANDALONE = true ]]; then + BAKEFILE=$0 +else + if [[ "$1" = "__autocomplete__" ]]; then + echo '_bake_complete() { + local curr_arg + curr_arg=${COMP_WORDS[COMP_CWORD]} + if [[ $COMP_CWORD -eq 1 ]]; then + COMPREPLY=( $(compgen -W "$( bake __list__ ) -h -l -m" -- $curr_arg ) ); + fi + } + complete -F _bake_complete bake + # Run me as: source <( bake __autocomplete__ ) + ' + exit + fi + for BAKEFILE in Bakefile bakefile /dev/null; do + if [[ -f ./$BAKEFILE ]]; then + BAKEFILE=./$BAKEFILE + break + fi + done +fi + +_flines() { cat "$BAKEFILE" | \ + grep -E '^([^_][a-zA-Z0-9_\.]+)\(\) {.*'; } +_menu() { _flines | while read line; do + if [[ "$line" =~ ([a-zA-Z0-9_\.]+)\(\).\{[\ #]*(.*) ]]; then + printf "\e[33m%+20s \e[36m [ %-50s ]\e[0m\n" \ + "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" + fi + done; } +_itemhelp() { funfound=0; cat "$BAKEFILE" | while read line; do + if [[ "$line" =~ ^("$1")\(\).\{[\ #]*(.*) ]]; then + printf "\e[33m%s \e[36m %s\e[0m\n" \ + "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" + funfound=1 + else + if [[ $funfound -eq 1 ]]; then + if [[ "$line" =~ ^[\ ]*#[\ ](.*) ]]; then + printf "\e[36m%s\e[0m\n" \ + "${BASH_REMATCH[1]}" + else + funfound=0 + fi + fi + fi + done; } +_smenu() { while true; do + selection=$( _flines | sed 's/().*//' | \ + smenu -m "Select target (q: exit)" -n 22 -t 1 -a c:2,b i:7,b m:7,bu ) + [[ -n "$selection" ]] && { _source_bakefile && "$selection"; } || { exit; } + done; exit; } +_commands() { _flines | sed 's/().*//' | while read line; do + printf "^%s$|" "$line" + done | sed 's/.$//'; } +_source_bakefile() { + if [[ $STANDALONE = false ]]; then + if [[ ! -f "$BAKEFILE" ]]; then + echo No Bakefile present >&2 + exit 1 + fi + . "$BAKEFILE" + fi; } + +case $1 in + "__list__") _flines | sed 's/().*//'; exit ;; + "-m") _smenu; exit ;; + "-l") _menu; exit ;; + "-h") if [[ -n "$2" ]]; then _itemhelp "$2"; else cat <