bashly 0.7.6 → 0.7.9

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bashly/cli.rb +2 -1
  3. data/lib/bashly/commands/add.rb +1 -0
  4. data/lib/bashly/commands/base.rb +6 -0
  5. data/lib/bashly/commands/generate.rb +13 -1
  6. data/lib/bashly/commands/validate.rb +1 -3
  7. data/lib/bashly/concerns/renderable.rb +8 -1
  8. data/lib/bashly/config.rb +1 -1
  9. data/lib/bashly/config_validator.rb +35 -5
  10. data/lib/bashly/extensions/yaml.rb +10 -0
  11. data/lib/bashly/libraries/completions_function.rb +1 -1
  12. data/lib/bashly/libraries.yml +8 -8
  13. data/lib/bashly/library.rb +3 -2
  14. data/lib/bashly/message_strings.rb +2 -2
  15. data/lib/bashly/refinements/compose_refinements.rb +1 -1
  16. data/lib/bashly/script/argument.rb +13 -1
  17. data/lib/bashly/script/base.rb +7 -30
  18. data/lib/bashly/script/catch_all.rb +4 -0
  19. data/lib/bashly/script/command.rb +14 -8
  20. data/lib/bashly/script/environment_variable.rb +6 -0
  21. data/lib/bashly/script/flag.rb +9 -0
  22. data/lib/bashly/settings.rb +13 -1
  23. data/lib/bashly/version.rb +1 -1
  24. data/lib/bashly/views/argument/usage.erb +2 -2
  25. data/lib/bashly/views/argument/validations.erb +1 -1
  26. data/lib/bashly/views/command/catch_all_filter.erb +1 -1
  27. data/lib/bashly/views/command/command_fallback.erb +1 -1
  28. data/lib/bashly/views/command/command_filter.erb +1 -1
  29. data/lib/bashly/views/command/command_functions.erb +1 -1
  30. data/lib/bashly/views/command/default_assignments.erb +1 -1
  31. data/lib/bashly/views/command/dependencies_filter.erb +1 -1
  32. data/lib/bashly/views/command/environment_variables_filter.erb +1 -1
  33. data/lib/bashly/views/command/fixed_flags_filter.erb +3 -1
  34. data/lib/bashly/views/command/footer.erb +1 -0
  35. data/lib/bashly/views/command/function.erb +1 -1
  36. data/lib/bashly/views/command/initialize.erb +2 -2
  37. data/lib/bashly/views/command/inspect_args.erb +1 -1
  38. data/lib/bashly/views/command/master_script.erb +1 -0
  39. data/lib/bashly/views/command/normalize_input.erb +1 -1
  40. data/lib/bashly/views/command/parse_requirements.erb +1 -1
  41. data/lib/bashly/views/command/parse_requirements_case.erb +15 -3
  42. data/lib/bashly/views/command/parse_requirements_while.erb +1 -1
  43. data/lib/bashly/views/command/required_args_filter.erb +1 -1
  44. data/lib/bashly/views/command/required_flags_filter.erb +1 -1
  45. data/lib/bashly/views/command/root_command.erb +1 -1
  46. data/lib/bashly/views/command/run.erb +1 -1
  47. data/lib/bashly/views/command/usage.erb +1 -1
  48. data/lib/bashly/views/command/usage_args.erb +1 -1
  49. data/lib/bashly/views/command/usage_commands.erb +1 -1
  50. data/lib/bashly/views/command/usage_environment_variables.erb +1 -1
  51. data/lib/bashly/views/command/usage_examples.erb +1 -1
  52. data/lib/bashly/views/command/usage_fixed_flags.erb +1 -1
  53. data/lib/bashly/views/command/usage_flags.erb +1 -1
  54. data/lib/bashly/views/command/user_filter.erb +1 -1
  55. data/lib/bashly/views/command/user_lib.erb +2 -2
  56. data/lib/bashly/views/command/version_command.erb +1 -1
  57. data/lib/bashly/views/command/whitelist_filter.erb +21 -1
  58. data/lib/bashly/views/environment_variable/usage.erb +1 -1
  59. data/lib/bashly/views/flag/case.erb +1 -1
  60. data/lib/bashly/views/flag/conflicts.erb +1 -1
  61. data/lib/bashly/views/flag/usage.erb +1 -1
  62. data/lib/bashly/views/flag/validations.erb +1 -1
  63. data/lib/bashly/views/wrapper/bash3_bouncer.erb +1 -1
  64. data/lib/bashly/views/wrapper/header.erb +1 -1
  65. data/lib/bashly/views/wrapper/wrapper.erb +1 -1
  66. data/lib/bashly.rb +13 -0
  67. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98fc7fa0a703a1bdef30afdd0e4ff4b5a4d5cc6025380e4aa952aeb77c0b9aa8
4
- data.tar.gz: 2d148783f32363862d4039b424ef8ddd5fa050c849bbe742f7195096cdf78830
3
+ metadata.gz: 2ef923a576e9bb9e16ec9f78c96c6008772c77d3bfc9520299fc2dd3cd7f3dd3
4
+ data.tar.gz: 593393d64ca6e63216e0e974c580db50db754fe430d319115aef8610c47d39aa
5
5
  SHA512:
6
- metadata.gz: 309afb5a2c73c170fafacf9ab02066bd1e4d29934c6a94f6518328dbfd246a8679fc0e8ffc51e00a3359adc90cc25d1d9433e8944db7def0cf806ac5dd99d89d
7
- data.tar.gz: fd16952f25275a54d0aaaf990b00575a19fc5d38cab3206918722240466df9e1ae7f55f439ccfc1129ca5d8733181583fbd4280bf18cb42615119a9122f666d8
6
+ metadata.gz: 2b0ffb33c0c11b423cb59d594362a0c2c071a685a2ad7d4837cbdc3bb1d6a494bdcce8ff1cb3d19cfb0078ac5f167912a9d2f93c44f173d2821b415fe9cbd92e
7
+ data.tar.gz: c6b6989f3c75226641847feee4e4e8a73326da2a006bbbd52ce7544c7c4ffb3bf1f4a659a15f0b70f14590b1fe0392062099f6ced43134b2a3d81000d5a350f9
data/lib/bashly/cli.rb CHANGED
@@ -6,7 +6,8 @@ module Bashly
6
6
  class CLI
7
7
  def self.runner
8
8
  runner = MisterBin::Runner.new version: Bashly::VERSION,
9
- header: "Bashly - Bash CLI Generator"
9
+ header: "Bashly - Bash CLI Generator",
10
+ footer: "Help: !txtpur!bashly COMMAND --help!txtrst!\nDocs: !undblu!https://bashly.dannyb.co"
10
11
 
11
12
  runner.route 'init', to: Commands::Init
12
13
  runner.route 'preview', to: Commands::Preview
@@ -32,6 +32,7 @@ module Bashly
32
32
  example "bashly add comp script completions.bash"
33
33
 
34
34
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
35
+ environment "BASHLY_LIB_DIR", "The path to use for creating the library files, relative to the source dir [default: lib]"
35
36
 
36
37
  def strings_command
37
38
  add_lib 'strings'
@@ -5,6 +5,12 @@ module Bashly
5
5
  module Commands
6
6
  class Base < MisterBin::Command
7
7
  include AssetHelper
8
+
9
+ def validate_config
10
+ config = Config.new "#{Settings.source_dir}/bashly.yml"
11
+ validator = ConfigValidator.new config
12
+ validator.validate
13
+ end
8
14
  end
9
15
  end
10
16
  end
@@ -3,22 +3,34 @@ module Bashly
3
3
  class Generate < Base
4
4
  help "Generate the bash script and required files"
5
5
 
6
- usage "bashly generate [--force --quiet --upgrade --wrap FUNCTION]"
6
+ usage "bashly generate [options]"
7
7
  usage "bashly generate (-h|--help)"
8
8
 
9
9
  option "-f --force", "Overwrite existing files"
10
10
  option "-q --quiet", "Disable on-screen progress report"
11
11
  option "-u --upgrade", "Upgrade all added library functions"
12
12
  option "-w --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
13
+ option "-e --env ENV", "Force the generation environment (see BASHLY_ENV)"
13
14
 
14
15
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
15
16
  environment "BASHLY_TARGET_DIR", "The path to use for creating the bash script [default: .]"
17
+ environment "BASHLY_LIB_DIR", "The path to use for upgrading library files, relative to the source dir [default: lib]"
16
18
  environment "BASHLY_STRICT", "When not empty, enable bash strict mode (set -euo pipefail)"
19
+ environment "BASHLY_ENV", <<~EOF
20
+ Set to 'production' or 'development':
21
+ - production generate a smaller script, without file markers
22
+ - development generate with file markers
23
+
24
+ Can be overridden with --env [default: development]
25
+ EOF
17
26
 
18
27
  example "bashly generate --force"
19
28
  example "bashly generate --wrap my_function"
20
29
 
21
30
  def run
31
+ validate_config
32
+ ENV['BASHLY_ENV'] = args['--env'] if args['--env']
33
+ quiet_say "creating !txtgrn!production!txtrst! version" if Bashly.production?
22
34
  create_user_files
23
35
  upgrade_libs if args['--upgrade']
24
36
  create_master_script
@@ -9,9 +9,7 @@ module Bashly
9
9
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
10
10
 
11
11
  def run
12
- config = Config.new "#{Settings.source_dir}/bashly.yml"
13
- validator = ConfigValidator.new config
14
- validator.validate
12
+ validate_config
15
13
  say "!txtgrn!OK"
16
14
  end
17
15
  end
@@ -4,13 +4,20 @@ module Bashly
4
4
  module Renderable
5
5
  def render(view)
6
6
  template = File.read view_path(view)
7
- ERB.new(template, trim_mode: '%-').result(binding)
7
+ erb = ERB.new(template, trim_mode: '%-')
8
+ erb.filename = "#{views_subfolder}.#{view}"
9
+ erb.result binding
8
10
  end
9
11
 
10
12
  def strings
11
13
  @strings ||= MessageStrings.new
12
14
  end
13
15
 
16
+ def view_marker(id = nil)
17
+ id ||= ":#{caller_locations.first.path}"
18
+ "# #{id}" unless Bashly.production?
19
+ end
20
+
14
21
  private
15
22
 
16
23
  def view_path(view)
data/lib/bashly/config.rb CHANGED
@@ -10,7 +10,7 @@ module Bashly
10
10
 
11
11
  def self.new(config)
12
12
  if config.is_a? String
13
- YAML.load_file(config).compose
13
+ YAML.properly_load_file(config).compose
14
14
  else
15
15
  config
16
16
  end
@@ -42,8 +42,13 @@ module Bashly
42
42
  end
43
43
  end
44
44
 
45
- def assert_hash(key, value)
45
+ def assert_hash(key, value, whitelist = nil)
46
46
  assert value.is_a?(Hash), "#{key} must be a hash"
47
+
48
+ if whitelist
49
+ invalid_keys = value.keys.map(&:to_sym) - whitelist
50
+ assert invalid_keys.empty?, "#{key} contains invalid options: #{invalid_keys.join(', ')}"
51
+ end
47
52
  end
48
53
 
49
54
  def assert_version(key, value)
@@ -61,6 +66,7 @@ module Bashly
61
66
  end
62
67
 
63
68
  def assert_catch_all_hash(key, value)
69
+ assert_hash key, value, Script::CatchAll.option_keys
64
70
  assert_string "#{key}.label", value['label']
65
71
  assert_optional_string "#{key}.help", value['help']
66
72
  assert_boolean "#{key}.required", value['required']
@@ -73,7 +79,7 @@ module Bashly
73
79
  end
74
80
 
75
81
  def assert_arg(key, value)
76
- assert_hash key, value
82
+ assert_hash key, value, Script::Argument.option_keys
77
83
  assert_string "#{key}.name", value['name']
78
84
  assert_optional_string "#{key}.help", value['help']
79
85
  assert_optional_string "#{key}.default", value['default']
@@ -84,10 +90,12 @@ module Bashly
84
90
  assert_array "#{key}.allowed", value['allowed'], of: :string
85
91
 
86
92
  refute value['name'].match(/^-/), "#{key}.name must not start with '-'"
93
+
94
+ refute value['required'] && value['default'], "#{key} cannot have both required and default"
87
95
  end
88
96
 
89
97
  def assert_flag(key, value)
90
- assert_hash key, value
98
+ assert_hash key, value, Script::Flag.option_keys
91
99
  assert value['short'] || value['long'], "#{key} must have at least one of long or short name"
92
100
 
93
101
  assert_optional_string "#{key}.long", value['long']
@@ -97,6 +105,7 @@ module Bashly
97
105
  assert_optional_string "#{key}.default", value['default']
98
106
  assert_optional_string "#{key}.validate", value['validate']
99
107
 
108
+ assert_boolean "#{key}.repeatable", value['repeatable']
100
109
  assert_boolean "#{key}.required", value['required']
101
110
  assert_array "#{key}.allowed", value['allowed'], of: :string
102
111
  assert_array "#{key}.conflicts", value['conflicts'], of: :string
@@ -104,10 +113,20 @@ module Bashly
104
113
  assert value['long'].match(/^--[a-zA-Z0-9_\-]+$/), "#{key}.long must be in the form of '--name'" if value['long']
105
114
  assert value['short'].match(/^-[a-zA-Z0-9]$/), "#{key}.short must be in the form of '-n'" if value['short']
106
115
  refute value['arg'].match(/^-/), "#{key}.arg must not start with '-'" if value['arg']
116
+
117
+ refute value['required'] && value['default'], "#{key} cannot have both required and default"
118
+
119
+ if value['default']
120
+ assert value['arg'], "#{key}.default does not make sense without arg"
121
+ end
122
+
123
+ if value['allowed']
124
+ assert value['arg'], "#{key}.allowed does not make sense without arg"
125
+ end
107
126
  end
108
127
 
109
128
  def assert_env_var(key, value)
110
- assert_hash key, value
129
+ assert_hash key, value, Script::EnvironmentVariable.option_keys
111
130
  assert_string "#{key}.name", value['name']
112
131
  assert_optional_string "#{key}.help", value['help']
113
132
  assert_optional_string "#{key}.default", value['default']
@@ -115,7 +134,7 @@ module Bashly
115
134
  end
116
135
 
117
136
  def assert_command(key, value)
118
- assert_hash key, value
137
+ assert_hash key, value, Script::Command.option_keys
119
138
 
120
139
  refute value['commands'] && value['args'], "#{key} cannot have both commands and args"
121
140
  refute value['commands'] && value['flags'], "#{key} cannot have both commands and flags"
@@ -127,6 +146,7 @@ module Bashly
127
146
  assert_optional_string "#{key}.group", value['group']
128
147
  assert_optional_string "#{key}.filename", value['filename']
129
148
 
149
+ assert_boolean "#{key}.private", value['private']
130
150
  assert_boolean "#{key}.default", value['default']
131
151
  assert_version "#{key}.version", value['version']
132
152
  assert_catch_all "#{key}.catch_all", value['catch_all']
@@ -140,6 +160,16 @@ module Bashly
140
160
  assert_array "#{key}.filters", value['filters'], of: :string
141
161
  assert_array "#{key}.environment_variables", value['environment_variables'], of: :env_var
142
162
  assert_array "#{key}.examples", value['examples'], of: :string
163
+
164
+ if key == "root"
165
+ refute value['short'], "#{key}.short makes no sense"
166
+ refute value['group'], "#{key}.group makes no sense"
167
+ refute value['default'], "#{key}.default makes no sense"
168
+ refute value['private'], "#{key}.private makes no sense"
169
+ else
170
+ refute value['version'], "#{key}.version makes no sense"
171
+ refute value['extensible'], "#{key}.extensible makes no sense"
172
+ end
143
173
  end
144
174
  end
145
175
  end
@@ -0,0 +1,10 @@
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:
9
+ end
10
+ end
@@ -4,7 +4,7 @@ module Bashly
4
4
  def files
5
5
  [
6
6
  {
7
- path: "#{Settings.source_dir}/lib/#{function_name}.sh",
7
+ path: "#{Settings.full_lib_dir}/#{function_name}.sh",
8
8
  content: completions_function_code(function_name)
9
9
  }
10
10
  ]
@@ -1,22 +1,22 @@
1
1
  colors:
2
2
  files:
3
3
  - source: "templates/lib/colors.sh"
4
- target: "%{user_source_dir}/lib/colors.sh"
4
+ target: "%{user_lib_dir}/colors.sh"
5
5
 
6
6
  config:
7
7
  files:
8
8
  - source: "templates/lib/config.sh"
9
- target: "%{user_source_dir}/lib/config.sh"
9
+ target: "%{user_lib_dir}/config.sh"
10
10
 
11
11
  yaml:
12
12
  files:
13
13
  - source: "templates/lib/yaml.sh"
14
- target: "%{user_source_dir}/lib/yaml.sh"
14
+ target: "%{user_lib_dir}/yaml.sh"
15
15
 
16
16
  lib:
17
17
  files:
18
18
  - source: "templates/lib/sample_function.sh"
19
- target: "%{user_source_dir}/lib/sample_function.sh"
19
+ target: "%{user_lib_dir}/sample_function.sh"
20
20
 
21
21
  strings:
22
22
  files:
@@ -41,13 +41,13 @@ test:
41
41
  validations:
42
42
  files:
43
43
  - source: "templates/lib/validations/validate_dir_exists.sh"
44
- target: "%{user_source_dir}/lib/validations/validate_dir_exists.sh"
44
+ target: "%{user_lib_dir}/validations/validate_dir_exists.sh"
45
45
  - source: "templates/lib/validations/validate_file_exists.sh"
46
- target: "%{user_source_dir}/lib/validations/validate_file_exists.sh"
46
+ target: "%{user_lib_dir}/validations/validate_file_exists.sh"
47
47
  - source: "templates/lib/validations/validate_integer.sh"
48
- target: "%{user_source_dir}/lib/validations/validate_integer.sh"
48
+ target: "%{user_lib_dir}/validations/validate_integer.sh"
49
49
  - source: "templates/lib/validations/validate_not_empty.sh"
50
- target: "%{user_source_dir}/lib/validations/validate_not_empty.sh"
50
+ target: "%{user_lib_dir}/validations/validate_not_empty.sh"
51
51
 
52
52
  completions: :CompletionsFunction
53
53
  completions_script: :CompletionsScript
@@ -6,7 +6,7 @@ module Bashly
6
6
  end
7
7
 
8
8
  def config
9
- @config ||= YAML.load_file(config_path)
9
+ @config ||= YAML.properly_load_file(config_path)
10
10
  end
11
11
 
12
12
  def config_path
@@ -59,7 +59,8 @@ module Bashly
59
59
  def target_file_args
60
60
  {
61
61
  user_source_dir: Settings.source_dir,
62
- user_target_dir: Settings.target_dir
62
+ user_target_dir: Settings.target_dir,
63
+ user_lib_dir: Settings.full_lib_dir,
63
64
  }
64
65
  end
65
66
  end
@@ -13,7 +13,7 @@ module Bashly
13
13
  private
14
14
 
15
15
  def values!
16
- defaults = YAML.load_file asset("templates/strings.yml")
16
+ defaults = YAML.properly_load_file asset("templates/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.load_file project_strings_path
26
+ YAML.properly_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.load_file path
25
+ loaded = YAML.properly_load_file path
26
26
  return loaded if loaded.is_a? Array or loaded.is_a? Hash
27
27
  raise Bashly::ConfigurationError, "Cannot find a valid YAML in !txtgrn!#{path}"
28
28
 
@@ -1,8 +1,20 @@
1
1
  module Bashly
2
2
  module Script
3
3
  class Argument < Base
4
+ class << self
5
+ def option_keys
6
+ @option_keys ||= %i[
7
+ allowed default help name repeatable required validate
8
+ ]
9
+ end
10
+ end
11
+
4
12
  def usage_string
5
- required ? name.upcase : "[#{name.upcase}]"
13
+ required ? label : "[#{label}]"
14
+ end
15
+
16
+ def label
17
+ repeatable ? "#{name.upcase}..." : name.upcase
6
18
  end
7
19
  end
8
20
  end
@@ -5,42 +5,19 @@ module Bashly
5
5
 
6
6
  attr_reader :options
7
7
 
8
- OPTION_KEYS = %i[
9
- allowed
10
- arg
11
- catch_all
12
- completions
13
- conflicts
14
- default
15
- dependencies
16
- description
17
- environment_variables
18
- examples
19
- extensible
20
- filters
21
- flags
22
- footer
23
- group
24
- help
25
- long
26
- name
27
- parent_name
28
- private
29
- repeatable
30
- required
31
- short
32
- validate
33
- version
34
- ]
8
+ class << self
9
+ def option_keys
10
+ @option_keys ||= []
11
+ end
12
+ end
35
13
 
36
14
  def initialize(options)
37
15
  raise Error, "Invalid options provided" unless options.respond_to? :keys
38
16
  @options = options
39
- validate_options if respond_to? :validate_options
40
17
  end
41
18
 
42
19
  def optional
43
- !required
20
+ !options['required']
44
21
  end
45
22
 
46
23
  def summary
@@ -57,7 +34,7 @@ module Bashly
57
34
  end
58
35
 
59
36
  def respond_to_missing?(method_name, include_private = false)
60
- OPTION_KEYS.include?(method_name) || super
37
+ self.class.option_keys.include?(method_name) || super
61
38
  end
62
39
  end
63
40
  end
@@ -2,6 +2,10 @@ module Bashly
2
2
  module Script
3
3
  class CatchAll
4
4
  class << self
5
+ def option_keys
6
+ @option_keys ||= %i[label help required]
7
+ end
8
+
5
9
  def from_config(config)
6
10
  options = case config
7
11
  when nil
@@ -4,6 +4,18 @@ module Bashly
4
4
  include Completions
5
5
  include CommandScopes
6
6
 
7
+ class << self
8
+ def option_keys
9
+ @option_keys ||= %i[
10
+ args catch_all commands completions
11
+ default dependencies environment_variables examples
12
+ extensible filename filters flags
13
+ footer group help name
14
+ private short version
15
+ ]
16
+ end
17
+ end
18
+
7
19
  # Returns the name to be used as an action.
8
20
  # - If it is the root command, the action is "root"
9
21
  # - Else, it is all the parents, except the first one (root) joined
@@ -90,7 +102,7 @@ module Bashly
90
102
  default_content
91
103
  end
92
104
 
93
- "# :#{path}\n#{content}"
105
+ Bashly.production? ? content : "#{view_marker path}\n#{content}"
94
106
  end
95
107
 
96
108
  # Returns an array of all parents. For example, the command
@@ -125,13 +137,7 @@ module Bashly
125
137
  # This is meant to provide the user with the ability to add custom
126
138
  # functions
127
139
  def user_lib
128
- @user_lib ||= Dir["#{Settings.source_dir}/lib/**/*.sh"].sort
129
- end
130
-
131
- # Raise an exception if there are some serious issues with the command
132
- # definition. This is called by Base#initialize.
133
- def validate_options
134
- Bashly::ConfigValidator.new(options).validate
140
+ @user_lib ||= Dir["#{Settings.full_lib_dir}/**/*.sh"].sort
135
141
  end
136
142
 
137
143
  end
@@ -1,6 +1,12 @@
1
1
  module Bashly
2
2
  module Script
3
3
  class EnvironmentVariable < Base
4
+ class << self
5
+ def option_keys
6
+ @option_keys ||= %i[default help name required]
7
+ end
8
+ end
9
+
4
10
  def usage_string(extended: false)
5
11
  result = [name.upcase]
6
12
  result << strings[:required] if required and extended
@@ -1,6 +1,15 @@
1
1
  module Bashly
2
2
  module Script
3
3
  class Flag < Base
4
+ class << self
5
+ def option_keys
6
+ @option_keys ||= %i[
7
+ allowed arg conflicts default help long repeatable required
8
+ short validate
9
+ ]
10
+ end
11
+ end
12
+
4
13
  def aliases
5
14
  if long and short
6
15
  [long, short]
@@ -1,7 +1,7 @@
1
1
  module Bashly
2
2
  class Settings
3
3
  class << self
4
- attr_writer :source_dir, :target_dir
4
+ attr_writer :source_dir, :target_dir, :lib_dir, :strict
5
5
 
6
6
  def source_dir
7
7
  @source_dir ||= ENV['BASHLY_SOURCE_DIR'] || 'src'
@@ -10,6 +10,18 @@ module Bashly
10
10
  def target_dir
11
11
  @target_dir ||= ENV['BASHLY_TARGET_DIR'] || '.'
12
12
  end
13
+
14
+ def lib_dir
15
+ @lib_dir ||= ENV['BASHLY_LIB_DIR'] || 'lib'
16
+ end
17
+
18
+ def strict
19
+ @strict ||= ENV['BASHLY_STRICT']
20
+ end
21
+
22
+ def full_lib_dir
23
+ "#{source_dir}/#{lib_dir}"
24
+ end
13
25
  end
14
26
  end
15
27
  end
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = "0.7.6"
2
+ VERSION = "0.7.9"
3
3
  end
@@ -1,5 +1,5 @@
1
- # :argument.usage
2
- echo " <%= name.upcase %>"
1
+ <%= view_marker %>
2
+ echo " <%= label %>"
3
3
  printf "<%= help.wrap(76).indent(4).sanitize_for_print %>\n"
4
4
  % if allowed
5
5
  printf " <%= strings[:allowed] % { values: allowed.join(', ') } -%>\n"
@@ -1,4 +1,4 @@
1
- # :argument.validations
1
+ <%= view_marker %>
2
2
  % if validate
3
3
  if [[ -n $(validate_<%= validate %> "$1") ]]; then
4
4
  printf "<%= strings[:validation_error] %>\n" "<%= name.upcase %>" "$(validate_<%= validate %> "$1")"
@@ -1,4 +1,4 @@
1
- # :command.catch_all_filter
1
+ <%= view_marker %>
2
2
  % if catch_all.required?
3
3
  if [[ ${#other_args[@]} -eq 0 ]]; then
4
4
  printf "<%= strings[:missing_required_argument] % { arg: catch_all.label, usage: usage_string } %>\n"
@@ -1,4 +1,4 @@
1
- # :command.command_fallback
1
+ <%= view_marker %>
2
2
  % if default_command
3
3
  "" )
4
4
  <%= function_name %>_usage
@@ -1,4 +1,4 @@
1
- # :command.command_filter
1
+ <%= view_marker %>
2
2
  % if commands.any?
3
3
  action=${1:-}
4
4
 
@@ -1,4 +1,4 @@
1
- # :command.command_functions
1
+ <%= view_marker %>
2
2
  % deep_commands.each do |command|
3
3
  <%= command.render :function unless command.commands.any? %>
4
4
  % end
@@ -1,4 +1,4 @@
1
- # :command.default_assignments
1
+ <%= view_marker %>
2
2
  % default_args.each do |arg|
3
3
  [[ -n ${args[<%= arg.name %>]:-} ]] || args[<%= arg.name %>]="<%= arg.default %>"
4
4
  % end
@@ -1,4 +1,4 @@
1
- # :command.dependencies_filter
1
+ <%= view_marker %>
2
2
  % if dependencies
3
3
  % dependencies.each do |dependency|
4
4
  if ! [[ -x "$(command -v <%= dependency %>)" ]]; then
@@ -1,4 +1,4 @@
1
- # :command.environment_variables_filter
1
+ <%= view_marker %>
2
2
  % if default_environment_variables.any?
3
3
  % default_environment_variables.each do |env_var|
4
4
  export <%= env_var.name.upcase %>="${<%= env_var.name.upcase %>:-<%= env_var.default %>}"
@@ -1,5 +1,6 @@
1
- # :command.fixed_flag_filter
1
+ <%= view_marker %>
2
2
  case "${1:-}" in
3
+ % if root_command?
3
4
  % if short_flag_exist? "-v"
4
5
  --version )
5
6
  % else
@@ -9,6 +10,7 @@ case "${1:-}" in
9
10
  exit
10
11
  ;;
11
12
 
13
+ % end
12
14
  % if short_flag_exist? "-h"
13
15
  --help )
14
16
  % else
@@ -1,2 +1,3 @@
1
+ <%= view_marker %>
1
2
  printf "<%= footer.gsub("\n", '\n').gsub('"', '\"') %>\n"
2
3
  echo
@@ -1,4 +1,4 @@
1
- # :command.function
1
+ <%= view_marker %>
2
2
  <%= function_name %>_command() {
3
3
  <%= load_user_file(filename).indent 2 %>
4
4
  }
@@ -1,8 +1,8 @@
1
- # :command.initialize
1
+ <%= view_marker %>
2
2
  initialize() {
3
3
  version="<%= version %>"
4
4
  long_usage=''
5
- <%= ENV['BASHLY_STRICT'] ? "set -euo pipefail" : "set -e" %>
5
+ <%= Settings.strict ? "set -euo pipefail" : "set -e" %>
6
6
 
7
7
  <%= load_user_file("initialize.sh", placeholder: false).indent 2 %>
8
8
  }
@@ -1,4 +1,4 @@
1
- # :command.inspect_args
1
+ <%= view_marker %>
2
2
  inspect_args() {
3
3
  readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort)
4
4
  if (( ${#args[@]} )); then
@@ -1,3 +1,4 @@
1
+ <%= view_marker %>
1
2
  <%= render :root_command if commands.empty? %>
2
3
  <%= render :version_command %>
3
4
  <%= render :usage %>
@@ -1,4 +1,4 @@
1
- # :command.normalize_input
1
+ <%= view_marker %>
2
2
  normalize_input() {
3
3
  local arg flags
4
4
 
@@ -1,4 +1,4 @@
1
- # :command.parse_requirements
1
+ <%= view_marker %>
2
2
  % if root_command?
3
3
  parse_requirements() {
4
4
  % else
@@ -1,18 +1,30 @@
1
- # :command.parse_requirements_case
1
+ <%= view_marker %>
2
+ % repeatable_arg = false
2
3
  % if args.any?
3
4
  % condition = "if"
4
5
  % args.each do |arg|
5
6
  <%= condition %> [[ -z ${args[<%= arg.name %>]+x} ]]; then
6
7
  <%= arg.render(:validations).indent 2 %>
8
+ % if arg.repeatable
9
+ % repeatable_arg = true
10
+ args[<%= arg.name %>]="\"$1\""
11
+ shift
12
+ else
13
+ args[<%= arg.name %>]="${args[<%= arg.name %>]} \"$1\""
14
+ shift
15
+ % else
7
16
  args[<%= arg.name %>]=$1
8
17
  shift
18
+ % end
9
19
  % condition = "elif"
10
20
  % end
21
+ % if !repeatable_arg
11
22
  else
23
+ % end
12
24
  % if catch_all.enabled?
13
25
  other_args+=("$1")
14
26
  shift
15
- % else
27
+ % elsif !repeatable_arg
16
28
  printf "<%= strings[:invalid_argument] %>\n" "$key"
17
29
  exit 1
18
30
  % end
@@ -20,7 +32,7 @@ fi
20
32
  % elsif catch_all.enabled?
21
33
  other_args+=("$1")
22
34
  shift
23
- % else
35
+ % elsif !repeatable_arg
24
36
  printf "<%= strings[:invalid_argument] %>\n" "$key"
25
37
  exit 1
26
38
  % end
@@ -1,4 +1,4 @@
1
- # :command.parse_requirements_while
1
+ <%= view_marker %>
2
2
  while [[ $# -gt 0 ]]; do
3
3
  key="$1"
4
4
  case "$key" in
@@ -1,4 +1,4 @@
1
- # :command.required_args_filter
1
+ <%= view_marker %>
2
2
  % required_args.each do |arg|
3
3
  if [[ -z ${args[<%= arg.name %>]+x} ]]; then
4
4
  printf "<%= strings[:missing_required_argument] % { arg: arg.name.upcase, usage: usage_string } %>\n"
@@ -1,4 +1,4 @@
1
- # :command.required_flags_filter
1
+ <%= view_marker %>
2
2
  % required_flags.each do |flag|
3
3
  if [[ -z ${args[<%= flag.long %>]+x} ]]; then
4
4
  printf "<%= strings[:missing_required_flag] % { usage: flag.usage_string } %>\n"
@@ -1,4 +1,4 @@
1
- # :command.root_command
1
+ <%= view_marker %>
2
2
  root_command() {
3
3
  <%= load_user_file(filename).indent 2 %>
4
4
  }
@@ -1,4 +1,4 @@
1
- # :command.run
1
+ <%= view_marker %>
2
2
  run() {
3
3
  declare -A args=()
4
4
  declare -a other_args=()
@@ -1,4 +1,4 @@
1
- # :command.usage
1
+ <%= view_marker %>
2
2
  <%= function_name %>_usage() {
3
3
  if [[ -n $long_usage ]]; then
4
4
  <%- if summary == help -%>
@@ -1,4 +1,4 @@
1
- # :command.usage_args
1
+ <%= view_marker %>
2
2
  printf "<%= strings[:arguments] %>\n"
3
3
  % if args.any?
4
4
 
@@ -1,4 +1,4 @@
1
- # :command.usage_commands
1
+ <%= view_marker %>
2
2
  % unless commands.first.group
3
3
  printf "<%= strings[:commands] %>\n"
4
4
  % end
@@ -1,4 +1,4 @@
1
- # :command.usage_environment_variables
1
+ <%= view_marker %>
2
2
  printf "<%= strings[:environment_variables] %>\n"
3
3
 
4
4
  % environment_variables.each do |env_var|
@@ -1,4 +1,4 @@
1
- # :command.usage_examples
1
+ <%= view_marker %>
2
2
  printf "<%= strings[:examples] %>\n"
3
3
 
4
4
  % examples.each do |example|
@@ -1,4 +1,4 @@
1
- # :command.usage_fixed_flags
1
+ <%= view_marker %>
2
2
  % if short_flag_exist? "-h"
3
3
  echo " --help"
4
4
  % else
@@ -1,4 +1,4 @@
1
- # :command.usage_flags
1
+ <%= view_marker %>
2
2
  % flags.each do |flag|
3
3
  <%= flag.render(:usage) %>
4
4
  % end
@@ -1,4 +1,4 @@
1
- # :command.user_filter
1
+ <%= view_marker %>
2
2
  % if filters
3
3
  % filters.each do |filter|
4
4
  filter_error=$(filter_<%= filter %>)
@@ -1,6 +1,6 @@
1
- # :command.user_lib
1
+ <%= view_marker %>
2
2
  % user_lib.each do |file|
3
- # <%= ":#{file}" %>
3
+ <%= view_marker file %>
4
4
  <%= File.read file %>
5
5
 
6
6
  % end
@@ -1,4 +1,4 @@
1
- # :command.version_command
1
+ <%= view_marker %>
2
2
  version_command() {
3
3
  echo "$version"
4
4
  }
@@ -1,13 +1,33 @@
1
- # :command.whitelist_filter
1
+ <%= view_marker %>
2
2
  % whitelisted_args.each do |arg|
3
+ % if arg.repeatable
4
+ eval "input_array=(${args[<%= arg.name %>]})"
5
+ for i in "${input_array[@]}"; do
6
+ if [[ ! $i =~ ^(<%= arg.allowed.join '|' %>)$ ]]; then
7
+ printf "%s\n" "<%= strings[:disallowed_argument] % { name: arg.name, allowed: arg.allowed.join(', ') } %>"
8
+ exit 1
9
+ fi
10
+ done
11
+ % else
3
12
  if [[ ! ${args[<%= arg.name %>]} =~ ^(<%= arg.allowed.join '|' %>)$ ]]; then
4
13
  printf "%s\n" "<%= strings[:disallowed_argument] % { name: arg.name, allowed: arg.allowed.join(', ') } %>"
5
14
  exit 1
6
15
  fi
7
16
  % end
17
+ % end
8
18
  % whitelisted_flags.each do |flag|
19
+ % if flag.repeatable
20
+ eval "input_array=(${args[<%= flag.name %>]})"
21
+ for i in "${input_array[@]}"; do
22
+ if [[ ! $i =~ ^(<%= flag.allowed.join '|' %>)$ ]]; then
23
+ printf "%s\n" "<%= strings[:disallowed_flag] % { name: flag.name, allowed: flag.allowed.join(', ') } %>"
24
+ exit 1
25
+ fi
26
+ done
27
+ % else
9
28
  if [[ ! ${args[<%= flag.name %>]} =~ ^(<%= flag.allowed.join '|' %>)$ ]]; then
10
29
  printf "%s\n" "<%= strings[:disallowed_flag] % { name: flag.name, allowed: flag.allowed.join(', ') } %>"
11
30
  exit 1
12
31
  fi
32
+ % end
13
33
  % end
@@ -1,4 +1,4 @@
1
- # :environment_variable.usage
1
+ <%= view_marker %>
2
2
  echo " <%= usage_string extended: true %>"
3
3
  printf "<%= help.wrap(76).indent(4).sanitize_for_print %>\n"
4
4
  % if default
@@ -1,4 +1,4 @@
1
- # :flag.case
1
+ <%= view_marker %>
2
2
  <%= aliases.join " | " %> )
3
3
  <%= render(:conflicts).indent 2 %>
4
4
  % if arg
@@ -1,4 +1,4 @@
1
- # :flag.conflicts
1
+ <%= view_marker %>
2
2
  % if conflicts
3
3
  % if conflicts.count == 1
4
4
  if [[ -n "${args[<%= conflicts.first %>]:-}" ]]; then
@@ -1,4 +1,4 @@
1
- # :flag.usage
1
+ <%= view_marker %>
2
2
  echo " <%= usage_string extended: true %>"
3
3
  printf "<%= help.wrap(76).indent(4).sanitize_for_print %>\n"
4
4
  % if allowed
@@ -1,4 +1,4 @@
1
- # :flag.validations
1
+ <%= view_marker %>
2
2
  % if validate
3
3
  if [[ -n $(validate_<%= validate %> "$2") ]]; then
4
4
  printf "<%= strings[:validation_error] %>\n" "<%= usage_string %>" "$(validate_<%= validate %> "$2")"
@@ -1,4 +1,4 @@
1
- # :script.bash3_bouncer
1
+ <%= view_marker %>
2
2
  if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then
3
3
  printf "<%= strings[:unsupported_bash_version] -%>\n"
4
4
  exit 1
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env bash
2
- # This script was generated by bashly (https://github.com/DannyBen/bashly)
2
+ # This script was generated by bashly <%= Bashly::VERSION %> (https://bashly.dannyb.co)
3
3
  # Modifying it manually is not recommended
4
4
 
@@ -1,4 +1,4 @@
1
- # :script.wrapper
1
+ <%= view_marker %>
2
2
  <%= function_name %>() {
3
3
  <%= body.indent 2 %>
4
4
  }
data/lib/bashly.rb CHANGED
@@ -7,6 +7,7 @@ end
7
7
 
8
8
  requires 'bashly/concerns'
9
9
 
10
+ requires 'bashly/extensions'
10
11
  requires 'bashly/settings'
11
12
  requires 'bashly/exceptions'
12
13
  requires 'bashly/refinements'
@@ -14,3 +15,15 @@ requires 'bashly/script/base'
14
15
  requires 'bashly/commands/base'
15
16
  requires 'bashly/libraries/base'
16
17
  requires 'bashly'
18
+
19
+ module Bashly
20
+ class << self
21
+ def env
22
+ ENV['BASHLY_ENV']&.to_sym
23
+ end
24
+
25
+ def production?
26
+ env == :production
27
+ end
28
+ end
29
+ 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: 0.7.6
4
+ version: 0.7.9
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-02-18 00:00:00.000000000 Z
11
+ date: 2022-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colsole
@@ -93,6 +93,7 @@ files:
93
93
  - lib/bashly/extensions/array.rb
94
94
  - lib/bashly/extensions/file.rb
95
95
  - lib/bashly/extensions/string.rb
96
+ - lib/bashly/extensions/yaml.rb
96
97
  - lib/bashly/libraries.yml
97
98
  - lib/bashly/libraries/base.rb
98
99
  - lib/bashly/libraries/completions.rb
@@ -191,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
192
  - !ruby/object:Gem::Version
192
193
  version: '0'
193
194
  requirements: []
194
- rubygems_version: 3.3.7
195
+ rubygems_version: 3.3.3
195
196
  signing_key:
196
197
  specification_version: 4
197
198
  summary: Bash Command Line Tool Generator