From a3dcd2b4a95a621dc8d98f8b9c364295b4e0996c Mon Sep 17 00:00:00 2001 From: Danny Ben Shitrit Date: Fri, 4 Aug 2023 04:00:33 +0000 Subject: [PATCH 1/4] - Breaking: Rewrite config (INI) library to provide an associative array --- examples/command-paths/README.md | 21 +++- examples/config-ini/README.md | 131 ++++++++++++++----- examples/config-ini/config.ini | 9 +- examples/config-ini/saved.ini | 9 ++ examples/config-ini/src/bashly.yml | 31 +++-- examples/config-ini/src/del_command.sh | 9 ++ examples/config-ini/src/get_command.sh | 12 +- examples/config-ini/src/lib/config.sh | 159 ++++++++---------------- examples/config-ini/src/list_command.sh | 9 +- examples/config-ini/src/set_command.sh | 10 +- examples/config-ini/test.sh | 4 +- examples/dependencies-alt/README.md | 2 +- lib/bashly/libraries/config/config.sh | 159 ++++++++---------------- 13 files changed, 288 insertions(+), 277 deletions(-) create mode 100644 examples/config-ini/saved.ini create mode 100644 examples/config-ini/src/del_command.sh diff --git a/examples/command-paths/README.md b/examples/command-paths/README.md index 18c971bb..802a7b8f 100644 --- a/examples/command-paths/README.md +++ b/examples/command-paths/README.md @@ -137,24 +137,37 @@ Options: ``` -### `$ ./docker download something` +### `$ ./docker container run alpine` ```shell -invalid command: download +# this file is located in 'src/commands/container/run.sh' +# code for 'docker container run' goes here +# you can edit it freely and regenerate (it will not be overwritten) +args: +- ${args[image]} = alpine ``` -### `$ ls -1 src/*` +### `$ ls -R src` ```shell -src/bashly.yml +src: +bashly.yml +commands src/commands: container image ps.sh +src/commands/container: +run.sh +stop.sh + +src/commands/image: +ls.sh + ``` diff --git a/examples/config-ini/README.md b/examples/config-ini/README.md index 65e62931..86d85356 100644 --- a/examples/config-ini/README.md +++ b/examples/config-ini/README.md @@ -13,7 +13,9 @@ $ bashly generate $ bashly generate ``` -Running the `bashly add config` command simply added the [src/lib/config.sh](src/lib/config.sh) file, which includes functions for reading and writing values from an INI file. +Running the `bashly add config` command simply added the +[src/lib/config.sh](src/lib/config.sh) file, which includes functions for +reading and writing values from an INI file. See the files in the [src](src) folder for usage examples. @@ -29,6 +31,23 @@ help: Sample application that uses the config functions version: 0.1.0 commands: +- name: list + alias: l + help: Show the entire config file + +- name: get + alias: g + help: Read a value from the config file + + args: + - name: key + required: true + help: Config key + + examples: + - configly get hello + - configly get user.name + - name: set alias: s help: Save a value in the config file @@ -43,10 +62,11 @@ commands: examples: - configly set hello world + - configly set user.email me@example.com -- name: get - alias: g - help: Read a value from the config file +- name: del + alias: d + help: Remove a value from the config file args: - name: key @@ -54,20 +74,24 @@ commands: help: Config key examples: - - configly set hello - -- name: list - alias: l - help: Show the entire config file + - configly del hello + - configly del user.name ``` ## `config.ini` ```ini -; comments are allowed +; comments are allowed, sections are optional hello = world bashly = works +[options] +name = value for options.name +path = value for options.path + +[user] +name = value for user.name +email = value for user.email ``` @@ -75,40 +99,44 @@ bashly = works ```bash # Using the standard library (lib/config.sh) to show a value from the config +config_load config.ini key="${args[key]}" -if config_has_key "$key"; then - config_get "$key" +value=${config[$key]} + +if [[ "$value" ]]; then + echo "$key = $value" else echo "No such key: $key" fi -# Example of how to assign the config value to a variable: -# result=$(config_get "${args[key]}") -# echo $result - - ``` ## `src/list_command.sh` ```bash # Using the standard library (lib/config.sh) to show the entire config file +config_load config.ini config_show -# Or to iterate through keys -for key in $(config_keys); do - echo "$key === $(config_get "$key")" +# Or to iterate through keys manually +for key in "${!config[@]}"; do + echo "$key = ${config[$key]}" done - ``` ## `src/set_command.sh` ```bash # Using the standard library (lib/config.sh) to store a value to the config -config_set "${args[key]}" "${args[value]}" -echo "saved: ${args[key]} = ${args[value]}" +config_load config.ini + +key="${args[key]}" +value="${args[value]}" + +config["$key"]="$value" +config_show +config_save saved.ini ``` @@ -126,9 +154,10 @@ Usage: configly --version | -v Commands: - set Save a value in the config file - get Read a value from the config file list Show the entire config file + get Read a value from the config file + set Save a value in the config file + del Remove a value from the config file Options: --help, -h @@ -144,15 +173,25 @@ Options: ### `$ ./configly set hello world` ```shell -saved: hello = world +bashly = works +hello = world +options.name = value for options.name +options.path = value for options.path +user.email = value for user.email +user.name = value for user.name ``` -### `$ ./configly set bashly works` +### `$ ./configly set user.name Megatron` ```shell -saved: bashly = works +bashly = works +hello = world +options.name = value for options.name +options.path = value for options.path +user.email = value for user.email +user.name = Megatron ``` @@ -160,7 +199,15 @@ saved: bashly = works ### `$ ./configly get hello` ```shell -world +hello = world + + +``` + +### `$ ./configly get user.name` + +```shell +user.name = value for user.name ``` @@ -171,17 +218,35 @@ world No such key: invalid_key +``` + +### `$ ./configly del user.email` + +```shell +bashly = works +hello = world +options.name = value for options.name +options.path = value for options.path +user.name = value for user.name + + ``` ### `$ ./configly list` ```shell -; comments are allowed +bashly = works hello = world +options.name = value for options.name +options.path = value for options.path +user.email = value for user.email +user.name = value for user.name bashly = works - -hello === world -bashly === works +hello = world +options.path = value for options.path +user.name = value for user.name +options.name = value for options.name +user.email = value for user.email ``` diff --git a/examples/config-ini/config.ini b/examples/config-ini/config.ini index b782f83d..6a09ffdf 100644 --- a/examples/config-ini/config.ini +++ b/examples/config-ini/config.ini @@ -1,4 +1,11 @@ -; comments are allowed +; comments are allowed, sections are optional hello = world bashly = works +[options] +name = value for options.name +path = value for options.path + +[user] +name = value for user.name +email = value for user.email diff --git a/examples/config-ini/saved.ini b/examples/config-ini/saved.ini new file mode 100644 index 00000000..9faeccdb --- /dev/null +++ b/examples/config-ini/saved.ini @@ -0,0 +1,9 @@ +bashly = works +hello = world + +[options] +name = value for options.name +path = value for options.path + +[user] +name = value for user.name diff --git a/examples/config-ini/src/bashly.yml b/examples/config-ini/src/bashly.yml index e0b058ef..f053172b 100644 --- a/examples/config-ini/src/bashly.yml +++ b/examples/config-ini/src/bashly.yml @@ -3,6 +3,23 @@ help: Sample application that uses the config functions version: 0.1.0 commands: +- name: list + alias: l + help: Show the entire config file + +- name: get + alias: g + help: Read a value from the config file + + args: + - name: key + required: true + help: Config key + + examples: + - configly get hello + - configly get user.name + - name: set alias: s help: Save a value in the config file @@ -17,10 +34,11 @@ commands: examples: - configly set hello world + - configly set user.email me@example.com -- name: get - alias: g - help: Read a value from the config file +- name: del + alias: d + help: Remove a value from the config file args: - name: key @@ -28,8 +46,5 @@ commands: help: Config key examples: - - configly set hello - -- name: list - alias: l - help: Show the entire config file + - configly del hello + - configly del user.name diff --git a/examples/config-ini/src/del_command.sh b/examples/config-ini/src/del_command.sh new file mode 100644 index 00000000..b54014ec --- /dev/null +++ b/examples/config-ini/src/del_command.sh @@ -0,0 +1,9 @@ +# Using the standard library (lib/config.sh) to delete a value from the config +config_load config.ini + +key="${args[key]}" +unset config["$key"] + +config_show +config_save saved.ini + diff --git a/examples/config-ini/src/get_command.sh b/examples/config-ini/src/get_command.sh index 844d2912..fe3c47d9 100644 --- a/examples/config-ini/src/get_command.sh +++ b/examples/config-ini/src/get_command.sh @@ -1,13 +1,11 @@ # Using the standard library (lib/config.sh) to show a value from the config +config_load config.ini key="${args[key]}" -if config_has_key "$key"; then - config_get "$key" +value=${config[$key]} + +if [[ "$value" ]]; then + echo "$key = $value" else echo "No such key: $key" fi - -# Example of how to assign the config value to a variable: -# result=$(config_get "${args[key]}") -# echo $result - diff --git a/examples/config-ini/src/lib/config.sh b/examples/config-ini/src/lib/config.sh index bb3074d4..6a3188db 100644 --- a/examples/config-ini/src/lib/config.sh +++ b/examples/config-ini/src/lib/config.sh @@ -1,128 +1,71 @@ -## Config functions [@bashly-upgrade config] +## Config (INI) functions [@bashly-upgrade config] ## This file is a part of Bashly standard library ## ## Usage: -## - In your script, set the CONFIG_FILE variable. For rxample: -## CONFIG_FILE=settings.ini. -## If it is unset, it will default to 'config.ini'. -## - Use any of the functions below to access the config file. +## - In your script, call `config_load path/to/config.ini`. +## - A global associative array named `config` will become available to you, +## and can be accessed like `${config[section1.key1]}` ## -## Create a new config file. -## There is normally no need to use this function, it is used by other -## functions as needed. -## -config_init() { - CONFIG_FILE=${CONFIG_FILE:=config.ini} - [[ -f "$CONFIG_FILE" ]] || touch "$CONFIG_FILE" -} +config_load() { + declare -gA config -## Get a value from the config. -## Usage: result=$(config_get hello) -config_get() { - local key=$1 - local regex="^$key *= *(.+)$" + local config_file="$1" + local section="" + local key="" local value="" - - config_init - - while IFS= read -r line || [ -n "$line" ]; do - if [[ $line =~ $regex ]]; then - value="${BASH_REMATCH[1]}" - break + local section_regex="^\[(.+)\]" + local key_regex="^([^ =]+) *= *(.*) *$" + local comment_regex="^;" + + while IFS= read -r line; do + if [[ $line =~ $comment_regex ]]; then + continue + elif [[ $line =~ $section_regex ]]; then + section="${BASH_REMATCH[1]}." + elif [[ $line =~ $key_regex ]]; then + key="${BASH_REMATCH[1]}" + value="${BASH_REMATCH[2]}" + config["${section}${key}"]="$value" fi - done <"$CONFIG_FILE" - - echo "$value" + done < "$config_file" } -## Add or update a key=value pair in the config. -## Usage: config_set key value -config_set() { - local key=$1 - shift - local value="$*" - - config_init - - local regex="^($key) *= *.+$" - local output="" - local found_key="" - local newline - - while IFS= read -r line || [ -n "$line" ]; do - newline=$line - if [[ $line =~ $regex ]]; then - found_key="${BASH_REMATCH[1]}" - newline="$key = $value" - output="$output$newline\n" - elif [[ $line ]]; then - output="$output$line\n" - fi - done <"$CONFIG_FILE" - - if [[ -z $found_key ]]; then - output="$output$key = $value\n" - fi +## Show all loaded key-value pairs +config_show() { + sorted_keys=($(echo "${!config[@]}" | tr ' ' '\n' | sort)) - printf "%b\n" "$output" >"$CONFIG_FILE" + for key in "${sorted_keys[@]}"; do + echo "$key = ${config[$key]}" + done } -## Delete a key from the config. -## Usage: config_del key -config_del() { - local key=$1 - - local regex="^($key) *=" - local output="" - - config_init +## Save the array back to a file +config_save() { + local filename="$1" + local current_section="" - while IFS= read -r line || [ -n "$line" ]; do - if [[ $line ]] && [[ ! $line =~ $regex ]]; then - output="$output$line\n" - fi - done <"$CONFIG_FILE" + rm -f "$filename" - printf "%b\n" "$output" >"$CONFIG_FILE" -} + free_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep -v '\.' | sort)) + sectioned_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep '\.' | sort)) -## Show the config file -config_show() { - config_init - cat "$CONFIG_FILE" -} - -## Return an array of the keys in the config file. -## Usage: -## -## for k in $(config_keys); do -## echo "- $k = $(config_get "$k")"; -## done -## -config_keys() { - local regex="^([a-zA-Z0-9_\-\/\.]+) *=" + for key in "${free_keys[@]}"; do + value="${config[$key]}" + echo "$key = $value" >> "$filename" + done - config_init + [[ $free_keys ]] && echo >> "$filename" - local keys=() - local key + for key in "${sectioned_keys[@]}"; do + value="${config[$key]}" + IFS="." read -r section_name key_name <<< "$key" - while IFS= read -r line || [ -n "$line" ]; do - if [[ $line =~ $regex ]]; then - key="${BASH_REMATCH[1]}" - keys+=("$key") + if [[ "$current_section" != "$section_name" ]]; then + [[ $current_section ]] && echo >> "$filename" + echo "[$section_name]" >> "$filename" + current_section="$section_name" fi - done <"$CONFIG_FILE" - echo "${keys[@]}" -} - -## Returns true if the specified key exists in the config file. -## Usage: -## -## if config_has_key "key"; then -## echo "key exists" -## fi -## -config_has_key() { - [[ $(config_get "$1") ]] + + echo "$key_name = $value" >> "$filename" + done } diff --git a/examples/config-ini/src/list_command.sh b/examples/config-ini/src/list_command.sh index 9fd650ce..d7ca8c67 100644 --- a/examples/config-ini/src/list_command.sh +++ b/examples/config-ini/src/list_command.sh @@ -1,7 +1,8 @@ # Using the standard library (lib/config.sh) to show the entire config file +config_load config.ini config_show -# Or to iterate through keys -for key in $(config_keys); do - echo "$key === $(config_get "$key")" -done +# Or to iterate through keys manually +for key in "${!config[@]}"; do + echo "$key = ${config[$key]}" +done \ No newline at end of file diff --git a/examples/config-ini/src/set_command.sh b/examples/config-ini/src/set_command.sh index a0cf7ebd..ed410e3a 100644 --- a/examples/config-ini/src/set_command.sh +++ b/examples/config-ini/src/set_command.sh @@ -1,3 +1,9 @@ # Using the standard library (lib/config.sh) to store a value to the config -config_set "${args[key]}" "${args[value]}" -echo "saved: ${args[key]} = ${args[value]}" +config_load config.ini + +key="${args[key]}" +value="${args[value]}" + +config["$key"]="$value" +config_show +config_save saved.ini diff --git a/examples/config-ini/test.sh b/examples/config-ini/test.sh index b34006d7..817c98d4 100644 --- a/examples/config-ini/test.sh +++ b/examples/config-ini/test.sh @@ -9,7 +9,9 @@ bashly generate ./configly -h ./configly set hello world -./configly set bashly works +./configly set user.name Megatron ./configly get hello +./configly get user.name ./configly get invalid_key +./configly del user.email ./configly list diff --git a/examples/dependencies-alt/README.md b/examples/dependencies-alt/README.md index 4c18e629..cf322487 100644 --- a/examples/dependencies-alt/README.md +++ b/examples/dependencies-alt/README.md @@ -60,7 +60,7 @@ args: none deps: - ${deps[git]} = /usr/bin/git - ${deps[http_client]} = /usr/bin/curl -- ${deps[ruby]} = /home/vagrant/.rbenv/versions/3.1.3/bin/ruby +- ${deps[ruby]} = /home/vagrant/.rbenv/versions/3.2.2/bin/ruby ``` diff --git a/lib/bashly/libraries/config/config.sh b/lib/bashly/libraries/config/config.sh index bb3074d4..6a3188db 100644 --- a/lib/bashly/libraries/config/config.sh +++ b/lib/bashly/libraries/config/config.sh @@ -1,128 +1,71 @@ -## Config functions [@bashly-upgrade config] +## Config (INI) functions [@bashly-upgrade config] ## This file is a part of Bashly standard library ## ## Usage: -## - In your script, set the CONFIG_FILE variable. For rxample: -## CONFIG_FILE=settings.ini. -## If it is unset, it will default to 'config.ini'. -## - Use any of the functions below to access the config file. +## - In your script, call `config_load path/to/config.ini`. +## - A global associative array named `config` will become available to you, +## and can be accessed like `${config[section1.key1]}` ## -## Create a new config file. -## There is normally no need to use this function, it is used by other -## functions as needed. -## -config_init() { - CONFIG_FILE=${CONFIG_FILE:=config.ini} - [[ -f "$CONFIG_FILE" ]] || touch "$CONFIG_FILE" -} +config_load() { + declare -gA config -## Get a value from the config. -## Usage: result=$(config_get hello) -config_get() { - local key=$1 - local regex="^$key *= *(.+)$" + local config_file="$1" + local section="" + local key="" local value="" - - config_init - - while IFS= read -r line || [ -n "$line" ]; do - if [[ $line =~ $regex ]]; then - value="${BASH_REMATCH[1]}" - break + local section_regex="^\[(.+)\]" + local key_regex="^([^ =]+) *= *(.*) *$" + local comment_regex="^;" + + while IFS= read -r line; do + if [[ $line =~ $comment_regex ]]; then + continue + elif [[ $line =~ $section_regex ]]; then + section="${BASH_REMATCH[1]}." + elif [[ $line =~ $key_regex ]]; then + key="${BASH_REMATCH[1]}" + value="${BASH_REMATCH[2]}" + config["${section}${key}"]="$value" fi - done <"$CONFIG_FILE" - - echo "$value" + done < "$config_file" } -## Add or update a key=value pair in the config. -## Usage: config_set key value -config_set() { - local key=$1 - shift - local value="$*" - - config_init - - local regex="^($key) *= *.+$" - local output="" - local found_key="" - local newline - - while IFS= read -r line || [ -n "$line" ]; do - newline=$line - if [[ $line =~ $regex ]]; then - found_key="${BASH_REMATCH[1]}" - newline="$key = $value" - output="$output$newline\n" - elif [[ $line ]]; then - output="$output$line\n" - fi - done <"$CONFIG_FILE" - - if [[ -z $found_key ]]; then - output="$output$key = $value\n" - fi +## Show all loaded key-value pairs +config_show() { + sorted_keys=($(echo "${!config[@]}" | tr ' ' '\n' | sort)) - printf "%b\n" "$output" >"$CONFIG_FILE" + for key in "${sorted_keys[@]}"; do + echo "$key = ${config[$key]}" + done } -## Delete a key from the config. -## Usage: config_del key -config_del() { - local key=$1 - - local regex="^($key) *=" - local output="" - - config_init +## Save the array back to a file +config_save() { + local filename="$1" + local current_section="" - while IFS= read -r line || [ -n "$line" ]; do - if [[ $line ]] && [[ ! $line =~ $regex ]]; then - output="$output$line\n" - fi - done <"$CONFIG_FILE" + rm -f "$filename" - printf "%b\n" "$output" >"$CONFIG_FILE" -} + free_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep -v '\.' | sort)) + sectioned_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep '\.' | sort)) -## Show the config file -config_show() { - config_init - cat "$CONFIG_FILE" -} - -## Return an array of the keys in the config file. -## Usage: -## -## for k in $(config_keys); do -## echo "- $k = $(config_get "$k")"; -## done -## -config_keys() { - local regex="^([a-zA-Z0-9_\-\/\.]+) *=" + for key in "${free_keys[@]}"; do + value="${config[$key]}" + echo "$key = $value" >> "$filename" + done - config_init + [[ $free_keys ]] && echo >> "$filename" - local keys=() - local key + for key in "${sectioned_keys[@]}"; do + value="${config[$key]}" + IFS="." read -r section_name key_name <<< "$key" - while IFS= read -r line || [ -n "$line" ]; do - if [[ $line =~ $regex ]]; then - key="${BASH_REMATCH[1]}" - keys+=("$key") + if [[ "$current_section" != "$section_name" ]]; then + [[ $current_section ]] && echo >> "$filename" + echo "[$section_name]" >> "$filename" + current_section="$section_name" fi - done <"$CONFIG_FILE" - echo "${keys[@]}" -} - -## Returns true if the specified key exists in the config file. -## Usage: -## -## if config_has_key "key"; then -## echo "key exists" -## fi -## -config_has_key() { - [[ $(config_get "$1") ]] + + echo "$key_name = $value" >> "$filename" + done } From b5ece8e6a9637d3157fa8b3f473d3d9d17942f1e Mon Sep 17 00:00:00 2001 From: Danny Ben Shitrit Date: Fri, 4 Aug 2023 04:14:51 +0000 Subject: [PATCH 2/4] update specs --- spec/approvals/examples/config-ini | 50 ++++++++++++++----- spec/approvals/fixtures/config-lib | 10 ---- .../fixtures/workspaces/config-lib/.gitignore | 2 - spec/fixtures/workspaces/config-lib/README.md | 2 - .../fixtures/workspaces/config-lib/config.ini | 2 - .../workspaces/config-lib/src/bashly.yml | 3 -- .../workspaces/config-lib/src/root_command.sh | 3 -- spec/fixtures/workspaces/config-lib/test.sh | 14 ------ 8 files changed, 38 insertions(+), 48 deletions(-) delete mode 100644 spec/approvals/fixtures/config-lib delete mode 100644 spec/fixtures/workspaces/config-lib/.gitignore delete mode 100644 spec/fixtures/workspaces/config-lib/README.md delete mode 100644 spec/fixtures/workspaces/config-lib/config.ini delete mode 100644 spec/fixtures/workspaces/config-lib/src/bashly.yml delete mode 100644 spec/fixtures/workspaces/config-lib/src/root_command.sh delete mode 100644 spec/fixtures/workspaces/config-lib/test.sh diff --git a/spec/approvals/examples/config-ini b/spec/approvals/examples/config-ini index 2cc3773e..47ec2670 100644 --- a/spec/approvals/examples/config-ini +++ b/spec/approvals/examples/config-ini @@ -2,9 +2,10 @@ created src/lib/config.sh + bashly generate creating user files in src -skipped src/set_command.sh (exists) -skipped src/get_command.sh (exists) skipped src/list_command.sh (exists) +skipped src/get_command.sh (exists) +skipped src/set_command.sh (exists) +skipped src/del_command.sh (exists) created ./configly run ./configly --help to test your bash script + ./configly -h @@ -16,9 +17,10 @@ Usage: configly --version | -v Commands: - set Save a value in the config file - get Read a value from the config file list Show the entire config file + get Read a value from the config file + set Save a value in the config file + del Remove a value from the config file Options: --help, -h @@ -28,17 +30,41 @@ Options: Show version number + ./configly set hello world -saved: hello = world -+ ./configly set bashly works -saved: bashly = works +bashly = works +hello = world +options.name = value for options.name +options.path = value for options.path +user.email = value for user.email +user.name = value for user.name ++ ./configly set user.name Megatron +bashly = works +hello = world +options.name = value for options.name +options.path = value for options.path +user.email = value for user.email +user.name = Megatron + ./configly get hello -world +hello = world ++ ./configly get user.name +user.name = value for user.name + ./configly get invalid_key No such key: invalid_key ++ ./configly del user.email +bashly = works +hello = world +options.name = value for options.name +options.path = value for options.path +user.name = value for user.name + ./configly list -; comments are allowed +bashly = works hello = world +options.name = value for options.name +options.path = value for options.path +user.email = value for user.email +user.name = value for user.name bashly = works - -hello === world -bashly === works +hello = world +options.path = value for options.path +user.name = value for user.name +options.name = value for options.name +user.email = value for user.email diff --git a/spec/approvals/fixtures/config-lib b/spec/approvals/fixtures/config-lib deleted file mode 100644 index 45237288..00000000 --- a/spec/approvals/fixtures/config-lib +++ /dev/null @@ -1,10 +0,0 @@ -+ bundle exec bashly add config --force -created src/lib/config.sh -+ bundle exec bashly generate -creating user files in src -skipped src/root_command.sh (exists) -created ./download -run ./download --help to test your bash script -+ ./download -foo=BOOM -bar= diff --git a/spec/fixtures/workspaces/config-lib/.gitignore b/spec/fixtures/workspaces/config-lib/.gitignore deleted file mode 100644 index b1260219..00000000 --- a/spec/fixtures/workspaces/config-lib/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -download -src/lib diff --git a/spec/fixtures/workspaces/config-lib/README.md b/spec/fixtures/workspaces/config-lib/README.md deleted file mode 100644 index 8806dc86..00000000 --- a/spec/fixtures/workspaces/config-lib/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This fixture tests that the config lib scope bug -Reference issue: https://github.com/DannyBen/bashly/issues/107 \ No newline at end of file diff --git a/spec/fixtures/workspaces/config-lib/config.ini b/spec/fixtures/workspaces/config-lib/config.ini deleted file mode 100644 index c2eb5b08..00000000 --- a/spec/fixtures/workspaces/config-lib/config.ini +++ /dev/null @@ -1,2 +0,0 @@ -foo = BOOM - diff --git a/spec/fixtures/workspaces/config-lib/src/bashly.yml b/spec/fixtures/workspaces/config-lib/src/bashly.yml deleted file mode 100644 index e6ff2744..00000000 --- a/spec/fixtures/workspaces/config-lib/src/bashly.yml +++ /dev/null @@ -1,3 +0,0 @@ -name: download -help: Sample minimal application without commands -version: 0.1.0 diff --git a/spec/fixtures/workspaces/config-lib/src/root_command.sh b/spec/fixtures/workspaces/config-lib/src/root_command.sh deleted file mode 100644 index aae155b5..00000000 --- a/spec/fixtures/workspaces/config-lib/src/root_command.sh +++ /dev/null @@ -1,3 +0,0 @@ -config_set foo BOOM -echo "foo=$(config_get foo)" -echo "bar=$(config_get bar)" \ No newline at end of file diff --git a/spec/fixtures/workspaces/config-lib/test.sh b/spec/fixtures/workspaces/config-lib/test.sh deleted file mode 100644 index 99cafd2d..00000000 --- a/spec/fixtures/workspaces/config-lib/test.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -# This fixture tests that the config lib scope bug -# It is executed as part of the Runfile examples test -# Reference issue: https://github.com/DannyBen/bashly/issues/107 - -rm -f ./download - -set -x - -bundle exec bashly add config --force -bundle exec bashly generate - -./download \ No newline at end of file From f7f45fec677fd139d1049e59e43f260e830f820d Mon Sep 17 00:00:00 2001 From: Danny Ben Shitrit Date: Fri, 4 Aug 2023 16:43:21 +0000 Subject: [PATCH 3/4] fix config library --- examples/config-ini/src/del_command.sh | 4 +-- examples/config-ini/src/lib/config.sh | 37 ++++++++++++--------- examples/config-ini/src/list_command.sh | 8 ++--- examples/config-ini/src/set_command.sh | 2 +- examples/config-ini/test.sh | 2 +- lib/bashly/libraries/config/config.sh | 37 ++++++++++++--------- spec/approvals/examples/config-ini | 44 ++++++++++++++----------- 7 files changed, 75 insertions(+), 59 deletions(-) diff --git a/examples/config-ini/src/del_command.sh b/examples/config-ini/src/del_command.sh index b54014ec..daf2eab8 100644 --- a/examples/config-ini/src/del_command.sh +++ b/examples/config-ini/src/del_command.sh @@ -2,8 +2,8 @@ config_load config.ini key="${args[key]}" -unset config["$key"] +unset "config[$key]" -config_show config_save saved.ini +cat saved.ini diff --git a/examples/config-ini/src/lib/config.sh b/examples/config-ini/src/lib/config.sh index 6a3188db..e4dd1d78 100644 --- a/examples/config-ini/src/lib/config.sh +++ b/examples/config-ini/src/lib/config.sh @@ -16,7 +16,7 @@ config_load() { local section_regex="^\[(.+)\]" local key_regex="^([^ =]+) *= *(.*) *$" local comment_regex="^;" - + while IFS= read -r line; do if [[ $line =~ $comment_regex ]]; then continue @@ -30,33 +30,25 @@ config_load() { done < "$config_file" } -## Show all loaded key-value pairs -config_show() { - sorted_keys=($(echo "${!config[@]}" | tr ' ' '\n' | sort)) - - for key in "${sorted_keys[@]}"; do - echo "$key = ${config[$key]}" - done -} - ## Save the array back to a file config_save() { local filename="$1" local current_section="" + local has_free_keys=false rm -f "$filename" - free_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep -v '\.' | sort)) - sectioned_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep '\.' | sort)) - - for key in "${free_keys[@]}"; do + for key in $(config_keys); do + [[ $key == *.* ]] && continue + has_free_keys=true value="${config[$key]}" echo "$key = $value" >> "$filename" done - [[ $free_keys ]] && echo >> "$filename" + [[ "${has_free_keys}" == "true" ]] && echo >> "$filename" - for key in "${sectioned_keys[@]}"; do + for key in $(config_keys); do + [[ $key == *.* ]] || continue value="${config[$key]}" IFS="." read -r section_name key_name <<< "$key" @@ -69,3 +61,16 @@ config_save() { echo "$key_name = $value" >> "$filename" done } + +## Show all loaded key-value pairs +config_show() { + for key in $(config_keys); do + echo "$key = ${config[$key]}" + done +} + +## Return a newline delimited, sorted list of keys +config_keys() { + local keys=("${!config[@]}") + for a in "${keys[@]}"; do echo "$a"; done |sort +} diff --git a/examples/config-ini/src/list_command.sh b/examples/config-ini/src/list_command.sh index d7ca8c67..f871729f 100644 --- a/examples/config-ini/src/list_command.sh +++ b/examples/config-ini/src/list_command.sh @@ -2,7 +2,7 @@ config_load config.ini config_show -# Or to iterate through keys manually -for key in "${!config[@]}"; do - echo "$key = ${config[$key]}" -done \ No newline at end of file +## Or to iterate through keys manually +# for key in $(config_keys); do +# echo "$key = ${config[$key]}" +# done \ No newline at end of file diff --git a/examples/config-ini/src/set_command.sh b/examples/config-ini/src/set_command.sh index ed410e3a..44b52203 100644 --- a/examples/config-ini/src/set_command.sh +++ b/examples/config-ini/src/set_command.sh @@ -5,5 +5,5 @@ key="${args[key]}" value="${args[value]}" config["$key"]="$value" -config_show config_save saved.ini +cat saved.ini diff --git a/examples/config-ini/test.sh b/examples/config-ini/test.sh index 817c98d4..ff620e7a 100644 --- a/examples/config-ini/test.sh +++ b/examples/config-ini/test.sh @@ -8,7 +8,7 @@ bashly generate ### Try Me ### ./configly -h -./configly set hello world +./configly set hello WORLD ./configly set user.name Megatron ./configly get hello ./configly get user.name diff --git a/lib/bashly/libraries/config/config.sh b/lib/bashly/libraries/config/config.sh index 6a3188db..e4dd1d78 100644 --- a/lib/bashly/libraries/config/config.sh +++ b/lib/bashly/libraries/config/config.sh @@ -16,7 +16,7 @@ config_load() { local section_regex="^\[(.+)\]" local key_regex="^([^ =]+) *= *(.*) *$" local comment_regex="^;" - + while IFS= read -r line; do if [[ $line =~ $comment_regex ]]; then continue @@ -30,33 +30,25 @@ config_load() { done < "$config_file" } -## Show all loaded key-value pairs -config_show() { - sorted_keys=($(echo "${!config[@]}" | tr ' ' '\n' | sort)) - - for key in "${sorted_keys[@]}"; do - echo "$key = ${config[$key]}" - done -} - ## Save the array back to a file config_save() { local filename="$1" local current_section="" + local has_free_keys=false rm -f "$filename" - free_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep -v '\.' | sort)) - sectioned_keys=($(echo "${!config[@]}" | tr ' ' '\n' | grep '\.' | sort)) - - for key in "${free_keys[@]}"; do + for key in $(config_keys); do + [[ $key == *.* ]] && continue + has_free_keys=true value="${config[$key]}" echo "$key = $value" >> "$filename" done - [[ $free_keys ]] && echo >> "$filename" + [[ "${has_free_keys}" == "true" ]] && echo >> "$filename" - for key in "${sectioned_keys[@]}"; do + for key in $(config_keys); do + [[ $key == *.* ]] || continue value="${config[$key]}" IFS="." read -r section_name key_name <<< "$key" @@ -69,3 +61,16 @@ config_save() { echo "$key_name = $value" >> "$filename" done } + +## Show all loaded key-value pairs +config_show() { + for key in $(config_keys); do + echo "$key = ${config[$key]}" + done +} + +## Return a newline delimited, sorted list of keys +config_keys() { + local keys=("${!config[@]}") + for a in "${keys[@]}"; do echo "$a"; done |sort +} diff --git a/spec/approvals/examples/config-ini b/spec/approvals/examples/config-ini index 47ec2670..7e677be2 100644 --- a/spec/approvals/examples/config-ini +++ b/spec/approvals/examples/config-ini @@ -29,20 +29,28 @@ Options: --version, -v Show version number -+ ./configly set hello world ++ ./configly set hello WORLD bashly = works -hello = world -options.name = value for options.name -options.path = value for options.path -user.email = value for user.email -user.name = value for user.name +hello = WORLD + +[options] +name = value for options.name +path = value for options.path + +[user] +email = value for user.email +name = value for user.name + ./configly set user.name Megatron bashly = works hello = world -options.name = value for options.name -options.path = value for options.path -user.email = value for user.email -user.name = Megatron + +[options] +name = value for options.name +path = value for options.path + +[user] +email = value for user.email +name = Megatron + ./configly get hello hello = world + ./configly get user.name @@ -52,9 +60,13 @@ No such key: invalid_key + ./configly del user.email bashly = works hello = world -options.name = value for options.name -options.path = value for options.path -user.name = value for user.name + +[options] +name = value for options.name +path = value for options.path + +[user] +name = value for user.name + ./configly list bashly = works hello = world @@ -62,9 +74,3 @@ options.name = value for options.name options.path = value for options.path user.email = value for user.email user.name = value for user.name -bashly = works -hello = world -options.path = value for options.path -user.name = value for user.name -options.name = value for options.name -user.email = value for user.email From 2e69b1f270062567edc612621fa04d9d7fe8575a Mon Sep 17 00:00:00 2001 From: Danny Ben Shitrit Date: Fri, 4 Aug 2023 16:57:05 +0000 Subject: [PATCH 4/4] fix shfmt issues --- examples/config-ini/README.md | 54 +++++++++++++++------------ examples/config-ini/src/lib/config.sh | 16 ++++---- lib/bashly/libraries/config/config.sh | 16 ++++---- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/examples/config-ini/README.md b/examples/config-ini/README.md index 86d85356..3b4eac8a 100644 --- a/examples/config-ini/README.md +++ b/examples/config-ini/README.md @@ -119,10 +119,10 @@ fi config_load config.ini config_show -# Or to iterate through keys manually -for key in "${!config[@]}"; do - echo "$key = ${config[$key]}" -done +## Or to iterate through keys manually +# for key in $(config_keys); do +# echo "$key = ${config[$key]}" +# done ``` ## `src/set_command.sh` @@ -135,8 +135,8 @@ key="${args[key]}" value="${args[value]}" config["$key"]="$value" -config_show config_save saved.ini +cat saved.ini ``` @@ -170,15 +170,19 @@ Options: ``` -### `$ ./configly set hello world` +### `$ ./configly set hello WORLD` ```shell bashly = works -hello = world -options.name = value for options.name -options.path = value for options.path -user.email = value for user.email -user.name = value for user.name +hello = WORLD + +[options] +name = value for options.name +path = value for options.path + +[user] +email = value for user.email +name = value for user.name ``` @@ -188,10 +192,14 @@ user.name = value for user.name ```shell bashly = works hello = world -options.name = value for options.name -options.path = value for options.path -user.email = value for user.email -user.name = Megatron + +[options] +name = value for options.name +path = value for options.path + +[user] +email = value for user.email +name = Megatron ``` @@ -225,9 +233,13 @@ No such key: invalid_key ```shell bashly = works hello = world -options.name = value for options.name -options.path = value for options.path -user.name = value for user.name + +[options] +name = value for options.name +path = value for options.path + +[user] +name = value for user.name ``` @@ -241,12 +253,6 @@ options.name = value for options.name options.path = value for options.path user.email = value for user.email user.name = value for user.name -bashly = works -hello = world -options.path = value for options.path -user.name = value for user.name -options.name = value for options.name -user.email = value for user.email ``` diff --git a/examples/config-ini/src/lib/config.sh b/examples/config-ini/src/lib/config.sh index e4dd1d78..9c0faf1b 100644 --- a/examples/config-ini/src/lib/config.sh +++ b/examples/config-ini/src/lib/config.sh @@ -27,7 +27,7 @@ config_load() { value="${BASH_REMATCH[2]}" config["${section}${key}"]="$value" fi - done < "$config_file" + done <"$config_file" } ## Save the array back to a file @@ -42,23 +42,23 @@ config_save() { [[ $key == *.* ]] && continue has_free_keys=true value="${config[$key]}" - echo "$key = $value" >> "$filename" + echo "$key = $value" >>"$filename" done - [[ "${has_free_keys}" == "true" ]] && echo >> "$filename" + [[ "${has_free_keys}" == "true" ]] && echo >>"$filename" for key in $(config_keys); do [[ $key == *.* ]] || continue value="${config[$key]}" - IFS="." read -r section_name key_name <<< "$key" + IFS="." read -r section_name key_name <<<"$key" if [[ "$current_section" != "$section_name" ]]; then - [[ $current_section ]] && echo >> "$filename" - echo "[$section_name]" >> "$filename" + [[ $current_section ]] && echo >>"$filename" + echo "[$section_name]" >>"$filename" current_section="$section_name" fi - echo "$key_name = $value" >> "$filename" + echo "$key_name = $value" >>"$filename" done } @@ -72,5 +72,5 @@ config_show() { ## Return a newline delimited, sorted list of keys config_keys() { local keys=("${!config[@]}") - for a in "${keys[@]}"; do echo "$a"; done |sort + for a in "${keys[@]}"; do echo "$a"; done | sort } diff --git a/lib/bashly/libraries/config/config.sh b/lib/bashly/libraries/config/config.sh index e4dd1d78..9c0faf1b 100644 --- a/lib/bashly/libraries/config/config.sh +++ b/lib/bashly/libraries/config/config.sh @@ -27,7 +27,7 @@ config_load() { value="${BASH_REMATCH[2]}" config["${section}${key}"]="$value" fi - done < "$config_file" + done <"$config_file" } ## Save the array back to a file @@ -42,23 +42,23 @@ config_save() { [[ $key == *.* ]] && continue has_free_keys=true value="${config[$key]}" - echo "$key = $value" >> "$filename" + echo "$key = $value" >>"$filename" done - [[ "${has_free_keys}" == "true" ]] && echo >> "$filename" + [[ "${has_free_keys}" == "true" ]] && echo >>"$filename" for key in $(config_keys); do [[ $key == *.* ]] || continue value="${config[$key]}" - IFS="." read -r section_name key_name <<< "$key" + IFS="." read -r section_name key_name <<<"$key" if [[ "$current_section" != "$section_name" ]]; then - [[ $current_section ]] && echo >> "$filename" - echo "[$section_name]" >> "$filename" + [[ $current_section ]] && echo >>"$filename" + echo "[$section_name]" >>"$filename" current_section="$section_name" fi - echo "$key_name = $value" >> "$filename" + echo "$key_name = $value" >>"$filename" done } @@ -72,5 +72,5 @@ config_show() { ## Return a newline delimited, sorted list of keys config_keys() { local keys=("${!config[@]}") - for a in "${keys[@]}"; do echo "$a"; done |sort + for a in "${keys[@]}"; do echo "$a"; done | sort }