bashly 1.1.3 → 1.1.5

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: 44036d2bc4aabc216e7d60a788bfce201f71ad8230f4b44df5cb9d201500a0a5
4
- data.tar.gz: 30a1fb4efdafb7c305f0b1f1dcb38eaf8e05ed4a613b73c2ebd501cfe319bde7
3
+ metadata.gz: 17cea196efbe1bc65a6639258fe902503b75656c6a759ea5434a12d6a53d4529
4
+ data.tar.gz: 5e86d08e594250889bc351d5d6113bcfc40f8ec04ba39f72a7f19eec8329c7af
5
5
  SHA512:
6
- metadata.gz: 78109f5a7b1273746d0db4dfcce037862ee9964333c001b4db5bec3997074ec70aab849e7783c12cf1337b4c5086747e8591c94ed9d52e612bf1e281cdfff772
7
- data.tar.gz: 141f6ad7bf8a1a932f8d76774737dde4ef61f7222adc48c3932eba460d187dde4a194e9ee5771b3136bd699410e50874ecaa2f668a51684662c506f33013820c
6
+ metadata.gz: ade5312408fc08533dc6992673744920e941e142c09c9f05e58e66a08a6dfccfab100707cee319cb2ec388e60f9a73ae8ff735e8217c8f91820fc5e2e22af886
7
+ data.tar.gz: cf7f6da0438551ba2a10ed5c224d7ad6ac6b02d8675dca57c8ac01eb465e705a19bd2c3d1812b61b54ab52a433b5ce228b7f3b579e9de24f71c6f512caad1202
@@ -4,7 +4,7 @@ require 'tty-markdown'
4
4
  module Bashly
5
5
  module Commands
6
6
  class Render < Base
7
- help 'Render the bashly data structure using cutsom templates'
7
+ help 'Render the bashly data structure using custom templates'
8
8
 
9
9
  usage 'bashly render SOURCE TARGET [--watch --show PATH]'
10
10
  usage 'bashly render SOURCE --about'
@@ -31,7 +31,7 @@ module Bashly
31
31
  return unless of
32
32
 
33
33
  value.each_with_index do |val, i|
34
- send "assert_#{of}".to_sym, "#{key}[#{i}]", val
34
+ send :"assert_#{of}", "#{key}[#{i}]", val
35
35
  end
36
36
  end
37
37
 
@@ -91,16 +91,25 @@ module Bashly
91
91
  assert_hash key, value, keys: Script::Argument.option_keys
92
92
  assert_string "#{key}.name", value['name']
93
93
  assert_optional_string "#{key}.help", value['help']
94
- assert_optional_string "#{key}.default", value['default']
94
+ assert_string_or_array "#{key}.default", value['default']
95
95
  assert_optional_string "#{key}.validate", value['validate']
96
96
  assert_boolean "#{key}.required", value['required']
97
97
  assert_boolean "#{key}.repeatable", value['repeatable']
98
+ assert_boolean "#{key}.unique", value['unique']
98
99
 
99
100
  assert_array "#{key}.allowed", value['allowed'], of: :string
100
101
 
101
102
  refute value['name'].match(/^-/), "#{key}.name must not start with '-'"
102
103
 
103
104
  refute value['required'] && value['default'], "#{key} cannot have both nub`required` and nub`default`"
105
+
106
+ if value['unique']
107
+ assert value['repeatable'], "#{key}.unique does not make sense without nub`repeatable`"
108
+ end
109
+
110
+ if value['default'].is_a? Array
111
+ assert value['repeatable'], "#{key}.default array does not make sense without nub`repeatable`"
112
+ end
104
113
  end
105
114
 
106
115
  def assert_flag(key, value)
@@ -113,11 +122,12 @@ module Bashly
113
122
  assert_optional_string "#{key}.short", value['short']
114
123
  assert_optional_string "#{key}.help", value['help']
115
124
  assert_optional_string "#{key}.arg", value['arg']
116
- assert_optional_string "#{key}.default", value['default']
125
+ assert_string_or_array "#{key}.default", value['default']
117
126
  assert_optional_string "#{key}.validate", value['validate']
118
127
 
119
128
  assert_boolean "#{key}.private", value['private']
120
129
  assert_boolean "#{key}.repeatable", value['repeatable']
130
+ assert_boolean "#{key}.unique", value['unique']
121
131
  assert_boolean "#{key}.required", value['required']
122
132
  assert_array "#{key}.allowed", value['allowed'], of: :string
123
133
  assert_array "#{key}.conflicts", value['conflicts'], of: :string
@@ -140,6 +150,15 @@ module Bashly
140
150
  if value['completions']
141
151
  assert value['arg'], "#{key}.completions does not make sense without nub`arg`"
142
152
  end
153
+
154
+ if value['unique']
155
+ assert value['arg'] && value['repeatable'],
156
+ "#{key}.unique does not make sense without nub`arg` and nub`repeatable`"
157
+ end
158
+
159
+ if value['default'].is_a? Array
160
+ assert value['repeatable'], "#{key}.default array does not make sense without nub`repeatable`"
161
+ end
143
162
  end
144
163
 
145
164
  def assert_env_var(key, value)
@@ -149,6 +168,9 @@ module Bashly
149
168
  assert_optional_string "#{key}.default", value['default']
150
169
  assert_boolean "#{key}.required", value['required']
151
170
  assert_boolean "#{key}.private", value['private']
171
+ assert_array "#{key}.allowed", value['allowed'], of: :string
172
+
173
+ refute value['required'] && value['default'], "#{key} cannot have both nub`required` and nub`default`"
152
174
  end
153
175
 
154
176
  def assert_command(key, value)
@@ -201,6 +223,16 @@ module Bashly
201
223
  refute repeatable_arg, "#{key}.catch_all makes no sense with repeatable arg (#{repeatable_arg})"
202
224
  end
203
225
 
226
+ if value['args']
227
+ repeatable_args = value['args'].count { |a| a['repeatable'] }
228
+ assert repeatable_args < 2, "#{key}.args cannot have more than one repeatable args"
229
+
230
+ if repeatable_args == 1
231
+ assert value['args'].last['repeatable'],
232
+ "#{key}.args cannot contain a repeatable arg unless it is the last one"
233
+ end
234
+ end
235
+
204
236
  if value['expose']
205
237
  assert value['commands'], "#{key}.expose makes no sense without nub`commands`"
206
238
  end
@@ -41,9 +41,10 @@ flag.arg:
41
41
  url: https://bashly.dannyb.co/configuration/flag/#arg
42
42
  example: |-
43
43
  flags:
44
- - long: --ssh
45
- short: -s
46
- help: Clone using SSH
44
+ - long: --user
45
+ short: -u
46
+ arg: name
47
+ help: Specify the user name
47
48
 
48
49
  flag.completions:
49
50
  help: Specify a list of additional completion suggestions when used in conjunction with `bashly add completions`. Must be accompanied by `arg`.
@@ -161,6 +162,17 @@ flag.short:
161
162
  arg: name
162
163
  help: Repository user name
163
164
 
165
+ flag.unique:
166
+ help: Specify that the arguments provided by this repeatable flag must be unique. When this is set to `true`, non-unique values will be ignored.
167
+ url: https://bashly.dannyb.co/configuration/flag/#unique
168
+ example: |-
169
+ flags:
170
+ - long: --path
171
+ arg: location
172
+ help: Set one or more paths
173
+ repeatable: true
174
+ unique: true
175
+
164
176
  flag.validate:
165
177
  help: Apply custom validation functions. Must be accompanied by `arg`.
166
178
 
@@ -34,5 +34,6 @@ missing_required_environment_variable: "missing required environment variable: %
34
34
  missing_dependency: "missing dependency: %{dependency}"
35
35
  disallowed_flag: "%{name} must be one of: %{allowed}"
36
36
  disallowed_argument: "%{name} must be one of: %{allowed}"
37
+ disallowed_environment_variable: "%{name} environment variable must be one of: %{allowed}"
37
38
  unsupported_bash_version: "bash version 4 or higher is required"
38
39
  validation_error: "validation error in %s:\\n%s"
@@ -1,4 +1,4 @@
1
- require 'date' # for use by template render scripts
1
+ require 'date' # for use by template render scripts
2
2
  require 'colsole'
3
3
 
4
4
  module Bashly
@@ -1,14 +1,26 @@
1
+ require 'shellwords'
2
+
1
3
  module Bashly
2
4
  module Script
3
5
  class Argument < Base
4
6
  class << self
5
7
  def option_keys
6
8
  @option_keys ||= %i[
7
- allowed default help name repeatable required validate
9
+ allowed default help name repeatable required unique validate
8
10
  ]
9
11
  end
10
12
  end
11
13
 
14
+ def default_string
15
+ if default.is_a?(Array)
16
+ Shellwords.shelljoin default
17
+ elsif default.is_a?(String) && repeatable
18
+ Shellwords.shellescape default
19
+ else
20
+ default
21
+ end
22
+ end
23
+
12
24
  def usage_string
13
25
  required ? label : "[#{label}]"
14
26
  end
@@ -327,6 +327,11 @@ module Bashly
327
327
  args.select(&:allowed)
328
328
  end
329
329
 
330
+ # Returns an array of all the environemnt_variables with a whitelist arg
331
+ def whitelisted_environment_variables
332
+ environment_variables.select(&:allowed)
333
+ end
334
+
330
335
  # Returns an array of all the flags with a whitelist arg
331
336
  def whitelisted_flags
332
337
  flags.select(&:allowed)
@@ -3,7 +3,7 @@ module Bashly
3
3
  class EnvironmentVariable < Base
4
4
  class << self
5
5
  def option_keys
6
- @option_keys ||= %i[default help name required private]
6
+ @option_keys ||= %i[allowed default help name required private]
7
7
  end
8
8
  end
9
9
 
@@ -7,7 +7,7 @@ module Bashly
7
7
  def option_keys
8
8
  @option_keys ||= %i[
9
9
  allowed arg completions conflicts default help long repeatable
10
- required short validate private
10
+ required short unique validate private
11
11
  ]
12
12
  end
13
13
  end
@@ -22,6 +22,16 @@ module Bashly
22
22
  end
23
23
  end
24
24
 
25
+ def default_string
26
+ if default.is_a?(Array)
27
+ Shellwords.shelljoin default
28
+ elsif default.is_a?(String) && repeatable
29
+ Shellwords.shellescape default
30
+ else
31
+ default
32
+ end
33
+ end
34
+
25
35
  def name
26
36
  long || short
27
37
  end
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = '1.1.3'
2
+ VERSION = '1.1.5'
3
3
  end
@@ -8,7 +8,11 @@ if allowed
8
8
  end
9
9
 
10
10
  if default
11
- > printf " {{ strings[:default] % { value: default } }}\n"
11
+ if default.is_a? Array
12
+ > printf " {{ strings[:default] % { value: default.join(', ') } }}\n"
13
+ else
14
+ > printf " {{ strings[:default] % { value: default } }}\n"
15
+ end
12
16
  end
13
17
 
14
18
  > echo
@@ -2,11 +2,11 @@ if default_args.any? or default_flags.any?
2
2
  = view_marker
3
3
 
4
4
  default_args.each do |arg|
5
- > [[ -n ${args['{{ arg.name }}']:-} ]] || args['{{ arg.name }}']="{{ arg.default }}"
5
+ > [[ -n ${args['{{ arg.name }}']:-} ]] || args['{{ arg.name }}']="{{ arg.default_string }}"
6
6
  end
7
7
 
8
8
  default_flags.each do |flag|
9
- > [[ -n ${args['{{ flag.name }}']:-} ]] || args['{{ flag.name }}']="{{ flag.default }}"
9
+ > [[ -n ${args['{{ flag.name }}']:-} ]] || args['{{ flag.name }}']="{{ flag.default_string }}"
10
10
  end
11
11
 
12
12
  >
@@ -1,13 +1,26 @@
1
- if default_environment_variables.any? or required_environment_variables.any?
2
- = view_marker
1
+ if environment_variables.any?
2
+ = view_marker
3
3
  = render(:environment_variables_default)
4
4
 
5
- if required_environment_variables.any?
6
- required_environment_variables.each do |env_var|
7
- > if [[ -z "${<%= env_var.name.upcase %>:-}" ]]; then
8
- > printf "{{ strings[:missing_required_environment_variable] % { var: env_var.name.upcase } }}\n" >&2
9
- > exit 1
10
- > fi
11
- end
5
+ environment_variables.each do |env_var|
6
+ > env_var_names+=("{{ env_var.name.upcase }}")
12
7
  end
13
- end
8
+ end
9
+
10
+ if required_environment_variables.any?
11
+ required_environment_variables.each do |env_var|
12
+ > if [[ -z "${<%= env_var.name.upcase %>:-}" ]]; then
13
+ > printf "{{ strings[:missing_required_environment_variable] % { var: env_var.name.upcase } }}\n" >&2
14
+ > exit 1
15
+ > fi
16
+ end
17
+ end
18
+
19
+ if whitelisted_environment_variables.any?
20
+ whitelisted_environment_variables.each do |env_var|
21
+ > if [[ -n "${<%= env_var.name.upcase %>:-}" ]] && [[ ! ${<%= env_var.name.upcase %>:-} =~ ^({{ env_var.allowed.join '|' }})$ ]]; then
22
+ > printf "%s\n" "{{ strings[:disallowed_environment_variable] % { name: env_var.name.upcase, allowed: env_var.allowed.join(', ') } }}" >&2
23
+ > exit 1
24
+ > fi
25
+ end
26
+ end
@@ -4,7 +4,9 @@
4
4
  > if ((${#args[@]})); then
5
5
  > readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
6
6
  > echo args:
7
- > for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done
7
+ > for k in "${sorted_keys[@]}"; do
8
+ > echo "- \${args[$k]} = ${args[$k]}"
9
+ > done
8
10
  > else
9
11
  > echo args: none
10
12
  > fi
@@ -22,8 +24,18 @@
22
24
  > readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort)
23
25
  > echo
24
26
  > echo deps:
25
- > for k in "${sorted_keys[@]}"; do echo "- \${deps[$k]} = ${deps[$k]}"; done
27
+ > for k in "${sorted_keys[@]}"; do
28
+ > echo "- \${deps[$k]} = ${deps[$k]}"
29
+ > done
26
30
  > fi
27
31
  >
32
+ > if ((${#env_var_names[@]})); then
33
+ > readarray -t sorted_names < <(printf '%s\n' "${env_var_names[@]}" | sort)
34
+ > echo
35
+ > echo "environment variables:"
36
+ > for k in "${sorted_names[@]}"; do
37
+ > echo "- \$$k = ${!k:-}"
38
+ > done
39
+ > fi
28
40
  > }
29
41
  >
@@ -7,9 +7,17 @@ args.each do |arg|
7
7
  if arg.repeatable
8
8
  > args['{{ arg.name }}']="\"$1\""
9
9
  > shift
10
- > else
11
- > args['{{ arg.name }}']="${args[{{ arg.name }}]} \"$1\""
12
- > shift
10
+ if arg.unique
11
+ > elif [[ ! "${args['{{ arg.name }}']}" =~ \"$1\" ]]; then
12
+ > args['{{ arg.name }}']="${args[{{ arg.name }}]} \"$1\""
13
+ > shift
14
+ > else
15
+ > shift
16
+ else
17
+ > else
18
+ > args['{{ arg.name }}']="${args[{{ arg.name }}]} \"$1\""
19
+ > shift
20
+ end
13
21
 
14
22
  else
15
23
  > args['{{ arg.name }}']=$1
@@ -4,6 +4,7 @@
4
4
  > declare -A args=()
5
5
  > declare -A deps=()
6
6
  > declare -a other_args=()
7
+ > declare -a env_var_names=()
7
8
  > declare -a input=()
8
9
  > normalize_input "$@"
9
10
  > parse_requirements "${input[@]}"
@@ -3,6 +3,10 @@
3
3
  > printf " %s\n" "{{ usage_string(extended: true).color(:environment_variable) }}"
4
4
  > printf "{{ help.wrap(76).indent(4).sanitize_for_print }}\n"
5
5
 
6
+ if allowed
7
+ > printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
8
+ end
9
+
6
10
  if default
7
11
  > printf " {{ strings[:default] % { value: default } }}\n"
8
12
  end
@@ -6,8 +6,12 @@
6
6
  if repeatable
7
7
  > if [[ -z ${args['{{ name }}']+x} ]]; then
8
8
  > args['{{ name }}']="\"$2\""
9
- > else
10
- > args['{{ name }}']="${args[{{ name }}]} \"$2\""
9
+ if unique
10
+ > elif [[ ! "${args['{{ name }}']}" =~ \"$2\" ]]; then
11
+ else
12
+ > else
13
+ end
14
+ > args['{{ name }}']="${args['{{ name }}']} \"$2\""
11
15
  > fi
12
16
 
13
17
  else
@@ -4,11 +4,15 @@
4
4
  > printf "{{ help.wrap(76).indent(4).sanitize_for_print }}\n"
5
5
 
6
6
  if allowed
7
- > printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
7
+ > printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
8
8
  end
9
9
 
10
10
  if default
11
- > printf " {{ strings[:default] % { value: default } }}\n"
11
+ if default.is_a? Array
12
+ > printf " {{ strings[:default] % { value: default.join(', ') } }}\n"
13
+ else
14
+ > printf " {{ strings[:default] % { value: default } }}\n"
15
+ end
12
16
  end
13
17
 
14
18
  > echo
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.1.3
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-25 00:00:00.000000000 Z
11
+ date: 2023-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole