diff --git a/README.md b/README.md index c67ae8c..f5cf548 100644 --- a/README.md +++ b/README.md @@ -52,14 +52,8 @@ For concrete examples see [glue-example](https://github.com/eankeen/glue-example See [details.md](./docs/details.md) -- Fix broken links in docs -- Other todos scattered throughout -- On warnings in which there is something about with two files, print the two files adjacently vertical +TODOS + +- autocomplete - greadlink readlink -f check -- TODO: autocomplete -- make requireConfig work with folders -- rename requireConfig to useConfig -- search for requireActions in 'actions'? -- cd to GLUE_WD? -- list dependencies in regular file instead of having requireCOnfig annotatinos -- log paths show relative paths +- list dependencies in regular file instead of having requireConfig annotatinos? diff --git a/docs/api.md b/docs/api.md index 0312352..e725c9c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -26,11 +26,11 @@ Certain directories have an intrinsic meaning and should be used as such. All di ### `commands` -The location Glue looks to execute a particular task. Glue also scans this directory to find `requireAction()` annotations +The location Glue looks to execute a particular task. Glue also scans this directory to find `useAction()` annotations ### `actions` -The location a script in 'commands' looks to source to perform a more fine-grained action (ex. run `eslint`). Glue also scans this directorie to find `requireConfig()` annotations +The location a script in 'commands' looks to source to perform a more fine-grained action (ex. run `eslint`). Glue also scans this directorie to find `useConfig()` annotations ### `configs` @@ -51,5 +51,3 @@ Any persistent state that your scripts may emit. Use of this directory is _highl # Miscellaneous - Most script-writing-gotchia's are due to the fact that the script file can reside in either `commands/auto/script.sh` or `commands/script.sh` - -- Note that for example, when `commands/auto/script.sh` runs, `GLUE_ACTIONS_DIR` may be different on first pass. This is due to the eval of `GLUE_ACTIONS_BOOTSTRAP`. So, only use these variables in functions diff --git a/docs/details.md b/docs/details.md index cb19bf4..97d8dfc 100644 --- a/docs/details.md +++ b/docs/details.md @@ -2,7 +2,7 @@ For every project you want to use Glue with, a `.glue` directory is used to contain everything related to Glue: configuration, scripts, and script output. -There are two types of scripts: 'command' and 'action'. 'command' scripts can simply be though of the execution of a particular task relating to a programming language. For example: `Build Go library` or `Deploy Node server`. Each 'command' script calls out to an 'action' script that does the actual command. For example `go build .` or `ansible-playbook playbook.yml`. Two categories of scripts exist to increase composability of 'actions' across languages (or even possibly domains!). Lastly, 'command' and 'action' scripts are contains in the `.glue/commands` and `.glue/actions` directories, respectively +There are two types of scripts: 'command' and 'action'. 'command' scripts can simply be though of the execution of a particular task relating to a programming language. For example: `Build Go library` or `Deploy Node server`. Each 'command' script calls out to an 'action' script that does the actual command. For example a script containaing `go build .` or `ansible-playbook playbook.yml`. Two categories of scripts exist to increase composability of 'actions' across languages (or even possibly domains!). Lastly, 'command' and 'action' scripts are contained in the `.glue/commands` and `.glue/actions` directories, respectively The following explain the different parts of Glue, in no particular order @@ -18,13 +18,13 @@ It's important to understand the execution flow of Glue when using the `cmd` sub 1. When first invoking Glue, it looks for an `actions.bootstrap.*` and a `commands.bootstraps.*` file in the Glue store, setting their contents to `$GLUE_ACTIONS_BOOTSTRAP` and `$GLUE_COMMANDS_BOOTSTRAP`, respectively -2. If a task is specified through the `cmd` subcommand, it looks for that task in the `.glue/commands`, then `.glue/commands/auto` directories of your project. If none are found, it displays an error. See [Finding Scripts](## Finding Scripts) for more details +2. If a task is specified through the `cmd` subcommand, it looks for that task in the `.glue/commands`, then `.glue/commands/auto` directories of your project. If none are found, it displays an error. See [Scripts](#scripts) for more details 3. Assuming the task is found, the file is executed, and the `$GLUE_ACTIONS_BOOTSTRAP`, `$GLUE_COMMANDS_BOOTSTRAP`, and `$GLUE_IS_AUTO` variables are passed into the environment. The rest of the execution is now dependent on the user's Glue store -## About Scripts +## Scripts -Glue's process of finding and executing scripts makes script-writing easy to extend, modify, and compose. This functionality is only for scripts in the `commands (not `actions`) directory. +Glue's process of finding and executing scripts makes script-writing easy to extend, modify, and compose. This functionality is only for scripts in the `commands` (not `actions`) directory. A meta task is a combination of a Project Type, a Task, and a When. Not all components need to be present and not all compositional variations are valid @@ -40,7 +40,7 @@ glue cmd NodeJS_Server.build-before From this meta task, Glue searches for a script (ex. NodeJS_Server.build-before.sh`) in `.glue/commands/auto`. However, if one by the same name is found in `.glue/commands`, it uses that one instead -As you can see, script names are nearly identical to the meta task. The following lists all variations and their semantics +As you can see, script names are nearly identical to the meta task. The following code blocks lists all variations and their semantics ```sh # Only task @@ -58,12 +58,10 @@ glue cmd NodeJS_Server-before # Invalid because it doesn't make sense # And projectType, task, when -glue cmd NodeJS_Server-before -glue cmd NodeJS_Server-only +glue cmd NodeJS_Server.ci-before +glue cmd NodeJS_Server.ci-only ``` -To know which scripts are executed in which order, see [Finding Scripts](##finding-scripts) - ### Project Type ```sh diff --git a/glue.sh b/glue.sh index 5f82855..33bded0 100755 --- a/glue.sh +++ b/glue.sh @@ -42,6 +42,10 @@ main() { shift doSync "$@" ;; + list) + sync + doList "$@" + ;; cmd) shift doCmd "$@" diff --git a/lib/do.sh b/lib/do.sh index 0f00f6c..abab477 100644 --- a/lib/do.sh +++ b/lib/do.sh @@ -37,7 +37,7 @@ doSync() { # ACTIONS, CONFIGS # local arg - for arg in 'commands:requireAction:actions' 'actions:requireConfig:configs'; do + for arg in 'commands:useAction:actions' 'actions:useConfig:configs'; do local searchDir="${arg%%:*}" local annotationName="${arg#*:}"; annotationName="${annotationName%:*}" local fileDir="${arg##*:}" @@ -52,7 +52,7 @@ doSync() { # 'file' is a relative path for file in "${files[@]}"; do - if [ -f "$GLUE_STORE/$fileDir/$file" ]; then + if [ -e "$GLUE_STORE/$fileDir/$file" ]; then case "$file" in */*) # If file contains a directory path in it @@ -60,15 +60,39 @@ doSync() { cp "$GLUE_STORE/$fileDir/$file" "$GLUE_WD/.glue/$fileDir/auto/${file%/*}" ;; *) - cp "$GLUE_STORE/$fileDir/$file" "$GLUE_WD/.glue/$fileDir/auto/" + cp -r "$GLUE_STORE/$fileDir/$file" "$GLUE_WD/.glue/$fileDir/auto/" esac else - log.warn "Corresponding file for annotation'$annotationName()' not found in directory '$GLUE_STORE/$fileDir'. Skipping'" + log.warn "Corresponding file for annotation '$annotationName($file)' not found in directory '$GLUE_STORE/$fileDir'. Skipping'" fi done done } +doList() { + local -A tasks=() + + shopt -s dotglob + shopt -s nullglob + + local filePath + for filePath in "$GLUE_WD"/.glue/commands/* "$GLUE_WD"/.glue/commands/auto/*; do + local file="${filePath##*/}" + local task="${file%%.*}" + + # Do not include files without a projectType + if [ "$file" = "$task" ]; then + continue + fi + + tasks+=(["$task"]='') + done + + for task in "${!tasks[@]}"; do + echo "$task" + done +} + doCmd() { [[ -z $1 ]] && die 'No meta task passed' @@ -85,6 +109,7 @@ doCmd() { cat "$actionsBootstrapFile" )" || die "Could not get contents of '$actionsBootstrapFile'" + # -------------------- Parse Meta task ------------------- # get.task "$1" local task="$REPLY" @@ -94,20 +119,18 @@ doCmd() { get.when "$1" local when="$REPLY" + # --------------------- Sanity check --------------------- # + if [ -z "$task" ]; then + die "Specifying a 'task is required" + fi + if [[ -v DEBUG ]]; then echo "task: $task" echo "projectType: $projectType" echo "when: $when" fi - if [ -z "$task" ]; then - die "Specifying a 'task is required" - fi - - local commandDir="$GLUE_WD/.glue/commands" - local hasRan=no - - # specify projectTypes + # calculate 'projectType's to run local -a projectTypes=() if [ -n "$projectType" ]; then projectTypes=("$projectType" "") @@ -119,7 +142,7 @@ doCmd() { projectTypes=("${GLUE_USING[@]}" "") fi - # specify whens + # calculate 'when's to run local -a whens=() if [ -n "$when" ]; then # a blank 'when' represents a file like 'build-go.sh' compared to 'build-go-before.sh' @@ -133,6 +156,9 @@ doCmd() { whens=("-before" "" "-after") fi + # run and execute files in order + local commandDir="$GLUE_WD/.glue/commands" + local hasRan=no for projectType in "${projectTypes[@]}"; do for when in "${whens[@]}"; do helper.get_executable_file "$commandDir/${projectType}.${task}${when}" @@ -153,7 +179,9 @@ doCmd() { done if [[ $hasRan == no ]]; then - printf -v msg "%s\n -> %s\n -> %s\nExiting" "Task '$task' did not match any files in the following directories" ".glue/commands/auto" ".glue/commands" - log.error "$msg" + log.error "Task '$task' did match any files" + echo " -> Is the task contained in '.glue/commands/auto' or '.glue/commands'" >&2 + echo " -> Was a task like 'build', 'ci', etc. actually specified?" >&2 + exit 1 fi } diff --git a/lib/helper.sh b/lib/helper.sh index 23eeb8a..6bf81ee 100644 --- a/lib/helper.sh +++ b/lib/helper.sh @@ -19,7 +19,9 @@ helper.get_executable_file() { firstFileMatch= for aFileMatch in "$file".*?; do if [[ $hasRanFile = yes ]]; then - log.warn "Both '$aFileMatch' and '$firstFileMatch' should not exist" + log.warn "Two files match the same pattern" + echo " -> '$aFileMatch" >&2 + echo " -> '$firstFileMatch'" >&2 break fi diff --git a/lib/util/log.sh b/lib/util/log.sh index 20c6574..4931a03 100644 --- a/lib/util/log.sh +++ b/lib/util/log.sh @@ -10,14 +10,29 @@ die() { exit 1 } +# Print info log.info() { - printf "\033[0;34m%s\033[0m\n" "Info: $*" + if [[ -v NO_COLOR || $TERM = dumb ]]; then + printf "%s\n" "Info: $*" + else + printf "\033[0;34m%s\033[0m\n" "Info: $*" + fi } +# Print warning log.warn() { - printf "\033[1;33m%s\033[0m\n" "Warn: $*" >&2 + if [[ -v NO_COLOR || $TERM = dumb ]]; then + printf "%s\n" "Warn: $*" + else + printf "\033[1;33m%s\033[0m\n" "Warn: $*" >&2 + fi } +# Print error log.error() { - printf "\033[0;31m%s\033[0m\n" "Error: $*" >&2 + if [[ -v NO_COLOR || $TERM = dumb ]]; then + printf "%s\n" "Error: $*" + else + printf "\033[0;31m%s\033[0m\n" "Error: $*" >&2 + fi } diff --git a/lib/util/util.sh b/lib/util/util.sh index 3018e32..6341e6f 100644 --- a/lib/util/util.sh +++ b/lib/util/util.sh @@ -39,8 +39,7 @@ util.show_help() { } util.show_version() { - # TODO cat <<-EOF - VERSION + 0.3 EOF }