diff --git a/examples/variables/.gitignore b/examples/variables/.gitignore new file mode 100644 index 00000000..76ec9f59 --- /dev/null +++ b/examples/variables/.gitignore @@ -0,0 +1 @@ +cli \ No newline at end of file diff --git a/examples/variables/README.md b/examples/variables/README.md new file mode 100644 index 00000000..73f6ec17 --- /dev/null +++ b/examples/variables/README.md @@ -0,0 +1,113 @@ +# Variables Example + +Demonstrates how to define variables from the bashly.yml configuration. + +This example was generated with: + +```bash +$ bashly init +# ... now edit src/bashly.yml to match the example ... +# ... now edit src/download_command.sh to match the example ... +# ... now edit src/compress_command.sh to match the example ... +$ bashly generate +``` + + + +----- + +## `bashly.yml` + +````yaml +name: cli +help: Sample application demonstrating the use of variables +version: 0.1.0 + +# The `build_number` variable will be available globally +variables: +- name: build_number + value: 1337 + +commands: +- name: download + alias: d + help: Download a profile + + args: + - name: profile + required: true + help: Profile to download information from + + # These variables will be declared when the `download` command is executed. + # Note the use of an array value. + variables: + - name: output_folder + value: output + - name: download_sources + value: + - youtube + - instagram + +- name: compress + alias: c + help: Compress data + + # These variables will be declared when the `compress` command is executed. + # Note the use of an associative array value. + variables: + - name: zip_options + value: + pattern: "*.json" + compression_level: fast +```` + +## `src/download_command.sh` + +````bash +echo "build_number: $build_number" +echo "output_folder: $output_folder" +echo "download_sources:" +for value in "${download_sources[@]}"; do + echo "- $value" +done +```` + +## `src/compress_command.sh` + +````bash +echo "build_number: $build_number" +echo "zip_options:" +for key in "${!zip_options[@]}"; do + echo " $key: ${zip_options[$key]}" +done + +```` + + +## Output + +### `$ ./cli download something` + +````shell +build_number: 1337 +output_folder: output +download_sources: +- youtube +- instagram + + +```` + +### `$ ./cli compress` + +````shell +build_number: 1337 +zip_options: + compression_level: fast + pattern: *.json + + +```` + + + diff --git a/examples/variables/src/bashly.yml b/examples/variables/src/bashly.yml new file mode 100644 index 00000000..5cb332a2 --- /dev/null +++ b/examples/variables/src/bashly.yml @@ -0,0 +1,40 @@ +name: cli +help: Sample application demonstrating the use of variables +version: 0.1.0 + +# The `build_number` variable will be available globally +variables: +- name: build_number + value: 1337 + +commands: +- name: download + alias: d + help: Download a profile + + args: + - name: profile + required: true + help: Profile to download information from + + # These variables will be declared when the `download` command is executed. + # Note the use of an array value. + variables: + - name: output_folder + value: output + - name: download_sources + value: + - youtube + - instagram + +- name: compress + alias: c + help: Compress data + + # These variables will be declared when the `compress` command is executed. + # Note the use of an associative array value. + variables: + - name: zip_options + value: + pattern: "*.json" + compression_level: fast diff --git a/examples/variables/src/compress_command.sh b/examples/variables/src/compress_command.sh new file mode 100644 index 00000000..14cc9240 --- /dev/null +++ b/examples/variables/src/compress_command.sh @@ -0,0 +1,5 @@ +echo "build_number: $build_number" +echo "zip_options:" +for key in "${!zip_options[@]}"; do + echo " $key: ${zip_options[$key]}" +done diff --git a/examples/variables/src/download_command.sh b/examples/variables/src/download_command.sh new file mode 100644 index 00000000..c2aa5cc3 --- /dev/null +++ b/examples/variables/src/download_command.sh @@ -0,0 +1,6 @@ +echo "build_number: $build_number" +echo "output_folder: $output_folder" +echo "download_sources:" +for value in "${download_sources[@]}"; do + echo "- $value" +done \ No newline at end of file diff --git a/examples/variables/test.sh b/examples/variables/test.sh new file mode 100644 index 00000000..f8577023 --- /dev/null +++ b/examples/variables/test.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -x + +bashly generate + +### Try Me ### + +./cli download something +./cli compress diff --git a/lib/bashly/config_validator.rb b/lib/bashly/config_validator.rb index f08bab5e..5f81f824 100644 --- a/lib/bashly/config_validator.rb +++ b/lib/bashly/config_validator.rb @@ -24,7 +24,7 @@ def assert_version(key, value) def assert_catch_all(key, value) return unless value - assert [TrueClass, String, Hash].include?(value.class), + assert [TrueClass, FalseClass, String, Hash].include?(value.class), "#{key} must be a boolean, a string or a hash" assert_catch_all_hash key, value if value.is_a? Hash @@ -77,7 +77,7 @@ def assert_dependency(key, value) def assert_extensible(key, value) return unless value - assert [TrueClass, String].include?(value.class), + assert [TrueClass, FalseClass, String].include?(value.class), "#{key} must be a boolean or a string" end @@ -173,6 +173,11 @@ def assert_env_var(key, value) refute value['required'] && value['default'], "#{key} cannot have both nub`required` and nub`default`" end + def assert_var(key, value) + assert_hash key, value, keys: %i[name value] + assert_string "#{key}.name", value['name'] + end + def assert_command(key, value) assert_hash key, value, keys: Script::Command.option_keys @@ -207,6 +212,7 @@ def assert_command(key, value) assert_array "#{key}.completions", value['completions'], of: :string assert_array "#{key}.filters", value['filters'], of: :string assert_array "#{key}.environment_variables", value['environment_variables'], of: :env_var + assert_array "#{key}.variables", value['variables'], of: :var assert_uniq "#{key}.commands", value['commands'], %w[name alias] assert_uniq "#{key}.flags", value['flags'], 'long' diff --git a/lib/bashly/docs/command.yml b/lib/bashly/docs/command.yml index 42909a95..c4cfa400 100644 --- a/lib/bashly/docs/command.yml +++ b/lib/bashly/docs/command.yml @@ -309,6 +309,28 @@ command.private: help: Send bash completions private: true +command.variables: + help: Define a list of global bash variables. + url: https://bashly.dannyb.co/configuration/command/#variables + example: |- + variables: + # Simple value + - name: output_folder + value: output + + # Array + - name: download_sources + value: + - youtube + - instagram + + # Associative array + - name: zip_options + value: + pattern: "*.json" + compression_level: fast + + command.version: help: Specify the version to show when running with `--version`. url: https://bashly.dannyb.co/configuration/command/#version diff --git a/lib/bashly/script/command.rb b/lib/bashly/script/command.rb index 3e8c20e3..0e662f0a 100644 --- a/lib/bashly/script/command.rb +++ b/lib/bashly/script/command.rb @@ -17,7 +17,7 @@ def option_keys default dependencies environment_variables examples extensible expose filename filters flags footer function group help name - private version + private variables version ] end end diff --git a/lib/bashly/views/command/function.gtx b/lib/bashly/views/command/function.gtx index 250867ac..1e91fab0 100644 --- a/lib/bashly/views/command/function.gtx +++ b/lib/bashly/views/command/function.gtx @@ -1,6 +1,7 @@ = view_marker > {{ function_name }}_command() { += render(:variables).indent(2) if variables&.any? = load_user_file(filename).indent 2 > } > diff --git a/lib/bashly/views/command/run.gtx b/lib/bashly/views/command/run.gtx index 8dda6762..e3af52c4 100644 --- a/lib/bashly/views/command/run.gtx +++ b/lib/bashly/views/command/run.gtx @@ -9,6 +9,7 @@ if has_unique_args_or_flags? > declare -A unique_lookup=() end += render(:variables).indent(2) if variables&.any? > normalize_input "$@" > parse_requirements "${input[@]}" if user_file_exist?('before') diff --git a/lib/bashly/views/command/variables.gtx b/lib/bashly/views/command/variables.gtx new file mode 100644 index 00000000..a4676ca3 --- /dev/null +++ b/lib/bashly/views/command/variables.gtx @@ -0,0 +1,30 @@ += view_marker + +variables.each do |var| + case var['value'] + when Array + if var['value'].empty? + > declare -a {{ var['name'] }}=() + else + > declare -a {{ var['name'] }}=( + var['value'].each do |v| + > "{{ v }}" + end + > ) + end + when Hash + if var['value'].empty? + > declare -A {{ var['name'] }}=() + else + > declare -A {{ var['name'] }}=( + var['value'].each do |k, v| + > ["{{ k }}"]="{{ v }}" + end + > ) + end + when String, NilClass + > {{ var['name'] }}="{{ var['value'] }}" + else + > {{ var['name'] }}={{ var['value'] }} + end +end diff --git a/spec/approvals/cli/doc/full b/spec/approvals/cli/doc/full index 67f56ae8..43c7ae86 100644 --- a/spec/approvals/cli/doc/full +++ b/spec/approvals/cli/doc/full @@ -467,6 +467,29 @@ command.private See https://bashly.dannyb.co/configuration/command/#private +command.variables + + Define a list of global bash variables. + + variables: + # Simple value + - name: output_folder + value: output + + # Array + - name: download_sources + value: + - youtube + - instagram + + # Associative array + - name: zip_options + value: + pattern: "*.json" + compression_level: fast + + See https://bashly.dannyb.co/configuration/command/#variables + command.version Specify the version to show when running with --version. diff --git a/spec/approvals/cli/doc/index b/spec/approvals/cli/doc/index index 00791e68..3152055e 100644 --- a/spec/approvals/cli/doc/index +++ b/spec/approvals/cli/doc/index @@ -27,6 +27,7 @@ command.group command.help command.name command.private +command.variables command.version environment_variable environment_variable.default diff --git a/spec/approvals/examples/variables b/spec/approvals/examples/variables new file mode 100644 index 00000000..080791a5 --- /dev/null +++ b/spec/approvals/examples/variables @@ -0,0 +1,17 @@ ++ bashly generate +creating user files in src +skipped src/download_command.sh (exists) +skipped src/compress_command.sh (exists) +created ./cli +run ./cli --help to test your bash script ++ ./cli download something +build_number: 1337 +output_folder: output +download_sources: +- youtube +- instagram ++ ./cli compress +build_number: 1337 +zip_options: + compression_level: fast + pattern: *.json