bashly 0.8.1 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bashly/commands/generate.rb +40 -4
  3. data/lib/bashly/concerns/renderable.rb +19 -6
  4. data/lib/bashly/config_validator.rb +11 -0
  5. data/lib/bashly/extensions/string.rb +2 -2
  6. data/lib/bashly/script/command.rb +126 -24
  7. data/lib/bashly/templates/strings.yml +1 -0
  8. data/lib/bashly/version.rb +1 -1
  9. data/lib/bashly/views/README.md +6 -0
  10. data/lib/bashly/views/argument/usage.gtx +15 -0
  11. data/lib/bashly/views/argument/validations.gtx +11 -0
  12. data/lib/bashly/views/command/catch_all_filter.gtx +10 -0
  13. data/lib/bashly/views/command/command_fallback.gtx +42 -0
  14. data/lib/bashly/views/command/command_filter.gtx +29 -0
  15. data/lib/bashly/views/command/command_functions.gtx +5 -0
  16. data/lib/bashly/views/command/default_assignments.gtx +13 -0
  17. data/lib/bashly/views/command/default_initialize_script.gtx +7 -0
  18. data/lib/bashly/views/command/default_root_script.gtx +4 -0
  19. data/lib/bashly/views/command/default_script.gtx +5 -0
  20. data/lib/bashly/views/command/dependencies_filter.gtx +10 -0
  21. data/lib/bashly/views/command/environment_variables_filter.gtx +18 -0
  22. data/lib/bashly/views/command/fixed_flags_filter.gtx +20 -0
  23. data/lib/bashly/views/command/footer.gtx +5 -0
  24. data/lib/bashly/views/command/function.gtx +6 -0
  25. data/lib/bashly/views/command/initialize.gtx +12 -0
  26. data/lib/bashly/views/command/inspect_args.gtx +21 -0
  27. data/lib/bashly/views/command/long_usage.gtx +13 -0
  28. data/lib/bashly/views/command/master_script.gtx +17 -0
  29. data/lib/bashly/views/command/normalize_input.gtx +25 -0
  30. data/lib/bashly/views/command/parse_requirements.gtx +26 -0
  31. data/lib/bashly/views/command/parse_requirements_case.gtx +11 -0
  32. data/lib/bashly/views/command/parse_requirements_case_catch_all.gtx +23 -0
  33. data/lib/bashly/views/command/parse_requirements_case_repeatable.gtx +24 -0
  34. data/lib/bashly/views/command/parse_requirements_case_simple.gtx +25 -0
  35. data/lib/bashly/views/command/parse_requirements_while.gtx +33 -0
  36. data/lib/bashly/views/command/required_args_filter.gtx +13 -0
  37. data/lib/bashly/views/command/required_flags_filter.gtx +12 -0
  38. data/lib/bashly/views/command/root_command.gtx +6 -0
  39. data/lib/bashly/views/command/run.gtx +28 -0
  40. data/lib/bashly/views/command/usage.gtx +50 -0
  41. data/lib/bashly/views/command/usage_args.gtx +20 -0
  42. data/lib/bashly/views/command/usage_commands.gtx +18 -0
  43. data/lib/bashly/views/command/usage_environment_variables.gtx +10 -0
  44. data/lib/bashly/views/command/usage_examples.gtx +10 -0
  45. data/lib/bashly/views/command/usage_fixed_flags.gtx +13 -0
  46. data/lib/bashly/views/command/usage_flags.gtx +7 -0
  47. data/lib/bashly/views/command/user_filter.gtx +13 -0
  48. data/lib/bashly/views/command/user_lib.gtx +11 -0
  49. data/lib/bashly/views/command/version_command.gtx +6 -0
  50. data/lib/bashly/views/command/whitelist_filter.gtx +41 -0
  51. data/lib/bashly/views/environment_variable/usage.gtx +11 -0
  52. data/lib/bashly/views/flag/case.gtx +6 -0
  53. data/lib/bashly/views/flag/case_arg.gtx +25 -0
  54. data/lib/bashly/views/flag/case_no_arg.gtx +11 -0
  55. data/lib/bashly/views/flag/conflicts.gtx +22 -0
  56. data/lib/bashly/views/flag/usage.gtx +15 -0
  57. data/lib/bashly/views/flag/validations.gtx +11 -0
  58. data/lib/bashly/views/wrapper/bash3_bouncer.gtx +7 -0
  59. data/lib/bashly/views/wrapper/header.gtx +5 -0
  60. data/lib/bashly/views/wrapper/wrapper.gtx +8 -0
  61. metadata +89 -60
  62. data/lib/bashly/concerns/command_scopes.rb +0 -83
  63. data/lib/bashly/views/argument/usage.erb +0 -10
  64. data/lib/bashly/views/argument/validations.erb +0 -8
  65. data/lib/bashly/views/command/catch_all_filter.erb +0 -7
  66. data/lib/bashly/views/command/command_fallback.erb +0 -45
  67. data/lib/bashly/views/command/command_filter.erb +0 -22
  68. data/lib/bashly/views/command/command_functions.erb +0 -4
  69. data/lib/bashly/views/command/default_assignments.erb +0 -7
  70. data/lib/bashly/views/command/default_initialize_script.erb +0 -6
  71. data/lib/bashly/views/command/default_root_script.erb +0 -3
  72. data/lib/bashly/views/command/default_script.erb +0 -4
  73. data/lib/bashly/views/command/dependencies_filter.erb +0 -9
  74. data/lib/bashly/views/command/environment_variables_filter.erb +0 -14
  75. data/lib/bashly/views/command/fixed_flags_filter.erb +0 -24
  76. data/lib/bashly/views/command/footer.erb +0 -3
  77. data/lib/bashly/views/command/function.erb +0 -4
  78. data/lib/bashly/views/command/initialize.erb +0 -8
  79. data/lib/bashly/views/command/inspect_args.erb +0 -19
  80. data/lib/bashly/views/command/master_script.erb +0 -14
  81. data/lib/bashly/views/command/normalize_input.erb +0 -24
  82. data/lib/bashly/views/command/parse_requirements.erb +0 -22
  83. data/lib/bashly/views/command/parse_requirements_case.erb +0 -8
  84. data/lib/bashly/views/command/parse_requirements_case_catch_all.erb +0 -18
  85. data/lib/bashly/views/command/parse_requirements_case_repeatable.erb +0 -18
  86. data/lib/bashly/views/command/parse_requirements_case_simple.erb +0 -18
  87. data/lib/bashly/views/command/parse_requirements_while.erb +0 -26
  88. data/lib/bashly/views/command/required_args_filter.erb +0 -7
  89. data/lib/bashly/views/command/required_flags_filter.erb +0 -7
  90. data/lib/bashly/views/command/root_command.erb +0 -4
  91. data/lib/bashly/views/command/run.erb +0 -23
  92. data/lib/bashly/views/command/usage.erb +0 -50
  93. data/lib/bashly/views/command/usage_args.erb +0 -14
  94. data/lib/bashly/views/command/usage_commands.erb +0 -18
  95. data/lib/bashly/views/command/usage_environment_variables.erb +0 -6
  96. data/lib/bashly/views/command/usage_examples.erb +0 -7
  97. data/lib/bashly/views/command/usage_fixed_flags.erb +0 -17
  98. data/lib/bashly/views/command/usage_flags.erb +0 -4
  99. data/lib/bashly/views/command/user_filter.erb +0 -11
  100. data/lib/bashly/views/command/user_lib.erb +0 -6
  101. data/lib/bashly/views/command/version_command.erb +0 -4
  102. data/lib/bashly/views/command/whitelist_filter.erb +0 -33
  103. data/lib/bashly/views/environment_variable/usage.erb +0 -7
  104. data/lib/bashly/views/flag/case.erb +0 -4
  105. data/lib/bashly/views/flag/case_arg.erb +0 -19
  106. data/lib/bashly/views/flag/case_no_arg.erb +0 -8
  107. data/lib/bashly/views/flag/conflicts.erb +0 -18
  108. data/lib/bashly/views/flag/usage.erb +0 -10
  109. data/lib/bashly/views/flag/validations.erb +0 -8
  110. data/lib/bashly/views/wrapper/bash3_bouncer.erb +0 -5
  111. data/lib/bashly/views/wrapper/header.erb +0 -4
  112. data/lib/bashly/views/wrapper/wrapper.erb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4be359964fc41fae59f83eae85c594a4e0edec41e0cc5752fec25850b7b7ca43
4
- data.tar.gz: 62023932e59ae5b9856a9617f9148a7e28bfab5bca5cebca98d3fefbf401ae21
3
+ metadata.gz: 5bec052fd6ce0ffa90e32f48c5899a6f9ff7807750ffbe126b61b8cbd72a6210
4
+ data.tar.gz: 69d88a7b5a307ea324156a53f379b78d27b4b376dbe3fb3763307f4fd34ab7c3
5
5
  SHA512:
6
- metadata.gz: a0e222c6ead53cfef4597653d9ce51b6e9fffd1a3556acd72eff5447b9a203371a0097cd42f4058405cd473e7f0c55f4f9a448d45d3b1af73898b74a79706df4
7
- data.tar.gz: 8362eff89fccaad8c9a1f370270e33426d0089bbe131eec4fc55f586413afaa556caa81e62389daefb400941122db96fa1f8b4e04d3780a4d45ea88060dfdc1e
6
+ metadata.gz: cba455f059a94e300ad787e1a9ed69455160f915302033217350101e5d57e53c3f64c91192f942d6e18ad1995e1317082dcd46bf715b8f0ac7401080d409cc54
7
+ data.tar.gz: 48ce5d30512a9aa8ba0401c66cb1619f1f4926bcc041e0309a19543a5a99395f098b3c6d1bad0adfdf9076560e438f26849214ca3c33dbe24158beb34badd0ca
@@ -1,3 +1,5 @@
1
+ require 'filewatcher'
2
+
1
3
  module Bashly
2
4
  module Commands
3
5
  class Generate < Base
@@ -9,7 +11,8 @@ module Bashly
9
11
  option "-f --force", "Overwrite existing files"
10
12
  option "-q --quiet", "Disable on-screen progress report"
11
13
  option "-u --upgrade", "Upgrade all added library functions"
12
- option "-w --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
14
+ option "-w --watch", "Watch the source directory for changes and regenerate on change"
15
+ option "-r --wrap FUNCTION", "Wrap the entire script in a function so it can also be sourced"
13
16
  option "-e --env ENV", "Force the generation environment (see BASHLY_ENV)"
14
17
 
15
18
  environment "BASHLY_SOURCE_DIR", "The path containing the bashly configuration and source files [default: src]"
@@ -27,17 +30,50 @@ module Bashly
27
30
 
28
31
  example "bashly generate --force"
29
32
  example "bashly generate --wrap my_function"
33
+ example "bashly g -uw"
34
+
35
+ attr_reader :watching
30
36
 
31
37
  def run
38
+ Settings.env = args['--env'] if args['--env']
39
+ @watching = args['--watch']
40
+
41
+ generate
42
+ watch if watching
43
+ end
44
+
45
+ private
46
+
47
+ def watch
48
+ quiet_say "!txtgrn!watching!txtrst! #{Settings.source_dir}\n"
49
+
50
+ Filewatcher.new([Settings.source_dir]).watch do
51
+ reset
52
+ generate
53
+
54
+ rescue Bashly::ConfigurationError => e
55
+ say! "!undred!#{e.class}!txtrst!\n#{e.message}"
56
+
57
+ ensure
58
+ quiet_say "!txtgrn!waiting\n"
59
+
60
+ end
61
+ end
62
+
63
+ def generate
32
64
  with_valid_config do
33
- Settings.env = args['--env'] if args['--env']
34
65
  quiet_say "creating !txtgrn!production!txtrst! version" if Settings.production?
35
66
  generate_all_files
36
- quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script"
67
+ quiet_say "run !txtpur!#{master_script_path} --help!txtrst! to test your bash script" unless watching
37
68
  end
38
69
  end
39
70
 
40
- private
71
+ def reset
72
+ @config = nil
73
+ @config_validator = nil
74
+ @command = nil
75
+ @script = nil
76
+ end
41
77
 
42
78
  def quiet_say(message)
43
79
  say message unless args['--quiet']
@@ -1,12 +1,9 @@
1
- require 'erb'
1
+ require 'gtx'
2
2
 
3
3
  module Bashly
4
4
  module Renderable
5
5
  def render(view)
6
- template = File.read view_path(view)
7
- erb = ERB.new(template, trim_mode: '%-')
8
- erb.filename = "#{views_subfolder}.#{view}"
9
- erb.result binding
6
+ GTX.render_file view_path(view), context: binding, filename: "#{views_subfolder}.#{view}"
10
7
  end
11
8
 
12
9
  def strings
@@ -18,10 +15,26 @@ module Bashly
18
15
  "# #{id}" unless Settings.production?
19
16
  end
20
17
 
18
+ # Reads a file from the userspace (Settings.source_dir) and returns
19
+ # its contents. If the file is not found, returns a string with a hint.
20
+ def load_user_file(file, placeholder: true)
21
+ path = "#{Settings.source_dir}/#{file}"
22
+
23
+ content = if File.exist? path
24
+ File.read(path).remove_front_matter
25
+ elsif placeholder
26
+ %q[echo "error: cannot load file"]
27
+ else
28
+ ''
29
+ end
30
+
31
+ Settings.production? ? content : "#{view_marker path}\n#{content}"
32
+ end
33
+
21
34
  private
22
35
 
23
36
  def view_path(view)
24
- "#{self_views_path}/#{view}.erb"
37
+ "#{self_views_path}/#{view}.gtx"
25
38
  end
26
39
 
27
40
  def self_views_path
@@ -41,6 +41,11 @@ module Bashly
41
41
  "#{key} must be a boolean or a string"
42
42
  end
43
43
 
44
+ def assert_expose(key, value)
45
+ return unless value
46
+ assert [true, false, nil, 'always'].include?(value), "#{key} must be a boolean, or the string 'always'"
47
+ end
48
+
44
49
  def assert_arg(key, value)
45
50
  assert_hash key, value, Script::Argument.option_keys
46
51
  assert_string "#{key}.name", value['name']
@@ -117,6 +122,7 @@ module Bashly
117
122
 
118
123
  assert_boolean "#{key}.private", value['private']
119
124
  assert_boolean "#{key}.default", value['default']
125
+ assert_expose "#{key}.expose", value['expose']
120
126
  assert_version "#{key}.version", value['version']
121
127
  assert_catch_all "#{key}.catch_all", value['catch_all']
122
128
  assert_string_or_array "#{key}.alias", value['alias']
@@ -141,11 +147,16 @@ module Bashly
141
147
  refute repeatable_arg, "#{key}.catch_all makes no sense with repeatable arg (#{repeatable_arg})"
142
148
  end
143
149
 
150
+ if value['expose']
151
+ assert value['commands'], "#{key}.expose makes no sense without commands"
152
+ end
153
+
144
154
  if key == "root"
145
155
  refute value['alias'], "#{key}.alias makes no sense"
146
156
  refute value['group'], "#{key}.group makes no sense"
147
157
  refute value['default'], "#{key}.default makes no sense"
148
158
  refute value['private'], "#{key}.private makes no sense"
159
+ refute value['expose'], "#{key}.expose makes no sense"
149
160
  else
150
161
  refute value['version'], "#{key}.version makes no sense"
151
162
  refute value['extensible'], "#{key}.extensible makes no sense"
@@ -5,7 +5,7 @@ class String
5
5
 
6
6
  def indent(offset)
7
7
  return self unless offset > 0
8
- split("\n").indent(offset).join("\n")
8
+ lines.indent(offset).join
9
9
  end
10
10
 
11
11
  def to_underscore
@@ -24,7 +24,7 @@ class String
24
24
  end
25
25
 
26
26
  def lint
27
- gsub(/\s+\n/m, "\n\n").lines.reject { |l| l =~ /^\s*##/ }.join ""
27
+ gsub(/\s+\n/m, "\n\n").lines.reject { |l| l =~ /^\s*##/ }.join
28
28
  end
29
29
 
30
30
  def remove_front_matter
@@ -2,14 +2,13 @@ module Bashly
2
2
  module Script
3
3
  class Command < Base
4
4
  include Completions::Command
5
- include CommandScopes
6
5
 
7
6
  class << self
8
7
  def option_keys
9
8
  @option_keys ||= %i[
10
9
  alias args catch_all commands completions
11
10
  default dependencies environment_variables examples
12
- extensible filename filters flags
11
+ extensible expose filename filters flags
13
12
  footer group help name
14
13
  private version
15
14
  short
@@ -18,6 +17,9 @@ module Bashly
18
17
  end
19
18
  end
20
19
 
20
+ attr_accessor :parent_command
21
+ attr_writer :parents
22
+
21
23
  # Returns the name to be used as an action.
22
24
  # - If it is the root command, the action is "root"
23
25
  # - Else, it is all the parents, except the first one (root) joined
@@ -32,6 +34,16 @@ module Bashly
32
34
  [name] + alt
33
35
  end
34
36
 
37
+ # Returns an array of all full names (including aliases and aliases of
38
+ # parents)
39
+ def all_full_names
40
+ if parent_command
41
+ parent_command.all_full_names.product(aliases).map { |a| a.join ' ' }
42
+ else
43
+ aliases
44
+ end
45
+ end
46
+
35
47
  # Returns an array of alternative aliases if any
36
48
  def alt
37
49
  # DEPRECATION 0.8.0
@@ -57,14 +69,79 @@ module Bashly
57
69
  @catch_all ||= CatchAll.from_config options['catch_all']
58
70
  end
59
71
 
72
+ # Returns a full list of the Command names and aliases combined
73
+ def command_aliases
74
+ commands.map(&:aliases).flatten
75
+ end
76
+
77
+ # Returns a data structure for displaying subcommands help
78
+ def command_help_data
79
+ result = {}
80
+
81
+ public_commands.each do |command|
82
+ result[command.group_string] ||= {}
83
+ result[command.group_string][command.name] = { summary: command.summary_string }
84
+ next unless command.expose
85
+
86
+ command.public_commands.each do |subcommand|
87
+ result[command.group_string]["#{command.name} #{subcommand.name}"] = {
88
+ summary: subcommand.summary_string,
89
+ help_only: command.expose != 'always'
90
+ }
91
+ end
92
+ end
93
+
94
+ result
95
+ end
96
+
97
+ # Returns only the names of the Commands
98
+ def command_names
99
+ commands.map &:name
100
+ end
101
+
60
102
  # Returns an array of the Commands
61
103
  def commands
62
104
  return [] unless options["commands"]
63
105
  options["commands"].map do |options|
64
- options['parents'] = parents + [name]
65
- options['parent_command'] = self
66
- Command.new options
106
+ result = Command.new options
107
+ result.parents = parents + [name]
108
+ result.parent_command = self
109
+ result
110
+ end
111
+ end
112
+
113
+ # Returns a flat array containing all the commands in this tree.
114
+ # This includes self + children + grandchildres + ...
115
+ def deep_commands
116
+ result = []
117
+ commands.each do |command|
118
+ result << command
119
+ if command.commands.any?
120
+ result += command.deep_commands
121
+ end
67
122
  end
123
+ result
124
+ end
125
+
126
+ # If any of this command's subcommands has the default option set to
127
+ # true, this default command will be returned, nil otherwise.
128
+ def default_command
129
+ commands.find { |c| c.default }
130
+ end
131
+
132
+ # Returns an array of all the default Args
133
+ def default_args
134
+ args.select &:default
135
+ end
136
+
137
+ # Returns an array of all the default Environment Variables
138
+ def default_environment_variables
139
+ environment_variables.select &:default
140
+ end
141
+
142
+ # Returns an array of all the default Flags
143
+ def default_flags
144
+ flags.select &:default
68
145
  end
69
146
 
70
147
  # Returns an array of EnvironmentVariables
@@ -100,32 +177,24 @@ module Bashly
100
177
  parents.any? ? (parents + [name]).join(' ') : name
101
178
  end
102
179
 
103
- # Reads a file from the userspace (Settings.source_dir) and returns
104
- # its contents.
105
- # If the file is not found, returns a string with a hint.
106
- def load_user_file(file, placeholder: true)
107
- path = "#{Settings.source_dir}/#{file}"
108
-
109
- content = if File.exist? path
110
- File.read(path).remove_front_matter
111
- elsif placeholder
112
- %q[echo "error: cannot load file"]
180
+ # Returns the string for the group caption
181
+ def group_string
182
+ if group
183
+ strings[:group] % { group: group }
113
184
  else
114
- ''
185
+ strings[:commands]
115
186
  end
116
-
117
- Settings.production? ? content : "#{view_marker path}\n#{content}"
118
- end
119
-
120
- # Returns the Command instance of the direct parent
121
- def parent_command
122
- options['parent_command']
123
187
  end
124
188
 
125
189
  # Returns an array of all parents. For example, the command
126
190
  # "docker container run" will have [docker, container] as its parents
127
191
  def parents
128
- options['parents'] || []
192
+ @parents ||= []
193
+ end
194
+
195
+ # Returns only commands that are not private
196
+ def public_commands
197
+ commands.reject &:private
129
198
  end
130
199
 
131
200
  # Returns true if one of the args is repeatable
@@ -133,6 +202,21 @@ module Bashly
133
202
  args.select(&:repeatable).any?
134
203
  end
135
204
 
205
+ # Returns an array of all the required Arguments
206
+ def required_args
207
+ args.select &:required
208
+ end
209
+
210
+ # Returns an array of all the required EnvironmentVariables
211
+ def required_environment_variables
212
+ environment_variables.select &:required
213
+ end
214
+
215
+ # Returns an array of all the required Flags
216
+ def required_flags
217
+ flags.select &:required
218
+ end
219
+
136
220
  # Returns true if this is the root command (no parents)
137
221
  def root_command?
138
222
  parents.empty?
@@ -143,6 +227,15 @@ module Bashly
143
227
  flags.select { |f| f.short == flag }.any?
144
228
  end
145
229
 
230
+ # Returns the summary string
231
+ def summary_string
232
+ if default
233
+ strings[:default_command_summary] % { summary: summary }
234
+ else
235
+ summary
236
+ end
237
+ end
238
+
146
239
  # Returns a constructed string suitable for Usage pattern
147
240
  def usage_string
148
241
  result = [full_name]
@@ -162,6 +255,15 @@ module Bashly
162
255
  @user_lib ||= Dir["#{Settings.full_lib_dir}/**/*.sh"].sort
163
256
  end
164
257
 
258
+ # Returns an array of all the args with a whitelist
259
+ def whitelisted_args
260
+ args.select &:allowed
261
+ end
262
+
263
+ # Returns an array of all the flags with a whitelist arg
264
+ def whitelisted_flags
265
+ flags.select &:allowed
266
+ end
165
267
  end
166
268
  end
167
269
  end
@@ -26,6 +26,7 @@ version_flag_text: Show version number
26
26
  flag_requires_an_argument: "%{name} requires an argument: %{usage}"
27
27
  invalid_argument: "invalid argument: %s"
28
28
  invalid_flag: "invalid option: %s"
29
+ invalid_command: "invalid command: %s"
29
30
  conflicting_flags: "conflicting options: %s cannot be used with %s"
30
31
  missing_required_argument: "missing required argument: %{arg}\\nusage: %{usage}"
31
32
  missing_required_flag: "missing required flag: %{usage}"
@@ -1,3 +1,3 @@
1
1
  module Bashly
2
- VERSION = "0.8.1"
2
+ VERSION = "0.8.4"
3
3
  end
@@ -0,0 +1,6 @@
1
+ # View Tempaltes
2
+
3
+ These are [GTX](https://github.com/dannyben/gtx) templates.
4
+
5
+ For syntax highlighting, set up your editor to treat `*.gtx` files as Ruby
6
+ source code.
@@ -0,0 +1,15 @@
1
+ = view_marker
2
+
3
+ > echo " {{ label }}"
4
+ > printf "{{ help.wrap(76).indent(4).sanitize_for_print }}\n"
5
+
6
+ if allowed
7
+ > printf " {{ strings[:allowed] % { values: allowed.join(', ') } }}\n"
8
+ end
9
+
10
+ if default
11
+ > printf " {{ strings[:default] % { value: default } }}\n"
12
+ end
13
+
14
+ > echo
15
+ >
@@ -0,0 +1,11 @@
1
+ if validate
2
+
3
+ = view_marker
4
+
5
+ > if [[ -n $(validate_{{ validate }} "$1") ]]; then
6
+ > printf "{{ strings[:validation_error] }}\n" "{{ name.upcase }}" "$(validate_{{ validate }} "$1")"
7
+ > exit 1
8
+ > fi
9
+ >
10
+
11
+ end
@@ -0,0 +1,10 @@
1
+ if catch_all.required?
2
+ = view_marker
3
+
4
+ > if [[ ${#other_args[@]} -eq 0 ]]; then
5
+ > printf "{{ strings[:missing_required_argument] % { arg: catch_all.label, usage: usage_string } }}\n"
6
+ > exit 1
7
+ > fi
8
+ >
9
+
10
+ end
@@ -0,0 +1,42 @@
1
+ = view_marker
2
+
3
+ > "" )
4
+ > {{ function_name }}_usage
5
+ > exit 1
6
+ > ;;
7
+ >
8
+ > * )
9
+
10
+ if default_command
11
+ > action="{{ default_command.name }}"
12
+ > {{ default_command.function_name }}_parse_requirements "$@"
13
+ > shift $#
14
+ > ;;
15
+ >
16
+
17
+ elsif extensible.is_a? String
18
+ > if [[ -x "$(command -v "{{ extensible }}")" ]]; then
19
+ > exec {{ extensible }} "$@"
20
+ > else
21
+ > printf "{{ strings[:invalid_command] }}\n" "$action"
22
+ > exit 1
23
+ > fi
24
+ >
25
+
26
+ elsif extensible
27
+ > if [[ -x "$(command -v "{{ function_name }}-$action")" ]]; then
28
+ > shift
29
+ > exec "{{ function_name }}-$action" "$@"
30
+ > else
31
+ > printf "{{ strings[:invalid_command] }}\n" "$action"
32
+ > exit 1
33
+ > fi
34
+ >
35
+
36
+ else
37
+ > printf "{{ strings[:invalid_command] }}\n" "$action"
38
+ > exit 1
39
+ > ;;
40
+ >
41
+
42
+ end
@@ -0,0 +1,29 @@
1
+ = view_marker
2
+
3
+ if commands.any?
4
+ > action=${1:-}
5
+ >
6
+ > case $action in
7
+ > -* )
8
+ > ;;
9
+ >
10
+
11
+ commands.each do |command|
12
+ > {{ command.aliases.join " | " }} )
13
+ > action="{{ command.name }}"
14
+ > shift
15
+ > {{ command.function_name }}_parse_requirements "$@"
16
+ > shift $#
17
+ > ;;
18
+ >
19
+
20
+ end
21
+
22
+ = render :command_fallback
23
+ > esac
24
+ >
25
+
26
+ else
27
+ > action="{{ action_name }}"
28
+
29
+ end
@@ -0,0 +1,5 @@
1
+ = view_marker
2
+
3
+ deep_commands.each do |command|
4
+ = command.render :function unless command.commands.any?
5
+ end
@@ -0,0 +1,13 @@
1
+ if default_args.any? or default_flags.any?
2
+ = view_marker
3
+
4
+ default_args.each do |arg|
5
+ > [[ -n ${args[{{ arg.name }}]:-} ]] || args[{{ arg.name }}]="{{ arg.default }}"
6
+ end
7
+
8
+ default_flags.each do |flag|
9
+ > [[ -n ${args[{{ flag.long }}]:-} ]] || args[{{ flag.long }}]="{{ flag.default }}"
10
+ end
11
+
12
+ >
13
+ end
@@ -0,0 +1,7 @@
1
+ > ## Code here runs inside the initialize() function
2
+ > ## Use it for anything that you need to run before any other function, like
3
+ > ## setting environment vairables:
4
+ > ## CONFIG_FILE=settings.ini
5
+ > ##
6
+ > ## Feel free to empty (but not delete) this file.
7
+ >
@@ -0,0 +1,4 @@
1
+ > echo "# this file is located in '{{ "#{Settings.source_dir}/#{filename}" }}'"
2
+ > echo "# you can edit it freely and regenerate (it will not be overwritten)"
3
+ > inspect_args
4
+ >
@@ -0,0 +1,5 @@
1
+ > echo "# this file is located in '{{ "#{Settings.source_dir}/#{filename}" }}'"
2
+ > echo "# code for '{{ full_name }}' goes here"
3
+ > echo "# you can edit it freely and regenerate (it will not be overwritten)"
4
+ > inspect_args
5
+ >
@@ -0,0 +1,10 @@
1
+ if dependencies
2
+ = view_marker
3
+
4
+ dependencies.each do |dependency|
5
+ > if ! [[ -x "$(command -v {{ dependency }})" ]]; then
6
+ > printf "{{ strings[:missing_dependency] % { dependency: dependency } }}\n"
7
+ > exit 1
8
+ > fi
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ if default_environment_variables.any? or required_environment_variables.any?
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
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"
14
+ > exit 1
15
+ > fi
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ = view_marker
2
+
3
+ > case "${1:-}" in
4
+
5
+ if root_command?
6
+ = short_flag_exist?("-v") ? "--version )" : "--version | -v )"
7
+ > version_command
8
+ > exit
9
+ > ;;
10
+ >
11
+ end
12
+
13
+ = short_flag_exist?("-h") ? "--help )" : "--help | -h )"
14
+ > long_usage=yes
15
+ > <%= function_name %>_usage
16
+ > exit
17
+ > ;;
18
+ >
19
+ > esac
20
+ >
@@ -0,0 +1,5 @@
1
+ = view_marker
2
+
3
+ > printf "{{ footer.gsub("\n", '\n').gsub('"', '\"') }}\n"
4
+ > echo
5
+ >
@@ -0,0 +1,6 @@
1
+ = view_marker
2
+
3
+ > {{ function_name }}_command() {
4
+ = load_user_file(filename).indent 2
5
+ > }
6
+ >
@@ -0,0 +1,12 @@
1
+ = view_marker
2
+
3
+ > initialize() {
4
+ > version="<%= version %>"
5
+ > long_usage=''
6
+ > {{ Settings.strict ? "set -euo pipefail" : "set -e" }}
7
+ >
8
+
9
+ = load_user_file("initialize.sh", placeholder: false).indent 2
10
+
11
+ > }
12
+ >