bashly 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58a2804698490f003611b4f607614fef9995bea16f426c6d56d527d78b770a29
4
- data.tar.gz: 24a4c1d97b45332e424fc6932092225bab7b3ade618f5eec5e9c187ca91389ac
3
+ metadata.gz: b82e5ead650cc1774cf3870af91b9046b1e5f69f05484d833f72dd4090eab091
4
+ data.tar.gz: 26626b09b79382d2d4530241b5517ed04d3e4a27c004130adadad3b27421f100
5
5
  SHA512:
6
- metadata.gz: 0e62c14ede0d0295e01411cd946859a21413e50b43313f850ea494c4ed5dafe6f402b914dfc8f682c3abc8e38d9004917dbd654d78f8983b961f2f35228e97e4
7
- data.tar.gz: '00309d231db02bb61fe7d9ae2c95d9d615888830a6a95c2815cda9e8b08fa4dd73e6ccc0f0127bf46a467deee4888297975f421a2a1e0c80fa5b23d871124726'
6
+ metadata.gz: 9e3b78d5975c92954347be94d567f28d240d628e080fb3d136382cc4f8fa1ae81827057ad3b61ac144b5ab930c3f5353128f9d6068b983d0e2e77ac996d4ab0d
7
+ data.tar.gz: 2595428ca74b3ada25619fc7839f99993f98bcda169b47fcda84c82b279ebcaa1882864d2d842c67f05ca1ca946f2f64867d6905892f2ff5f5f5107f32f49037
data/README.md CHANGED
@@ -32,7 +32,6 @@ a [docker image](https://hub.docker.com/r/dannyben/bashly).
32
32
  <table>
33
33
  <tr>
34
34
  <td><a href="https://rhodecode.com/"><img src='support/img/RhodeCode-logo.png' width=240></a></td>
35
- <td><a href="https://decisiohealth.com/"><img src='support/img/decisio-logo.png' width=240></a></td>
36
35
  </tr>
37
36
  </table>
38
37
 
@@ -82,11 +81,6 @@ to contribute, feel free to [open an issue][issues] or
82
81
 
83
82
  Visit the *[How to contribute][contributing]* page for more information.
84
83
 
85
- ## Stargazers and Forkers
86
-
87
- [![Stargazers repo roster for @DannyBen/bashly](https://reporoster.com/stars/DannyBen/bashly)](https://github.com/DannyBen/bashly/stargazers)
88
-
89
- [![Forkers repo roster for @DannyBen/bashly](https://reporoster.com/forks/DannyBen/bashly)](https://github.com/DannyBen/bashly/network/members)
90
84
 
91
85
  [issues]: https://github.com/DannyBen/bashly/issues
92
86
  [discussions]: https://github.com/DannyBen/bashly/discussions
@@ -4,7 +4,7 @@ module Bashly
4
4
  summary 'Install bash completions for bashly itself'
5
5
  help 'Display the bash completions script or install it directly to your bash completions directory'
6
6
 
7
- usage 'bashly completions [--install --uninstall]'
7
+ usage 'bashly completions [--install|--uninstall]'
8
8
  usage 'bashly completions (-h|--help)'
9
9
 
10
10
  option '-i --install', 'Install the completions script to your bash completions directory'
data/lib/bashly/config.rb CHANGED
@@ -2,7 +2,11 @@ require 'yaml'
2
2
 
3
3
  module Bashly
4
4
  # A convenience class to use either a hash or a filename as a configuration
5
- # source
5
+ # source.
6
+ #
7
+ # When a filename is provided, it is loaded with these extra features:
8
+ # - Support for `import` keyword to merge additional YAML files
9
+ # - Preprocessing with ERB
6
10
  class Config
7
11
  using ComposeRefinements
8
12
 
@@ -10,7 +14,7 @@ module Bashly
10
14
 
11
15
  def self.new(config)
12
16
  if config.is_a? String
13
- YAML.properly_load_file(config).compose
17
+ YAML.load_erb_file(config).compose
14
18
  else
15
19
  config
16
20
  end
@@ -13,6 +13,10 @@ class String
13
13
  gsub(/(.)([A-Z])/, '\1_\2').gsub(/[- ]/, '_').downcase
14
14
  end
15
15
 
16
+ def to_path
17
+ tr(' ', '/').downcase
18
+ end
19
+
16
20
  def wrap(length = 80)
17
21
  strip!
18
22
  split("\n").collect! do |line|
@@ -1,10 +1,12 @@
1
1
  module YAML
2
- # This awkward patch is due to https://bugs.ruby-lang.org/issues/17866
3
- def self.properly_load_file(path)
4
- YAML.load_file path, aliases: true
5
- rescue ArgumentError
6
- # :nocov:
7
- YAML.load_file path
8
- # :nocov:
2
+ # We trust our loaded YAMLs
3
+ # This patch is due to https://bugs.ruby-lang.org/issues/17866
4
+ # StackOverflow: https://stackoverflow.com/questions/71191685/visit-psych-nodes-alias-unknown-alias-default-psychbadalias/71192990#71192990
5
+ class << self
6
+ alias load unsafe_load
7
+
8
+ def load_erb_file(path)
9
+ YAML.load ERB.new(File.read(path)).result
10
+ end
9
11
  end
10
12
  end
@@ -1,128 +1,108 @@
1
- ## Config functions [@bashly-upgrade config]
1
+ ## Config (INI) functions [@bashly-upgrade config]
2
2
  ## This file is a part of Bashly standard library
3
3
  ##
4
4
  ## Usage:
5
- ## - In your script, set the CONFIG_FILE variable. For rxample:
6
- ## CONFIG_FILE=settings.ini.
7
- ## If it is unset, it will default to 'config.ini'.
8
- ## - Use any of the functions below to access the config file.
9
5
  ##
10
- ## Create a new config file.
11
- ## There is normally no need to use this function, it is used by other
12
- ## functions as needed.
6
+ ## - Set the global variable CONFIG_FILE to the path of your INI file somewhere
7
+ ## in your script (for example, in src/initialize.sh).
8
+ ## - Use any of the following functions to access and manipulate the values.
9
+ ## - INI sections are optional (i.e., sectionless key=value pairs are allowed).
13
10
  ##
14
- config_init() {
15
- CONFIG_FILE=${CONFIG_FILE:=config.ini}
16
- [[ -f "$CONFIG_FILE" ]] || touch "$CONFIG_FILE"
11
+
12
+ ## Show all the key=value pairs from your config file
13
+ config_show() {
14
+ config_load
15
+ ini_show
17
16
  }
18
17
 
19
- ## Get a value from the config.
20
- ## Usage: result=$(config_get hello)
18
+ ## Get a single value from the config file:
19
+ ##
20
+ ## config_get login.email
21
+ ##
22
+ ## Get the value or a default one if it is not set:
23
+ ##
24
+ ## config_get login.user guest
25
+ ##
26
+ ## Assign the result to a variable:
27
+ ##
28
+ ## theme="$(config_get interface.theme)"
29
+ ##
21
30
  config_get() {
22
- local key=$1
23
- local regex="^$key *= *(.+)$"
24
- local value=""
25
-
26
- config_init
31
+ local key="$1"
32
+ local default_value="$2"
27
33
 
28
- while IFS= read -r line || [ -n "$line" ]; do
29
- if [[ $line =~ $regex ]]; then
30
- value="${BASH_REMATCH[1]}"
31
- break
32
- fi
33
- done <"$CONFIG_FILE"
34
-
35
- echo "$value"
34
+ config_load
35
+ echo "${ini["$key"]:-$default_value}"
36
36
  }
37
37
 
38
- ## Add or update a key=value pair in the config.
39
- ## Usage: config_set key value
38
+ ## Create/update a key=value pair:
39
+ ##
40
+ ## config_set cloud.provider aws
41
+ ##
40
42
  config_set() {
41
- local key=$1
43
+ local key="$1"
42
44
  shift
43
45
  local value="$*"
44
46
 
45
- config_init
46
-
47
- local regex="^($key) *= *.+$"
48
- local output=""
49
- local found_key=""
50
- local newline
51
-
52
- while IFS= read -r line || [ -n "$line" ]; do
53
- newline=$line
54
- if [[ $line =~ $regex ]]; then
55
- found_key="${BASH_REMATCH[1]}"
56
- newline="$key = $value"
57
- output="$output$newline\n"
58
- elif [[ $line ]]; then
59
- output="$output$line\n"
60
- fi
61
- done <"$CONFIG_FILE"
62
-
63
- if [[ -z $found_key ]]; then
64
- output="$output$key = $value\n"
65
- fi
66
-
67
- printf "%b\n" "$output" >"$CONFIG_FILE"
47
+ config_load
48
+ ini["$key"]="$value"
49
+ config_save
68
50
  }
69
51
 
70
- ## Delete a key from the config.
71
- ## Usage: config_del key
52
+ ## Delete a key=value pair:
53
+ ##
54
+ ## config_del login.email
55
+ ##
72
56
  config_del() {
73
- local key=$1
57
+ local key="$1"
74
58
 
75
- local regex="^($key) *="
76
- local output=""
77
-
78
- config_init
79
-
80
- while IFS= read -r line || [ -n "$line" ]; do
81
- if [[ $line ]] && [[ ! $line =~ $regex ]]; then
82
- output="$output$line\n"
83
- fi
84
- done <"$CONFIG_FILE"
85
-
86
- printf "%b\n" "$output" >"$CONFIG_FILE"
87
- }
88
-
89
- ## Show the config file
90
- config_show() {
91
- config_init
92
- cat "$CONFIG_FILE"
59
+ config_load
60
+ unset "ini[$key]"
61
+ config_save
93
62
  }
94
63
 
95
- ## Return an array of the keys in the config file.
96
- ## Usage:
64
+ ## Get an array of all keys:
97
65
  ##
98
- ## for k in $(config_keys); do
99
- ## echo "- $k = $(config_get "$k")";
66
+ ## for key in $(config_keys); do
67
+ ## echo "- $key = $(config_get "$key")";
100
68
  ## done
101
69
  ##
102
70
  config_keys() {
103
- local regex="^([a-zA-Z0-9_\-\/\.]+) *="
104
-
105
- config_init
106
-
107
- local keys=()
108
- local key
109
-
110
- while IFS= read -r line || [ -n "$line" ]; do
111
- if [[ $line =~ $regex ]]; then
112
- key="${BASH_REMATCH[1]}"
113
- keys+=("$key")
114
- fi
115
- done <"$CONFIG_FILE"
116
- echo "${keys[@]}"
71
+ config_load
72
+ ini_keys
117
73
  }
118
74
 
119
- ## Returns true if the specified key exists in the config file.
120
- ## Usage:
75
+ ## Check if a key exists:
121
76
  ##
122
- ## if config_has_key "key"; then
77
+ ## if config_has_key login.password; then
123
78
  ## echo "key exists"
124
79
  ## fi
125
80
  ##
126
81
  config_has_key() {
127
82
  [[ $(config_get "$1") ]]
128
83
  }
84
+
85
+ ## Force-load from file
86
+ ## This should normally not be called, unless you suspect that the INI file
87
+ ## was modified by external means during the run of your script.
88
+ config_reload() {
89
+ declare -g config_loaded=false
90
+ config_load
91
+ }
92
+
93
+ ## Load an INI file (unless loaded) and populate the associative array
94
+ ## NOTE: Normally there is no need to call this function, it is called as needed
95
+ config_load() {
96
+ [[ "$config_loaded" == "true" ]] && return
97
+
98
+ declare -g CONFIG_FILE=${CONFIG_FILE:=config.ini}
99
+ declare -g config_loaded=true
100
+ [[ -f "$CONFIG_FILE" ]] || touch "$CONFIG_FILE"
101
+ ini_load "$CONFIG_FILE"
102
+ }
103
+
104
+ ## Save the associative array back to a file
105
+ ## NOTE: Normally there is no need to call this function, it is called as needed
106
+ config_save() {
107
+ ini_save "$CONFIG_FILE"
108
+ }
@@ -0,0 +1,110 @@
1
+ ## INI functions [@bashly-upgrade ini]
2
+ ## This file is a part of Bashly standard library
3
+ ##
4
+ ## Usage:
5
+ ##
6
+ ## - In your script, call `ini_load path/to/config.ini`.
7
+ ## - A global associative array named `ini` will become available to you,
8
+ ## - When updating any of the associative array's values, call
9
+ ## `ini_save path/to/config.ini` to save the data.
10
+ ## - INI sections are optional.
11
+ ##
12
+ ## Get a value:
13
+ ##
14
+ ## ${ini[section1.key1]} # for keys under a [section]
15
+ ## ${ini[key1]} # for keys not under a [section]
16
+ ## ${ini[key1]:-default} # get a default value if the INI key is unset
17
+ ##
18
+ ## Update/create a value:
19
+ ##
20
+ ## ini[section1.key1]="value"
21
+ ## ini_save path/to/config.ini
22
+ ##
23
+ ## Delete a value
24
+ ##
25
+ ## unset ini[section1.key1]
26
+ ## ini_save path/to/config.ini
27
+ ##
28
+
29
+ ## Load an INI file and populate the associative array `ini`.
30
+ ini_load() {
31
+ declare -gA ini
32
+
33
+ local ini_file="$1"
34
+
35
+ local section=""
36
+ local key=""
37
+ local value=""
38
+ local section_regex="^\[(.+)\]"
39
+ local key_regex="^([^ =]+) *= *(.*) *$"
40
+ local comment_regex="^;"
41
+
42
+ while IFS= read -r line; do
43
+ if [[ $line =~ $comment_regex ]]; then
44
+ continue
45
+ elif [[ $line =~ $section_regex ]]; then
46
+ section="${BASH_REMATCH[1]}."
47
+ elif [[ $line =~ $key_regex ]]; then
48
+ key="${BASH_REMATCH[1]}"
49
+ value="${BASH_REMATCH[2]}"
50
+ ini["${section}${key}"]="$value"
51
+ fi
52
+ done <"$ini_file"
53
+ }
54
+
55
+ ## Save the associative array `ini` back to a file
56
+ ini_save() {
57
+ declare -gA ini
58
+
59
+ local ini_file="$1"
60
+
61
+ local current_section=""
62
+ local has_free_keys=false
63
+
64
+ rm -f "$ini_file"
65
+
66
+ for key in $(ini_keys); do
67
+ [[ $key == *.* ]] && continue
68
+ has_free_keys=true
69
+ value="${ini[$key]}"
70
+ echo "$key = $value" >>"$ini_file"
71
+ done
72
+
73
+ [[ "${has_free_keys}" == "true" ]] && echo >>"$ini_file"
74
+
75
+ for key in $(ini_keys); do
76
+ [[ $key == *.* ]] || continue
77
+ value="${ini[$key]}"
78
+ IFS="." read -r section_name key_name <<<"$key"
79
+
80
+ if [[ "$current_section" != "$section_name" ]]; then
81
+ [[ $current_section ]] && echo >>"$ini_file"
82
+ echo "[$section_name]" >>"$ini_file"
83
+ current_section="$section_name"
84
+ fi
85
+
86
+ echo "$key_name = $value" >>"$ini_file"
87
+ done
88
+ }
89
+
90
+ ## Show all loaded key-value pairs
91
+ ini_show() {
92
+ declare -gA ini
93
+
94
+ for key in $(ini_keys); do
95
+ echo "$key = ${ini[$key]}"
96
+ done
97
+ }
98
+
99
+ ## Get an array of all keys:
100
+ ##
101
+ ## for key in $(ini_keys); do
102
+ ## echo "- $key = ${ini[$key]}";
103
+ ## done
104
+ ##
105
+ ini_keys() {
106
+ declare -gA ini
107
+
108
+ local keys=("${!ini[@]}")
109
+ for a in "${keys[@]}"; do echo "$a"; done | sort
110
+ }
@@ -20,10 +20,12 @@ completions_yaml:
20
20
  handler: Bashly::Libraries::CompletionsYAML
21
21
 
22
22
  config:
23
- help: Add standard functions for handling INI files to the lib directory.
23
+ help: Add functions for handling INI configuration files to the lib directory.
24
24
  files:
25
25
  - source: "config/config.sh"
26
26
  target: "%{user_lib_dir}/config.%{user_ext}"
27
+ - source: "ini/ini.sh"
28
+ target: "%{user_lib_dir}/ini.%{user_ext}"
27
29
 
28
30
  help:
29
31
  help: Add a help command, in addition to the standard --help flag.
@@ -39,6 +41,12 @@ hooks:
39
41
  - source: "hooks/after.sh"
40
42
  target: "%{user_source_dir}/after.%{user_ext}"
41
43
 
44
+ ini:
45
+ help: Add low level functions for reading/writing INI files to the lib directory.
46
+ files:
47
+ - source: "ini/ini.sh"
48
+ target: "%{user_lib_dir}/ini.%{user_ext}"
49
+
42
50
  lib:
43
51
  help: |-
44
52
  Create the lib directory for any additional user scripts.
@@ -18,9 +18,15 @@ config_path: "%{source_dir}/bashly.yml"
18
18
  # The path to use for creating the bash script
19
19
  target_dir: .
20
20
 
21
- # The path to use for common library files, relative to the source dir
21
+ # The path to use for common library files, relative to source_dir
22
22
  lib_dir: lib
23
23
 
24
+ # The path to use for command files, relative to source_dir
25
+ # When set to nil (~), command files will be placed directly under source_dir
26
+ # When set to any other string, command files will be placed under this
27
+ # directory, and each command will get its own subdirectory
28
+ commands_dir: ~
29
+
24
30
  # Configure the bash options that will be added to the initialize function:
25
31
  # strict: true Bash strict mode (set -euo pipefail)
26
32
  # strict: false Only exit on errors (set -e)
@@ -14,7 +14,7 @@ module Bashly
14
14
  end
15
15
 
16
16
  def config
17
- @config ||= YAML.properly_load_file config_path
17
+ @config ||= YAML.load_file config_path
18
18
  end
19
19
 
20
20
  def libraries
@@ -13,7 +13,7 @@ module Bashly
13
13
  private
14
14
 
15
15
  def values!
16
- defaults = YAML.properly_load_file asset('libraries/strings/strings.yml')
16
+ defaults = YAML.load_file asset('libraries/strings/strings.yml')
17
17
  defaults.merge project_strings
18
18
  end
19
19
 
@@ -23,7 +23,7 @@ module Bashly
23
23
 
24
24
  def project_strings!
25
25
  if File.exist? project_strings_path
26
- YAML.properly_load_file project_strings_path
26
+ YAML.load_file project_strings_path
27
27
  else
28
28
  {}
29
29
  end
@@ -22,7 +22,7 @@ module ComposeRefinements
22
22
  end
23
23
 
24
24
  def safe_load_yaml(path)
25
- loaded = YAML.properly_load_file path
25
+ loaded = YAML.load_erb_file path
26
26
  return loaded if loaded.is_a?(Array) || loaded.is_a?(Hash)
27
27
 
28
28
  raise Bashly::ConfigurationError, "Cannot find a valid YAML in g`#{path}`"
@@ -159,10 +159,10 @@ module Bashly
159
159
  options['examples'].is_a?(Array) ? options['examples'] : [options['examples']]
160
160
  end
161
161
 
162
- # Returns the bash filename that is expected to hold the user code
163
- # for this command
162
+ # Returns the filename that is expected to hold the user code for this
163
+ # command
164
164
  def filename
165
- options['filename'] || "#{action_name.to_underscore}_command.#{Settings.partials_extension}"
165
+ options['filename'] || implicit_filename
166
166
  end
167
167
 
168
168
  # Returns an array of Flags
@@ -314,6 +314,18 @@ module Bashly
314
314
  def whitelisted_flags
315
315
  flags.select(&:allowed)
316
316
  end
317
+
318
+ private
319
+
320
+ # Returns either a flat filename (docker_status_command.sh) or a nested
321
+ # path (commands/docker/status.sh)
322
+ def implicit_filename
323
+ if Settings.commands_dir
324
+ "#{Settings.commands_dir}/#{action_name.to_path}.#{Settings.partials_extension}"
325
+ else
326
+ "#{action_name.to_underscore}_command.#{Settings.partials_extension}"
327
+ end
328
+ end
317
329
  end
318
330
  end
319
331
  end
@@ -4,6 +4,7 @@ module Bashly
4
4
  include AssetHelper
5
5
 
6
6
  attr_writer(
7
+ :commands_dir,
7
8
  :compact_short_flags,
8
9
  :config_path,
9
10
  :lib_dir,
@@ -15,6 +16,10 @@ module Bashly
15
16
  :usage_colors
16
17
  )
17
18
 
19
+ def commands_dir
20
+ @commands_dir ||= get :commands_dir
21
+ end
22
+
18
23
  def compact_short_flags
19
24
  @compact_short_flags ||= get :compact_short_flags
20
25
  end
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = '1.0.6'
2
+ VERSION = '1.0.8'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashly
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-27 00:00:00.000000000 Z
11
+ date: 2023-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -114,6 +114,26 @@ dependencies:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
116
  version: '1.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: psych
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 3.3.2
124
+ - - "<"
125
+ - !ruby/object:Gem::Version
126
+ version: '7'
127
+ type: :runtime
128
+ prerelease: false
129
+ version_requirements: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: 3.3.2
134
+ - - "<"
135
+ - !ruby/object:Gem::Version
136
+ version: '7'
117
137
  description: Generate bash command line tools using YAML configuration
118
138
  email: db@dannyben.com
119
139
  executables:
@@ -164,6 +184,7 @@ files:
164
184
  - lib/bashly/libraries/hooks/after.sh
165
185
  - lib/bashly/libraries/hooks/before.sh
166
186
  - lib/bashly/libraries/hooks/initialize.sh
187
+ - lib/bashly/libraries/ini/ini.sh
167
188
  - lib/bashly/libraries/lib/sample_function.sh
168
189
  - lib/bashly/libraries/libraries.yml
169
190
  - lib/bashly/libraries/settings/settings.yml
@@ -253,7 +274,7 @@ metadata:
253
274
  homepage_uri: https://bashly.dannyb.co/
254
275
  source_code_uri: https://github.com/DannyBen/bashly
255
276
  rubygems_mfa_required: 'true'
256
- post_install_message:
277
+ post_install_message:
257
278
  rdoc_options: []
258
279
  require_paths:
259
280
  - lib
@@ -268,8 +289,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
289
  - !ruby/object:Gem::Version
269
290
  version: '0'
270
291
  requirements: []
271
- rubygems_version: 3.4.14
272
- signing_key:
292
+ rubygems_version: 3.4.18
293
+ signing_key:
273
294
  specification_version: 4
274
295
  summary: Bash Command Line Tool Generator
275
296
  test_files: []