diff --git a/examples/is/README.md b/examples/is/README.md new file mode 100644 index 00000000..29faf47d --- /dev/null +++ b/examples/is/README.md @@ -0,0 +1,8 @@ +Is Example +================================================== + +This example was generated with: + + $ bashly init + $ bashly add is + $ bashly generate diff --git a/examples/is/exist b/examples/is/exist new file mode 100644 index 00000000..ea07df3c --- /dev/null +++ b/examples/is/exist @@ -0,0 +1,291 @@ +#!/usr/bin/env bash +# This script was generated by bashly (https://github.com/DannyBen/bashly) +# Modifying it manually is not recommended + +# :command.root_command +root_command() { + # :src/root_command.sh + file=${args[filename]} + + if is existing "$file" ; then + echo "File exists" + + if is writeable "$file" ; then + echo "... and is writeable" + else + echo "... and is NOT writeable" + fi + + else + echo "File does not exist" + + fi +} + +# :command.version_command +version_command() { + echo "$version" +} + +# :command.usage +exist_usage() { + if [[ -n $long_usage ]]; then + printf "exist - Sample application that uses the is.sh functions\n" + echo + else + printf "exist - Sample application that uses the is.sh functions\n" + echo + fi + + printf "Usage:\n" + printf " exist FILENAME\n" + printf " exist --help | -h\n" + printf " exist --version | -v\n" + echo + + if [[ -n $long_usage ]]; then + printf "Options:\n" + # :command.usage_fixed_flags + echo " --help, -h" + printf " Show this help\n" + echo + echo " --version, -v" + printf " Show version number\n" + echo + + # :command.usage_args + printf "Arguments:\n" + + # :argument.usage + echo " FILENAME" + printf " The file to check if exists\n" + echo + + # :command.usage_examples + printf "Examples:\n" + + printf " exist somefile\n" + echo + + fi +} + +# :command.inspect_args +inspect_args() { + echo args: + for k in "${!args[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done +} + +# :command.user_lib +# :src/lib/is.sh +# is.sh copyright notice: +# Copyright (c) 2016 Józef Sokołowski +# Distributed under the MIT License +# For most current version checkout repository: +# https://github.com/qzb/is.sh +is() { + if [ "$1" == "--help" ]; then + cat << EOF +Conditions: + is equal VALUE_A VALUE_B + is matching REGEXP VALUE + is substring VALUE_A VALUE_B + is empty VALUE + is number VALUE + is gt NUMBER_A NUMBER_B + is lt NUMBER_A NUMBER_B + is ge NUMBER_A NUMBER_B + is le NUMBER_A NUMBER_B + is file PATH + is dir PATH + is link PATH + is existing PATH + is readable PATH + is writeable PATH + is executable PATH + is available COMMAND + is older PATH_A PATH_B + is newer PATH_A PATH_B + is true VALUE + is false VALUE + +Negation: + is not equal VALUE_A VALUE_B + +Optional article: + is not a number VALUE + is an existing PATH + is the file PATH +EOF + exit + fi + + if [ "$1" == "--version" ]; then + echo "is.sh 1.1.0" + exit + fi + + local condition="$1" + local value_a="$2" + local value_b="$3" + + if [ "$condition" == "not" ]; then + shift 1 + ! is "${@}" + return $? + fi + + if [ "$condition" == "a" ] || [ "$condition" == "an" ] || [ "$condition" == "the" ]; then + shift 1 + is "${@}" + return $? + fi + + case "$condition" in + file) + [ -f "$value_a" ]; return $?;; + dir|directory) + [ -d "$value_a" ]; return $?;; + link|symlink) + [ -L "$value_a" ]; return $?;; + existent|existing|exist|exists) + [ -e "$value_a" ]; return $?;; + readable) + [ -r "$value_a" ]; return $?;; + writeable) + [ -w "$value_a" ]; return $?;; + executable) + [ -x "$value_a" ]; return $?;; + available|installed) + which "$value_a"; return $?;; + empty) + [ -z "$value_a" ]; return $?;; + number) + echo "$value_a" | grep -E '^[0-9]+(\.[0-9]+)?$'; return $?;; + older) + [ "$value_a" -ot "$value_b" ]; return $?;; + newer) + [ "$value_a" -nt "$value_b" ]; return $?;; + gt) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a > $value_b ? 0 : 1}"; return $?;; + lt) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a < $value_b ? 0 : 1}"; return $?;; + ge) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a >= $value_b ? 0 : 1}"; return $?;; + le) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a <= $value_b ? 0 : 1}"; return $?;; + eq|equal) + [ "$value_a" = "$value_b" ] && return 0; + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a == $value_b ? 0 : 1}"; return $?;; + match|matching) + echo "$value_b" | grep -xE "$value_a"; return $?;; + substr|substring) + echo "$value_b" | grep -F "$value_a"; return $?;; + true) + [ "$value_a" == true ] || [ "$value_a" == 0 ]; return $?;; + false) + [ "$value_a" != true ] && [ "$value_a" != 0 ]; return $?;; + esac > /dev/null + + return 1 +} + +# :command.command_functions + +# :command.parse_requirements +parse_requirements() { + # :command.fixed_flag_filter + case "$1" in + --version | -v ) + version_command + exit + ;; + + --help | -h ) + long_usage=yes + exist_usage + exit 1 + ;; + + esac + # :command.environment_variables_filter + # :command.dependencies_filter + # :command.command_filter + action="root" + # :command.required_args_filter + if [[ $1 && $1 != -* ]]; then + args[filename]=$1 + shift + else + printf "missing required argument: FILENAME\nusage: exist FILENAME\n" + exit 1 + fi + # :command.required_flags_filter + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + + -* ) + printf "invalid option: %s\n" "$key" + exit 1 + ;; + + * ) + # :command.parse_requirements_case + if [[ ! ${args[filename]} ]]; then + args[filename]=$1 + shift + else + printf "invalid argument: %s\n" "$key" + exit 1 + fi + ;; + + esac + done + # :command.default_assignments +} + +# :command.initialize +initialize() { + version="0.1.0" + long_usage='' + set -e + + # :src/initialize.sh + # Code here runs inside the initialize() function + # Use it for anything that you need to run before any other function, like + # setting environment vairables: + # CONFIG_FILE=settings.ini + # + # Feel free to empty (but not delete) this file. +} + +# :command.run +run() { + declare -A args + parse_requirements "$@" + + if [[ ${args[--version]} ]]; then + version_command + elif [[ ${args[--help]} ]]; then + long_usage=yes + exist_usage + elif [[ $action == "root" ]]; then + root_command + fi +} + +initialize +run "$@" diff --git a/examples/is/src/bashly.yml b/examples/is/src/bashly.yml new file mode 100644 index 00000000..cfd72fd0 --- /dev/null +++ b/examples/is/src/bashly.yml @@ -0,0 +1,11 @@ +name: exist +help: Sample application that uses the is.sh functions +version: 0.1.0 + +args: +- name: filename + required: true + help: The file to check if exists + +examples: +- exist somefile diff --git a/examples/is/src/initialize.sh b/examples/is/src/initialize.sh new file mode 100644 index 00000000..f2dbc52c --- /dev/null +++ b/examples/is/src/initialize.sh @@ -0,0 +1,6 @@ +# Code here runs inside the initialize() function +# Use it for anything that you need to run before any other function, like +# setting environment vairables: +# CONFIG_FILE=settings.ini +# +# Feel free to empty (but not delete) this file. diff --git a/examples/is/src/lib/is.sh b/examples/is/src/lib/is.sh new file mode 100644 index 00000000..6589f6a7 --- /dev/null +++ b/examples/is/src/lib/is.sh @@ -0,0 +1,121 @@ +# is.sh copyright notice: +# Copyright (c) 2016 Józef Sokołowski +# Distributed under the MIT License +# For most current version checkout repository: +# https://github.com/qzb/is.sh +is() { + if [ "$1" == "--help" ]; then + cat << EOF +Conditions: + is equal VALUE_A VALUE_B + is matching REGEXP VALUE + is substring VALUE_A VALUE_B + is empty VALUE + is number VALUE + is gt NUMBER_A NUMBER_B + is lt NUMBER_A NUMBER_B + is ge NUMBER_A NUMBER_B + is le NUMBER_A NUMBER_B + is file PATH + is dir PATH + is link PATH + is existing PATH + is readable PATH + is writeable PATH + is executable PATH + is available COMMAND + is older PATH_A PATH_B + is newer PATH_A PATH_B + is true VALUE + is false VALUE + +Negation: + is not equal VALUE_A VALUE_B + +Optional article: + is not a number VALUE + is an existing PATH + is the file PATH +EOF + exit + fi + + if [ "$1" == "--version" ]; then + echo "is.sh 1.1.0" + exit + fi + + local condition="$1" + local value_a="$2" + local value_b="$3" + + if [ "$condition" == "not" ]; then + shift 1 + ! is "${@}" + return $? + fi + + if [ "$condition" == "a" ] || [ "$condition" == "an" ] || [ "$condition" == "the" ]; then + shift 1 + is "${@}" + return $? + fi + + case "$condition" in + file) + [ -f "$value_a" ]; return $?;; + dir|directory) + [ -d "$value_a" ]; return $?;; + link|symlink) + [ -L "$value_a" ]; return $?;; + existent|existing|exist|exists) + [ -e "$value_a" ]; return $?;; + readable) + [ -r "$value_a" ]; return $?;; + writeable) + [ -w "$value_a" ]; return $?;; + executable) + [ -x "$value_a" ]; return $?;; + available|installed) + which "$value_a"; return $?;; + empty) + [ -z "$value_a" ]; return $?;; + number) + echo "$value_a" | grep -E '^[0-9]+(\.[0-9]+)?$'; return $?;; + older) + [ "$value_a" -ot "$value_b" ]; return $?;; + newer) + [ "$value_a" -nt "$value_b" ]; return $?;; + gt) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a > $value_b ? 0 : 1}"; return $?;; + lt) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a < $value_b ? 0 : 1}"; return $?;; + ge) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a >= $value_b ? 0 : 1}"; return $?;; + le) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a <= $value_b ? 0 : 1}"; return $?;; + eq|equal) + [ "$value_a" = "$value_b" ] && return 0; + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a == $value_b ? 0 : 1}"; return $?;; + match|matching) + echo "$value_b" | grep -xE "$value_a"; return $?;; + substr|substring) + echo "$value_b" | grep -F "$value_a"; return $?;; + true) + [ "$value_a" == true ] || [ "$value_a" == 0 ]; return $?;; + false) + [ "$value_a" != true ] && [ "$value_a" != 0 ]; return $?;; + esac > /dev/null + + return 1 +} diff --git a/examples/is/src/root_command.sh b/examples/is/src/root_command.sh new file mode 100644 index 00000000..16b15d81 --- /dev/null +++ b/examples/is/src/root_command.sh @@ -0,0 +1,15 @@ +file=${args[filename]} + +if is existing "$file" ; then + echo "File exists" + + if is writeable "$file" ; then + echo "... and is writeable" + else + echo "... and is NOT writeable" + fi + +else + echo "File does not exist" + +fi diff --git a/examples/is/test.sh b/examples/is/test.sh new file mode 100644 index 00000000..def5808b --- /dev/null +++ b/examples/is/test.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -x + +bashly generate + +./exist -h +./exist no/such.file +./exist README.md + diff --git a/lib/bashly/commands/add.rb b/lib/bashly/commands/add.rb index 409e8e2f..f9f6af07 100644 --- a/lib/bashly/commands/add.rb +++ b/lib/bashly/commands/add.rb @@ -8,6 +8,7 @@ class Add < Base usage "bashly add config [--force]" usage "bashly add colors [--force]" usage "bashly add yaml [--force]" + usage "bashly add is [--force]" usage "bashly add (-h|--help)" option "-f --force", "Overwrite existing files" @@ -17,6 +18,7 @@ class Add < Base command "config", "Add standard functions for handling INI files to the lib directory." command "colors", "Add standard functions for printing colorful and formatted text to the lib directory." command "yaml", "Add standard functions for reading YAML files to the lib directory." + command "is", "Add human readable conditions (is.sh)." environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]" @@ -40,7 +42,12 @@ def yaml_command safe_copy_lib "yaml.sh" end + def is_command + safe_copy_lib "is.sh" + end + private + def safe_copy_lib(libfile) safe_copy asset("templates/lib/#{libfile}"), "#{Settings.source_dir}/lib/#{libfile}" end diff --git a/lib/bashly/templates/lib/is.sh b/lib/bashly/templates/lib/is.sh new file mode 100644 index 00000000..6589f6a7 --- /dev/null +++ b/lib/bashly/templates/lib/is.sh @@ -0,0 +1,121 @@ +# is.sh copyright notice: +# Copyright (c) 2016 Józef Sokołowski +# Distributed under the MIT License +# For most current version checkout repository: +# https://github.com/qzb/is.sh +is() { + if [ "$1" == "--help" ]; then + cat << EOF +Conditions: + is equal VALUE_A VALUE_B + is matching REGEXP VALUE + is substring VALUE_A VALUE_B + is empty VALUE + is number VALUE + is gt NUMBER_A NUMBER_B + is lt NUMBER_A NUMBER_B + is ge NUMBER_A NUMBER_B + is le NUMBER_A NUMBER_B + is file PATH + is dir PATH + is link PATH + is existing PATH + is readable PATH + is writeable PATH + is executable PATH + is available COMMAND + is older PATH_A PATH_B + is newer PATH_A PATH_B + is true VALUE + is false VALUE + +Negation: + is not equal VALUE_A VALUE_B + +Optional article: + is not a number VALUE + is an existing PATH + is the file PATH +EOF + exit + fi + + if [ "$1" == "--version" ]; then + echo "is.sh 1.1.0" + exit + fi + + local condition="$1" + local value_a="$2" + local value_b="$3" + + if [ "$condition" == "not" ]; then + shift 1 + ! is "${@}" + return $? + fi + + if [ "$condition" == "a" ] || [ "$condition" == "an" ] || [ "$condition" == "the" ]; then + shift 1 + is "${@}" + return $? + fi + + case "$condition" in + file) + [ -f "$value_a" ]; return $?;; + dir|directory) + [ -d "$value_a" ]; return $?;; + link|symlink) + [ -L "$value_a" ]; return $?;; + existent|existing|exist|exists) + [ -e "$value_a" ]; return $?;; + readable) + [ -r "$value_a" ]; return $?;; + writeable) + [ -w "$value_a" ]; return $?;; + executable) + [ -x "$value_a" ]; return $?;; + available|installed) + which "$value_a"; return $?;; + empty) + [ -z "$value_a" ]; return $?;; + number) + echo "$value_a" | grep -E '^[0-9]+(\.[0-9]+)?$'; return $?;; + older) + [ "$value_a" -ot "$value_b" ]; return $?;; + newer) + [ "$value_a" -nt "$value_b" ]; return $?;; + gt) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a > $value_b ? 0 : 1}"; return $?;; + lt) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a < $value_b ? 0 : 1}"; return $?;; + ge) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a >= $value_b ? 0 : 1}"; return $?;; + le) + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a <= $value_b ? 0 : 1}"; return $?;; + eq|equal) + [ "$value_a" = "$value_b" ] && return 0; + is not a number "$value_a" && return 1; + is not a number "$value_b" && return 1; + awk "BEGIN {exit $value_a == $value_b ? 0 : 1}"; return $?;; + match|matching) + echo "$value_b" | grep -xE "$value_a"; return $?;; + substr|substring) + echo "$value_b" | grep -F "$value_a"; return $?;; + true) + [ "$value_a" == true ] || [ "$value_a" == 0 ]; return $?;; + false) + [ "$value_a" != true ] && [ "$value_a" != 0 ]; return $?;; + esac > /dev/null + + return 1 +} diff --git a/spec/approvals/cli/add/help b/spec/approvals/cli/add/help index 559bcf58..bec0d885 100644 --- a/spec/approvals/cli/add/help +++ b/spec/approvals/cli/add/help @@ -6,6 +6,7 @@ Usage: bashly add config [--force] bashly add colors [--force] bashly add yaml [--force] + bashly add is [--force] bashly add (-h|--help) Commands: @@ -27,6 +28,9 @@ Commands: yaml Add standard functions for reading YAML files to the lib directory. + is + Add human readable conditions (is.sh). + Options: -f --force Overwrite existing files diff --git a/spec/approvals/cli/add/is b/spec/approvals/cli/add/is new file mode 100644 index 00000000..150e77f7 --- /dev/null +++ b/spec/approvals/cli/add/is @@ -0,0 +1 @@ +created spec/tmp/src/lib/is.sh diff --git a/spec/approvals/cli/generate/usage b/spec/approvals/cli/generate/usage index b80fc35d..5f8d4c62 100644 --- a/spec/approvals/cli/generate/usage +++ b/spec/approvals/cli/generate/usage @@ -4,4 +4,5 @@ Usage: bashly add config [--force] bashly add colors [--force] bashly add yaml [--force] + bashly add is [--force] bashly add (-h|--help) diff --git a/spec/approvals/examples/is b/spec/approvals/examples/is new file mode 100644 index 00000000..47c49683 --- /dev/null +++ b/spec/approvals/examples/is @@ -0,0 +1,33 @@ ++ bashly generate +creating user files in src +skipped src/initialize.sh (exists) +skipped src/root_command.sh (exists) +created ./exist +run ./exist --help to test your bash script ++ ./exist -h +exist - Sample application that uses the is.sh functions + +Usage: + exist FILENAME + exist --help | -h + exist --version | -v + +Options: + --help, -h + Show this help + + --version, -v + Show version number + +Arguments: + FILENAME + The file to check if exists + +Examples: + exist somefile + ++ ./exist no/such.file +File does not exist ++ ./exist README.md +File exists +... and is writeable diff --git a/spec/bashly/commands/add_spec.rb b/spec/bashly/commands/add_spec.rb index c9ae8ad9..1acb15e5 100644 --- a/spec/bashly/commands/add_spec.rb +++ b/spec/bashly/commands/add_spec.rb @@ -99,4 +99,17 @@ end end + context "with is command" do + let(:lib_file) { "#{source_dir}/lib/is.sh" } + + before do + reset_tmp_dir create_src: true + end + + it "copies the is.sh lib file to the user space" do + expect { subject.run %w[add is] }.to output_fixture('cli/add/is') + expect(File).to exist(lib_file) + end + end + end