bashly 0.8.6 → 0.8.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: 6be5a0594215515e99372cba7e1f6b0a6540429299166e9a2f420d14181af207
4
- data.tar.gz: 91498eb6c640f0eb57f68aa974e876a69d624e9830402f10d11f5de874f6684c
3
+ metadata.gz: 4d91ebd35f74173621d545d29ff7ea404341638c7b06aa0610cb1ab10dfba93a
4
+ data.tar.gz: 81b1516fd118e2f985d5fd6b88cfa07db8f3b01eb91895d069587de26586bb1d
5
5
  SHA512:
6
- metadata.gz: f77887a91b45dcba6422d48fc794cd8bc8c50243a6b04df3bd426aa90b837beb53b1a770adf903482a85ad60631c6515f21f6559045aa73475b9321d5432c13e
7
- data.tar.gz: 8c05eba6921abcf365c6ab4df5f8632f7136749274708361dfb6dcf6e5a85b9b55c267d65adadb3ed77677fe9a94293a7259e86789e0a754c3ba461118c9701d
6
+ metadata.gz: f366a6add6ae9c750f07c219393f613dc381e7ade0f18e94fef716364fbcecdbcac7cb8f5cdaf2101ea2c2f0040dab72303e740d87508750f627b71e4dbca39f
7
+ data.tar.gz: 3327229305d123a6ea878846035fb4fbb0e33a6d7f6fd81ee3e203b1c89cd29d36cc36822908c31faa5fa97edba98a69db941fece386849aeafbdfef4cdea978
data/README.md CHANGED
@@ -70,10 +70,12 @@ If you experience any issue, have a question or a suggestion, or if you wish
70
70
  to contribute, feel free to [open an issue][issues] or
71
71
  [start a discussion][discussions].
72
72
 
73
+ Visit the *[How to contribute][contributing]* page for more information.
74
+
73
75
 
74
76
 
75
77
  [issues]: https://github.com/DannyBen/bashly/issues
76
78
  [discussions]: https://github.com/DannyBen/bashly/discussions
77
79
  [docs]: https://bashly.dannyb.co/
78
80
  [examples]: https://github.com/DannyBen/bashly/tree/master/examples#bashly-examples
79
-
81
+ [contributing]: https://github.com/DannyBen/bashly/blob/master/CONTRIBUTING.md#how-to-contribute
@@ -112,7 +112,7 @@ module Bashly
112
112
  assert_hash key, value, Script::Command.option_keys
113
113
 
114
114
  refute value['commands'] && value['args'], "#{key} cannot have both commands and args"
115
- refute value['commands'] && value['flags'], "#{key} cannot have both commands and flags"
115
+ refute value['commands'] && value['catch_all'], "#{key} cannot have both commands and catch_all"
116
116
 
117
117
  assert_string "#{key}.name", value['name']
118
118
  assert_optional_string "#{key}.help", value['help']
@@ -142,6 +142,10 @@ module Bashly
142
142
  assert_uniq "#{key}.flags", value['flags'], 'short'
143
143
  assert_uniq "#{key}.args", value['args'], 'name'
144
144
 
145
+ if value['default']
146
+ assert value['args'], "#{key}.default makes no sense without args"
147
+ end
148
+
145
149
  if value['catch_all'] and value['args']
146
150
  repeatable_arg = value['args'].select { |a| a['repeatable'] }.first&.dig 'name'
147
151
  refute repeatable_arg, "#{key}.catch_all makes no sense with repeatable arg (#{repeatable_arg})"
@@ -177,6 +177,12 @@ module Bashly
177
177
  parents.any? ? (parents + [name]).join(' ') : name
178
178
  end
179
179
 
180
+ # Returns true if this command's flags should be considered as gloal
181
+ # flags, and cascade to subcommands
182
+ def global_flags?
183
+ flags.any? and commands.any?
184
+ end
185
+
180
186
  # Returns the string for the group caption
181
187
  def group_string
182
188
  if group
@@ -186,6 +192,19 @@ module Bashly
186
192
  end
187
193
  end
188
194
 
195
+ # Returns a mode identifier
196
+ def mode
197
+ @mode ||= begin
198
+ if global_flags? then :global_flags
199
+ elsif commands.any? then :commands
200
+ elsif args.any? and flags.any? then :args_and_flags
201
+ elsif args.any? then :args
202
+ elsif flags.any? then :flags
203
+ else :empty
204
+ end
205
+ end
206
+ end
207
+
189
208
  # Returns an array of all parents. For example, the command
190
209
  # "docker container run" will have [docker, container] as its parents
191
210
  def parents
@@ -239,13 +258,23 @@ module Bashly
239
258
  # Returns a constructed string suitable for Usage pattern
240
259
  def usage_string
241
260
  result = [full_name]
242
- result << "[command]" if commands.any?
243
- args.each do |arg|
244
- result << arg.usage_string
261
+
262
+ result.push case mode
263
+ when :global_flags then ["[OPTIONS]", "COMMAND"]
264
+ when :commands then ["COMMAND"]
265
+ when :args_and_flags then usage_string_args + ["[OPTIONS]"]
266
+ when :args then usage_string_args
267
+ when :flags then ["[OPTIONS]"]
268
+ else nil
245
269
  end
246
- result << "[options]" unless flags.empty?
247
- result << catch_all.usage_string if catch_all.enabled?
248
- result.join " "
270
+
271
+ result.push catch_all.usage_string if catch_all.enabled? && commands.empty?
272
+ result.compact.join " "
273
+ end
274
+
275
+ # Returns an array of args usage_string for the command's usage_string
276
+ def usage_string_args
277
+ args.map { |arg| arg.usage_string }
249
278
  end
250
279
 
251
280
  # Returns an array of files to include as is inside the script
@@ -1,18 +1,21 @@
1
1
  module Bashly
2
2
  class Settings
3
3
  class << self
4
- attr_writer :source_dir, :target_dir, :lib_dir, :strict, :tab_indent
4
+ include AssetHelper
5
+
6
+ attr_writer :compact_short_flags, :source_dir, :target_dir,
7
+ :lib_dir, :strict, :tab_indent
5
8
 
6
9
  def source_dir
7
- @source_dir ||= get :source_dir, 'src'
10
+ @source_dir ||= get :source_dir
8
11
  end
9
12
 
10
13
  def target_dir
11
- @target_dir ||= get :target_dir, '.'
14
+ @target_dir ||= get :target_dir
12
15
  end
13
16
 
14
17
  def lib_dir
15
- @lib_dir ||= get :lib_dir, 'lib'
18
+ @lib_dir ||= get :lib_dir
16
19
  end
17
20
 
18
21
  def strict
@@ -23,8 +26,12 @@ module Bashly
23
26
  @tab_indent ||= get :tab_indent
24
27
  end
25
28
 
29
+ def compact_short_flags
30
+ @compact_short_flags ||= get :compact_short_flags
31
+ end
32
+
26
33
  def env
27
- @env ||= get(:env, :development)&.to_sym
34
+ @env ||= get(:env)&.to_sym
28
35
  end
29
36
 
30
37
  def env=(value)
@@ -41,14 +48,33 @@ module Bashly
41
48
 
42
49
  private
43
50
 
44
- def get(key, default = nil)
45
- ENV["BASHLY_#{key.upcase}"] || user_settings[key.to_s] || default
51
+ def get(key)
52
+ case env_value key
53
+ when nil then config[key.to_s]
54
+ when "0", "false", "no" then false
55
+ when "1", "true", "yes" then true
56
+ else env_value key
57
+ end
58
+ end
59
+
60
+ def env_value(key)
61
+ ENV["BASHLY_#{key.upcase}"]
62
+ end
63
+
64
+ def config
65
+ @config ||= defsult_settings.merge user_settings
46
66
  end
47
67
 
48
68
  def user_settings
49
- @user_settings ||= begin
50
- File.exist?('settings.yml') ? Config.new('settings.yml') : {}
51
- end
69
+ @user_settings ||= File.exist?('settings.yml') ? Config.new('settings.yml') : {}
70
+ end
71
+
72
+ def defsult_settings
73
+ @defsult_settings ||= Config.new(default_settings_path)
74
+ end
75
+
76
+ def default_settings_path
77
+ asset "templates/settings.yml"
52
78
  end
53
79
 
54
80
  end
@@ -1,6 +1,10 @@
1
1
  # All settings are optional (with their default values provided below), and
2
2
  # can also be set with an environment variable with the same name, capitalized
3
3
  # and prefixed by `BASHLY_` - for example: BASHLY_SOURCE_DIR
4
+ #
5
+ # When setting environment variables, you can use:
6
+ # - "0", "false" or "no" to represent false
7
+ # - "1", "true" or "yes" to represent true
4
8
 
5
9
  # The path containing the bashly configuration and source files
6
10
  source_dir: src
@@ -18,6 +22,10 @@ strict: false
18
22
  # (every 2 leading spaces will be converted to a tab character)
19
23
  tab_indent: false
20
24
 
25
+ # When true, the generated script will consider any argument in the form of
26
+ # `-abc` as if it is `-a -b -c`.
27
+ compact_short_flags: true
28
+
21
29
  # Set to 'production' or 'development':
22
30
  # - production generate a smaller script, without file markers
23
31
  # - development generate with file markers
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = "0.8.6"
2
+ VERSION = "0.8.8"
3
3
  end
@@ -3,7 +3,7 @@ if validate
3
3
  = view_marker
4
4
 
5
5
  > if [[ -n $(validate_{{ validate }} "$1") ]]; then
6
- > printf "{{ strings[:validation_error] }}\n" "{{ name.upcase }}" "$(validate_{{ validate }} "$1")"
6
+ > printf "{{ strings[:validation_error] }}\n" "{{ name.upcase }}" "$(validate_{{ validate }} "$1")" >&2
7
7
  > exit 1
8
8
  > fi
9
9
  >
@@ -2,7 +2,7 @@ if catch_all.required?
2
2
  = view_marker
3
3
 
4
4
  > if [[ ${#other_args[@]} -eq 0 ]]; then
5
- > printf "{{ strings[:missing_required_argument] % { arg: catch_all.label, usage: usage_string } }}\n"
5
+ > printf "{{ strings[:missing_required_argument] % { arg: catch_all.label, usage: usage_string } }}\n" >&2
6
6
  > exit 1
7
7
  > fi
8
8
  >
@@ -1,7 +1,7 @@
1
1
  = view_marker
2
2
 
3
3
  > "" )
4
- > {{ function_name }}_usage
4
+ > {{ function_name }}_usage >&2
5
5
  > exit 1
6
6
  > ;;
7
7
  >
@@ -18,7 +18,7 @@ elsif extensible.is_a? String
18
18
  > if [[ -x "$(command -v "{{ extensible }}")" ]]; then
19
19
  > exec {{ extensible }} "$@"
20
20
  > else
21
- > printf "{{ strings[:invalid_command] }}\n" "$action"
21
+ > printf "{{ strings[:invalid_command] }}\n" "$action" >&2
22
22
  > exit 1
23
23
  > fi
24
24
  >
@@ -28,13 +28,13 @@ elsif extensible
28
28
  > shift
29
29
  > exec "{{ function_name }}-$action" "$@"
30
30
  > else
31
- > printf "{{ strings[:invalid_command] }}\n" "$action"
31
+ > printf "{{ strings[:invalid_command] }}\n" "$action" >&2
32
32
  > exit 1
33
33
  > fi
34
34
  >
35
35
 
36
36
  else
37
- > printf "{{ strings[:invalid_command] }}\n" "$action"
37
+ > printf "{{ strings[:invalid_command] }}\n" "$action" >&2
38
38
  > exit 1
39
39
  > ;;
40
40
  >
@@ -3,7 +3,7 @@ if dependencies
3
3
 
4
4
  dependencies.each do |dependency|
5
5
  > if ! [[ -x "$(command -v {{ dependency }})" ]]; then
6
- > printf "{{ strings[:missing_dependency] % { dependency: dependency } }}\n"
6
+ > printf "{{ strings[:missing_dependency] % { dependency: dependency } }}\n" >&2
7
7
  > exit 1
8
8
  > fi
9
9
  end
@@ -0,0 +1,7 @@
1
+ if default_environment_variables.any?
2
+ = view_marker
3
+
4
+ default_environment_variables.each do |env_var|
5
+ > export {{ env_var.name.upcase }}="${<%= env_var.name.upcase %>:-<%= env_var.default %>}"
6
+ end
7
+ end
@@ -1,16 +1,11 @@
1
1
  if default_environment_variables.any? or required_environment_variables.any?
2
2
  = view_marker
3
-
4
- if default_environment_variables.any?
5
- default_environment_variables.each do |env_var|
6
- > export {{ env_var.name.upcase }}="${<%= env_var.name.upcase %>:-<%= env_var.default %>}"
7
- end
8
- end
3
+ = render(:environment_variables_default)
9
4
 
10
5
  if required_environment_variables.any?
11
6
  required_environment_variables.each do |env_var|
12
7
  > if [[ -z "${<%= env_var.name.upcase %>:-}" ]]; then
13
- > printf "{{ strings[:missing_required_environment_variable] % { var: env_var.name.upcase } }}\n"
8
+ > printf "{{ strings[:missing_required_environment_variable] % { var: env_var.name.upcase } }}\n" >&2
14
9
  > exit 1
15
10
  > fi
16
11
  end
@@ -16,5 +16,12 @@ end
16
16
  > exit
17
17
  > ;;
18
18
  >
19
+
20
+ if global_flags?
21
+ flags.each do |flag|
22
+ = flag.render(:case)
23
+ end
24
+ end
25
+
19
26
  > esac
20
27
  >
@@ -6,6 +6,10 @@
6
6
  > {{ Settings.strict ? "set -euo pipefail" : "set -e" }}
7
7
  >
8
8
 
9
+ if root_command?
10
+ = render(:environment_variables_default).indent 2
11
+ end
12
+
9
13
  = load_user_file("initialize.sh", placeholder: false).indent 2
10
14
 
11
15
  > }
@@ -11,11 +11,15 @@
11
11
  > elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then
12
12
  > input+=("${BASH_REMATCH[1]}")
13
13
  > input+=("${BASH_REMATCH[2]}")
14
+
15
+ if Settings.compact_short_flags
14
16
  > elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then
15
17
  > flags="${BASH_REMATCH[1]}"
16
18
  > for (( i=0 ; i < ${#flags} ; i++ )); do
17
19
  > input+=("-${flags:i:1}")
18
20
  > done
21
+ end
22
+
19
23
  > else
20
24
  > input+=("$arg")
21
25
  > fi
@@ -12,12 +12,12 @@ if args.any?
12
12
  end
13
13
 
14
14
  > else
15
- > printf "{{ strings[:invalid_argument] }}\n" "$key"
15
+ > printf "{{ strings[:invalid_argument] }}\n" "$key" >&2
16
16
  > exit 1
17
17
  > fi
18
18
 
19
19
  else
20
- > printf "{{ strings[:invalid_argument] }}\n" "$key"
20
+ > printf "{{ strings[:invalid_argument] }}\n" "$key" >&2
21
21
  > exit 1
22
22
 
23
23
  end
@@ -4,8 +4,10 @@
4
4
  > key="$1"
5
5
  > case "$key" in
6
6
 
7
- flags.each do |flag|
8
- = flag.render(:case).indent 2
7
+ unless global_flags?
8
+ flags.each do |flag|
9
+ = flag.render(:case).indent 2
10
+ end
9
11
  end
10
12
 
11
13
  >
@@ -17,7 +19,7 @@ if catch_all.enabled?
17
19
  > ;;
18
20
 
19
21
  else
20
- > printf "<%= strings[:invalid_flag] %>\n" "$key"
22
+ > printf "<%= strings[:invalid_flag] %>\n" "$key" >&2
21
23
  > exit 1
22
24
  > ;;
23
25
 
@@ -3,7 +3,7 @@ if required_args.any?
3
3
 
4
4
  required_args.each do |arg|
5
5
  > if [[ -z ${args[{{ arg.name }}]+x} ]]; then
6
- > printf "{{ strings[:missing_required_argument] % { arg: arg.name.upcase, usage: usage_string } }}\n"
6
+ > printf "{{ strings[:missing_required_argument] % { arg: arg.name.upcase, usage: usage_string } }}\n" >&2
7
7
  > exit 1
8
8
  > fi
9
9
  end
@@ -3,7 +3,7 @@ if required_flags.any?
3
3
 
4
4
  required_flags.each do |flag|
5
5
  > if [[ -z ${args[{{ flag.long }}]+x} ]]; then
6
- > printf "{{ strings[:missing_required_flag] % { usage: flag.usage_string } }}\n"
6
+ > printf "{{ strings[:missing_required_flag] % { usage: flag.usage_string } }}\n" >&2
7
7
  > exit 1
8
8
  > fi
9
9
  end
@@ -29,7 +29,7 @@ end
29
29
  > printf " {{ usage_string }}\n"
30
30
 
31
31
  if commands.any?
32
- > printf " {{ full_name }} [command] --help{{ " | -h" unless short_flag_exist? "-h" }}\n"
32
+ > printf " {{ full_name }} [COMMAND] --help{{ " | -h" unless short_flag_exist? "-h" }}\n"
33
33
  else
34
34
  > printf " {{ full_name }} --help{{ " | -h" unless short_flag_exist? "-h" }}\n"
35
35
  end
@@ -5,7 +5,7 @@ if filters
5
5
  filters.each do |filter|
6
6
  > filter_error=$(filter_{{ filter }})
7
7
  > if [[ -n $filter_error ]]; then
8
- > echo "$filter_error"
8
+ > echo "$filter_error" >&2
9
9
  > exit 1
10
10
  > fi
11
11
  >
@@ -6,14 +6,14 @@ if whitelisted_args.any? or whitelisted_flags.any?
6
6
  > eval "input_array=(${args[{{ arg.name }}]})"
7
7
  > for i in "${input_array[@]}"; do
8
8
  > if [[ ! $i =~ ^({{ arg.allowed.join '|' }})$ ]]; then
9
- > printf "%s\n" "{{ strings[:disallowed_argument] % { name: arg.name, allowed: arg.allowed.join(', ') } }}"
9
+ > printf "%s\n" "{{ strings[:disallowed_argument] % { name: arg.name, allowed: arg.allowed.join(', ') } }}" >&2
10
10
  > exit 1
11
11
  > fi
12
12
  > done
13
13
 
14
14
  else
15
15
  > if [[ ! ${args[{{ arg.name }}]} =~ ^({{ arg.allowed.join '|' }})$ ]]; then
16
- > printf "%s\n" "{{ strings[:disallowed_argument] % { name: arg.name, allowed: arg.allowed.join(', ') } }}"
16
+ > printf "%s\n" "{{ strings[:disallowed_argument] % { name: arg.name, allowed: arg.allowed.join(', ') } }}" >&2
17
17
  > exit 1
18
18
  > fi
19
19
 
@@ -25,14 +25,14 @@ if whitelisted_args.any? or whitelisted_flags.any?
25
25
  > eval "input_array=(${args[{{ flag.name }}]})"
26
26
  > for i in "${input_array[@]}"; do
27
27
  > if [[ ! $i =~ ^({{ flag.allowed.join '|' }})$ ]]; then
28
- > printf "%s\n" "{{ strings[:disallowed_flag] % { name: flag.name, allowed: flag.allowed.join(', ') } }}"
28
+ > printf "%s\n" "{{ strings[:disallowed_flag] % { name: flag.name, allowed: flag.allowed.join(', ') } }}" >&2
29
29
  > exit 1
30
30
  > fi
31
31
  > done
32
32
 
33
33
  else
34
34
  > if [[ ! ${args[{{ flag.name }}]} =~ ^({{ flag.allowed.join '|' }})$ ]]; then
35
- > printf "%s\n" "{{ strings[:disallowed_flag] % { name: flag.name, allowed: flag.allowed.join(', ') } }}"
35
+ > printf "%s\n" "{{ strings[:disallowed_flag] % { name: flag.name, allowed: flag.allowed.join(', ') } }}" >&2
36
36
  > exit 1
37
37
  > fi
38
38
 
@@ -18,7 +18,7 @@ end
18
18
  > shift
19
19
  > shift
20
20
  > else
21
- > printf "%s\n" "{{ strings[:flag_requires_an_argument] % { name: name, usage: usage_string } }}"
21
+ > printf "%s\n" "{{ strings[:flag_requires_an_argument] % { name: name, usage: usage_string } }}" >&2
22
22
  > exit 1
23
23
  > fi
24
24
  > ;;
@@ -4,7 +4,7 @@ if conflicts
4
4
 
5
5
  if conflicts.count == 1
6
6
  > if [[ -n "${args[{{ conflicts.first }}]:-}" ]]; then
7
- > printf "{{ strings[:conflicting_flags] }}\n" "$key" "{{ conflicts.first }}"
7
+ > printf "{{ strings[:conflicting_flags] }}\n" "$key" "{{ conflicts.first }}" >&2
8
8
  > exit 1
9
9
  > fi
10
10
  >
@@ -12,7 +12,7 @@ if conflicts
12
12
  else
13
13
  > for conflict in {{ conflicts.join ' ' }}; do
14
14
  > if [[ -n "${args[$conflict]:-}" ]]; then
15
- > printf "{{ strings[:conflicting_flags] }}\n" "$key" "$conflict"
15
+ > printf "{{ strings[:conflicting_flags] }}\n" "$key" "$conflict" >&2
16
16
  > exit 1
17
17
  > fi
18
18
  > done
@@ -3,7 +3,7 @@ if validate
3
3
  = view_marker
4
4
 
5
5
  > if [[ -n $(validate_{{ validate }} "$2") ]]; then
6
- > printf "{{ strings[:validation_error] }}\n" "{{ usage_string }}" "$(validate_{{ validate }} "$2")"
6
+ > printf "{{ strings[:validation_error] }}\n" "{{ usage_string }}" "$(validate_{{ validate }} "$2")" >&2
7
7
  > exit 1
8
8
  > fi
9
9
  >
@@ -1,7 +1,7 @@
1
1
  = view_marker
2
2
 
3
3
  > if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
4
- > printf "{{ strings[:unsupported_bash_version] }}\n"
4
+ > printf "{{ strings[:unsupported_bash_version] }}\n" >&2
5
5
  > exit 1
6
6
  > fi
7
7
  >
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: 0.8.6
4
+ version: 0.8.8
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: 2022-09-23 00:00:00.000000000 Z
11
+ date: 2022-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: completely
@@ -167,6 +167,7 @@ files:
167
167
  - lib/bashly/views/command/default_root_script.gtx
168
168
  - lib/bashly/views/command/default_script.gtx
169
169
  - lib/bashly/views/command/dependencies_filter.gtx
170
+ - lib/bashly/views/command/environment_variables_default.gtx
170
171
  - lib/bashly/views/command/environment_variables_filter.gtx
171
172
  - lib/bashly/views/command/fixed_flags_filter.gtx
172
173
  - lib/bashly/views/command/footer.gtx