From 89010fd209ac5d4331d7f6c1712bcfe9075eb1cc Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 20 Jun 2017 15:55:07 +0200 Subject: [PATCH] Improved help system. Signed-off-by: Tony Tkacik --- bin/nux-env | 16 +++--- bin/nux-runner | 116 ++++++++++++++++++++++++++++++------------ bin/nuxfs | 76 ++++++++++++++------------- bin/tdm-media | 1 - inc/dsl/nuxfs.dsl | 43 ++++++++-------- inc/dsl/nuxfs.fix.dsl | 5 +- inc/nux-base.inc.sh | 38 ++++++++------ inc/nux-runner.inc.sh | 63 ++++++++++++++++------- inc/nux.cfg.inc.sh | 8 ++- 9 files changed, 233 insertions(+), 133 deletions(-) diff --git a/bin/nux-env b/bin/nux-env index e58715e..697cedc 100755 --- a/bin/nux-env +++ b/bin/nux-env @@ -1,7 +1,8 @@ #!/usr/bin/env nux-runner -### Portable *nix environment by tonydamage +## Portable *nix environment by tonydamage -## status - Show status of nux-env installation +## status:: +## Show status of nux-env installation task.status() { echo nux-env folder: $NUX_ENV_DIR pushd $NUX_ENV_DIR > /dev/null @@ -9,7 +10,8 @@ task.status() { popd > /dev/null } -## update - pulls latest nux-env from repository. +## update:: +## pulls latest nux-env from repository. task.update() { pushd $NUX_ENV_DIR > /dev/null git stash @@ -18,17 +20,17 @@ task.update() { popd > /dev/null } -## install Install nux-env recommended binaries if not present -## +## install:: +## Install nux-env recommended binaries if not present task.install() { : } -## help.inc +## help library:: ## Displays help for specified nuxs-env library. ## -task.help.inc() { +task.help.library() { local name="$1" nux.help.comment $NUX_INC_DIR/$name.inc.sh } diff --git a/bin/nux-runner b/bin/nux-runner index 1cc350a..d3e2a74 100755 --- a/bin/nux-runner +++ b/bin/nux-runner @@ -1,9 +1,38 @@ #!/bin/bash ### -### nux-runner is environment runner for nux-env enhanced bash scripts -### and provides out of the box support for task-style scripts -### (similar in usage such as apt, git). +### *nux-runner* is wrapped bash interpreter for *nux-env* enhanced bash scripts +### and provides out of the box support for command-style scripts (similar in +### usage such as apt, git) with following features out of the box: +### +### task selection:: +### Automaticly selects correct tasks, displays help if +### task does not exists. +### logging:: +### Using *nux.log* function and changing output using +### *debug*, *trace* prefixes +### help display:: +### Automated help display when no arguments are provided. +### Uses source comments as source for help. +### +### +### # Writing nux-runner scripts +### +### *nux-runner* scripts are basicly bash scripts with some additional conventions. +### +### +### +### +### +### 1. Shebang:: +### Shebang (*#!*) at the start of file is *#!/usr/bin/env nux-runner* +### 2. Tasks:: +### Script usually does only defines functions in form task.{taskname} +### where taskname +### ## Defining a task +### +### +### ### @@ -16,39 +45,61 @@ readonly NUX_RUNNER=$NUX_RUNNER_BIN_DIR/nux-runner; nux.include nux-runner ## -## Commands provided by *nux-runner*: - - -## debug Runs specified task with debug messages enabled. -task.debug() { - nux.log.level debug - nux-runner.run "$@" -} - -## trace Runs specified task with debug & trace enabled. -task.trace() { - nux.log.level trace - nux-runner.run "$@" -} - -## help Display this help -task.help() { - echo Usage: $NC_Bold$NUX_SCRIPTNAME ${NC_No}${NC_White}\${NC_No} [\] - echo - grep -E "^\#\#\#( |$)" "$NUX_SCRIPT" | cut -d\# -f4- | cut -d" " -f2- | nux.help.shelldoc - echo - echo "Available Commands: " - nux.help.comment "$NUX_SCRIPT" - nux.help.comment "$NUX_RUNNER" - nux.exec.optional task.help.detailed -} +## Additional commands provided by *nux-runner*: +### *nux-runner* automaticly provides following tasks to any script it executes: ## + + +## debug:: [] +## Runs specified task with debug messages enabled. +task.debug() { + nux.log.level debug + nuxr.run "$@" +} + +## trace:: [] +## Runs specified task with debug & trace enabled. +task.trace() { + nux.log.level trace + nuxr.run "$@" +} + +## help:: [command] +## Display help for command or topic if specified. Otherwise displays +## documentation. +task.help() { + nuxr.task.help "$@" +} + +## config:: [type] name [value] +## Reads or writes application specific configuration option. +### +### There are 3 *types* of configuration: +### dist:: +### Distribution provided configuration. Read-only configuration. +### global:: +### Global (user-specific) provided configuration. This configuration is +### usually stored in *~/.config/{app-name}/config.yml* +### local:: +### Local configuration. +### +### The resulting application configuration is merger of these three (if available) +### with following preference (most-specific one): +### local, global, dist +### +task.config() { + nux.notimplemented task.config +} + task.() { task.help } +### +### + if [ "$NUX_RUNNER" = "$(realpath "$0")" ] then readonly NUX_SCRIPT=$1; @@ -61,12 +112,13 @@ fi if [ -n "$NUX_SCRIPT" ]; then # Determines script readonly NUX_SCRIPTNAME=$(basename $NUX_SCRIPT) - - nux-runner.run "$@" + readonly NUX_APPNAME=$(basename $NUX_SCRIPT) + nuxr.run "$@" else + echo Usage: nux-runner [script] [task] [options] echo - grep "^\#\#\# " "$NUX_RUNNER" | cut -d\# -f4- + grep "^\#\#" "$NUX_RUNNER" | sed -re "s/^#+ ?(.*)/\1/gi" | nux.help.shelldoc echo fi diff --git a/bin/nuxfs b/bin/nuxfs index 23c5dff..769de76 100755 --- a/bin/nuxfs +++ b/bin/nuxfs @@ -1,30 +1,30 @@ #!/usr/bin/env nux-runner -### # nuxfs - Filesystem layout manager -### -### *nuxfs* command uses file structure definition present in *.nuxfs* file -### to understand intented state of directory / filesystem of user. -### -### This definition is not only used to create filesystem hierarchy, checkout -### git repositories but also to verify state of filesystem afterwards. -### -### ## Example of .nuxfs file in home directory -### -### *dir* github -### *git* nux-env https://github.com/tonydamage/nux-env.git -### *git* bats https://github.com/sstephenson/bats.git -### *enddir* -### *link* .bashrc github/nux-env/bashrc -### -### This *.nuxfs* file describes simple home structure. If we execute -### **nuxfs apply** command, it will performs filesystem changes in order to -### recreate structure described in *.nuxfs* file. In case of example it is -### equivalent of executing: -### mkdir -p github -### git clone https://github.com/tonydamage/nux-env.git github/nux-env -### git clone https://github.com/sstephenson/bats.git -### ln -s github/nux-env/bashrc .bashrc -### +## # nuxfs - Filesystem layout manager +## +## *nuxfs* command uses file structure definition present in *.nuxfs* file +## to understand intented state of directory / filesystem of user. +## +## This definition is not only used to create filesystem hierarchy, checkout +## git repositories but also to verify state of filesystem afterwards. +## +## ## Example of .nuxfs file in home directory +## +## *dir* github +## *git* nux-env https://github.com/tonydamage/nux-env.git +## *git* bats https://github.com/sstephenson/bats.git +## *enddir* +## *link* .bashrc github/nux-env/bashrc +## +## This *.nuxfs* file describes simple home structure. If we execute +## **nuxfs apply** command, it will performs filesystem changes in order to +## recreate structure described in *.nuxfs* file. In case of example it is +## equivalent of executing: +## mkdir -p github +## git clone https://github.com/tonydamage/nux-env.git github/nux-env +## git clone https://github.com/sstephenson/bats.git +## ln -s github/nux-env/bashrc .bashrc +## local WORKDIR=$(pwd) local TEMPLATE_DIR=$NUX_ENV_DIR/templates @@ -37,9 +37,14 @@ nux.use nuxfs GIT_BIN=$(which git) -## check Verifies that directories and files matches the specification -## in *.nuxfs* definition -## +## Available commands: + +## check:: [] +## Verifies that directories and files matches the specification +## in *.nuxfs* definition +### +### Check is non-descructive operation, whose only output is printing out +### information task.check() { nuxfs.dsl.process "$@"; } @@ -48,22 +53,25 @@ task.describe() { nuxfs.dsl.process "$@"; } -## apply Creates missing files as specified in *.nuxfs* definition. -## **DOES NOT MODIFY** existing files breaking specification. +## apply:: [] +## Creates missing files as specified in *.nuxfs* definition. +## **DOES NOT MODIFY** existing files breaking specification. ## task.apply() { nuxfs.dsl.process "$@"; } -## fix Performs apply and tries to fix warnings and errors and files as -## specified in nuxfs definition. This operation **DOES MODIFY** -## existing files. +## fix:: [] +## Performs apply and tries to fix warnings and errors and files as +## specified in nuxfs definition. This operation **DOES MODIFY** +## existing files. ## task.fix() { nuxfs.dsl.process "$@"; } -## help.dsl Displays help for **nuxfs DSL language** +## help dsl:: +## Displays help for **nuxfs DSL language** ## task.help.dsl() { nux.help.comment "$NUX_INC_DIR/dsl/nuxfs.dsl" diff --git a/bin/tdm-media b/bin/tdm-media index c01a4ab..8ebd6dc 100755 --- a/bin/tdm-media +++ b/bin/tdm-media @@ -1,6 +1,5 @@ #!/bin/bash - type ffmpeg > /dev/null 2>&1 && FFMPEG_OR_LIBAV=ffmpeg type avconv > /dev/null 2>&1 && FFMPEG_OR_LIBAV=avconv diff --git a/inc/dsl/nuxfs.dsl b/inc/dsl/nuxfs.dsl index ad30280..026b1b1 100644 --- a/inc/dsl/nuxfs.dsl +++ b/inc/dsl/nuxfs.dsl @@ -39,6 +39,11 @@ ## unless **enddir** keyword is encountered. ## .block dir name +dir.entered() { + if nux.check.file.exists "$abs_path/.nuxfs"; then + source "$abs_path/.nuxfs" + fi +} ## link ## Defines a symbolik link with specified *name*, which points to @@ -63,8 +68,24 @@ ## .keyword exists name +## should-not-exists +## Defines a requirement for file not to be present. +## *nuxfs check*: error will be raised if file exists. +## *nuxfs fix*: files which match the match will be deleted. ## -.keyword should-not-exists +## +.keyword should-not-exists match +should-not-exists.check() { + test $(find "$(dirname "$abs_path")" -maxdepth 1 -iname "$match" | wc -l) -eq 0 +} + +should-not-exists.check.failed() { + find "$(dirname "$rel_path")" -maxdepth 1 -iname "$match" | while read f + do + nux.dsl.error $f Should not exists, but is present. + done +} + .keyword cathegorize match min delimiter cathegorize.check() { @@ -129,6 +150,7 @@ sdir() { dir "$@" enddir } + ## ## #Using custom keywords ## @@ -183,22 +205,3 @@ sdir() { .error does not exists. fi } -dir.entered() { - if nux.check.file.exists "$abs_path/.nuxfs"; then - source "$abs_path/.nuxfs" - fi -} - -should-not-exists.check() { - nux.log trace "Checking existence of $NC_White$abs_path$NC_No" - if nux.check.file.exists "$abs_path"; then - return 1 - fi - return 0 -} - -should-not-exists.check.failed() { - for f in "$rel_path"; do - nux.dsl.error $f Should not exists, but is present. - done -} diff --git a/inc/dsl/nuxfs.fix.dsl b/inc/dsl/nuxfs.fix.dsl index 7078401..c609258 100644 --- a/inc/dsl/nuxfs.fix.dsl +++ b/inc/dsl/nuxfs.fix.dsl @@ -1,10 +1,7 @@ .use-dsl nuxfs.apply should-not-exists.check.failed() { -for f in "$rel_path"; do - rm -r "$f" - nux.dsl.info $f Deleted. -done + find "$(dirname "$rel_path")" -maxdepth 1 -iname "$id" -delete } cathegorize.process.file() { diff --git a/inc/nux-base.inc.sh b/inc/nux-base.inc.sh index e1a9c4d..fec158c 100644 --- a/inc/nux-base.inc.sh +++ b/inc/nux-base.inc.sh @@ -74,7 +74,7 @@ NC_LOG_id_trace=5 ## debug ## trace ## -## nux.log +## nux.log:: ## Outputs log message to *STDERR*. LOG messages are filtered out based on ## level. Use *nux.log.level* to specify which messages should be displayed. ## @@ -91,7 +91,7 @@ function nux.log { } -## nux.log.level +## nux.log.level:: ## Sets maximum level of details to be logged. ## function nux.log.level { @@ -108,8 +108,7 @@ function nux.echo.warning { echo -e "${NC_warning}"$@" ${NC_No}"; } -## nux.use -## +## nux.use:: function nux.use { local incfile="$1.inc.sh" source "$NUX_INC_DIR/$incfile" @@ -120,7 +119,12 @@ function nux.fatal { exit -1; } -## nux.require [] +## nux.notimplemented:: +function nux.notimplemented { + nux.fatal "$@: is not imlemented." +} + +## nux.require:: [] function nux.require { local binary=$1; local package=${2:-$1} @@ -137,9 +141,10 @@ function nux.include { source "$NUX_INC_DIR/$incfile" } -## nux.check.function +## nux.check.function:: ## function nux.check.function { + nux.log trace "Checking if $1 is function." declare -f "$1" &>/dev/null && return 0 return 1 } @@ -149,7 +154,7 @@ function nux.check.exec { test -n "$(which "$binary")" } -## nux.check.file.exists +## nux.check.file.exists:: ## function nux.check.file.exists { test -e "$1" -o -h "$1"; @@ -160,7 +165,7 @@ function nux.eval { eval "$@" } -## nux.exec.optional [] +## nux.exec.optional:: [] ## function nux.exec.optional { local FUNC="$1"; shift; @@ -176,21 +181,22 @@ function nux.dirty.urlencode { function nux.help.comment { local source="$1" - grep -E "^\#\#( |$)" "$source" \ - | cut -d\# -f3- \ - | cut -d" " -f2- \ - | nux.help.shelldoc - + if nux.check.file.exists "$source" ; then + grep -E "^\#\#( |$)" "$source" \ + | cut -d\# -f3- \ + | cut -d" " -f2- \ + | nux.help.shelldoc + fi } function nux.help.shelldoc { - cat | sed -r \ + sed -r \ -e "s/^## ?(.*)/${NC_White}\1${NC_No}/gI" \ -e "s/^# ?(.*)/${NC_Bold}\1${NC_No}/gI" \ - -e "s/^ ?[a-z0-9.-_]*/${NC_Bold}&${NC_No}/gI" \ + -e "s/^([ a-z0-9.-_]*)::/${NC_Bold}\1${NC_No}/gI" \ -e "s/\*\*([^*]*)\*\*/${NC_Bold}\1${NC_No}/gI" \ -e "s/\*([^*]*)\*/${NC_White}\1${NC_No}/gI" \ - + -- } function nux.url.parse { diff --git a/inc/nux-runner.inc.sh b/inc/nux-runner.inc.sh index a8c4cba..55d23ce 100644 --- a/inc/nux-runner.inc.sh +++ b/inc/nux-runner.inc.sh @@ -1,24 +1,53 @@ - - -nux-runner.run() { +nuxr.run() { TASK=$1; shift; # Determines task - if nux.check.function task.$TASK + if [ -z "$NUX_NO_INCLUDE" ] then + nux.log debug "Including script: $NUX_SCRIPT" + source $NUX_SCRIPT; # Includes script + fi + if nux.check.function task.$TASK ; then nux.log debug "Running task: $TASK"; task.$TASK "$@" # Runs task else - if [ -z "$NUX_NO_INCLUDE" ] - then - nux.log debug "Including script: $NUX_SCRIPT" - source $NUX_SCRIPT; # Includes script - fi - if nux.check.function task.$TASK ; then - nux.log debug "Running task: $TASK"; - task.$TASK "$@" # Runs task - else - echo "$NUX_SCRIPTNAME: Unrecognized task ''$TASK' not available." - echo "Try '$NUX_SCRIPTNAME help' for more information." - exit -1 - fi + echo "$NUX_SCRIPTNAME: Unrecognized task ''$TASK' not available." + echo "Try '$NUX_SCRIPTNAME help' for more information." + exit -1 + fi +} + +function nuxr.task.help { + command="$1" + nux.log trace "Displaying help command for: $command" + if [ -z $command ] ; then + echo Usage: $NC_Bold$NUX_SCRIPTNAME ${NC_No}${NC_White}\${NC_No} [\] + nux.help.comment "$NUX_SCRIPT" + nux.help.comment "$NUX_RUNNER" + nux.exec.optional task.help.additional + elif nux.check.function "task.help.$command" ; then + shift; + task.help.$command "$@"; + else + nuxr.help.task.comment "$NUX_SCRIPT" "$command" \ + || nuxr.help.task.comment "$NUX_RUNNER" "$command" \ + || echo "Help topic $1 not found. Run $0 help to see topics." + fi +} + +function nuxr.help.task.comment { + local script="$1" + local task="$2" + + nux.log trace "Trying to figure task documentation location for $@" + doc_start=$(grep -hn -E "## +($task)::" "$script" | cut -d: -f1) + code_start=$(grep -hn -E "((function +task.$task)|(task.$task *\(\))) +{" "$script" | cut -d: -f1) + nux.log trace "doc_start" $doc_start $code_start + if [ -n "$doc_start" -a -n "$code_start" ] ; then + sed -n "$doc_start,$code_start"p "$script" \ + | grep "^\#\#" \ + | sed -re "s/^#+ ?(.*)/\1/gi" \ + | nux.help.shelldoc + return 0 + else + return -1 fi } diff --git a/inc/nux.cfg.inc.sh b/inc/nux.cfg.inc.sh index 69cf47e..3961c1d 100644 --- a/inc/nux.cfg.inc.sh +++ b/inc/nux.cfg.inc.sh @@ -10,10 +10,14 @@ function nux.cfg.include { } ## -## nux.cfg.global.path [] +## nux.cfg.global.path ## Returns global path., otherwise provides specified. ## -function nux.cfg.global.path { +function nux.cfg.global.dir { + : +} + +function nux.cfg.dist.dir : }