qb 0.3.25 → 0.4.0

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/ansible.cfg +10 -1
  4. data/exe/.qb_interop_receive +3 -10
  5. data/exe/qb +8 -2
  6. data/lib/python/qb/__init__.py +6 -0
  7. data/{roles/qb/ruby/rspec/setup/tasks/persistence.yml → lib/python/qb/ansible/__init__.py} +0 -0
  8. data/lib/python/qb/ansible/modules/__init__.py +0 -0
  9. data/lib/python/qb/ansible/modules/docker/__init__.py +0 -0
  10. data/lib/python/qb/ansible/modules/docker/client.py +177 -0
  11. data/lib/python/qb/ansible/modules/docker/image_manager.py +754 -0
  12. data/lib/python/qb/ipc/__init__.py +0 -0
  13. data/lib/python/qb/ipc/stdio/__init__.py +99 -0
  14. data/lib/python/qb/ipc/stdio/logging.py +151 -0
  15. data/lib/qb.rb +3 -3
  16. data/lib/qb/ansible/cmds/playbook.rb +5 -14
  17. data/lib/qb/ansible/env.rb +36 -6
  18. data/lib/qb/ansible/module.rb +396 -152
  19. data/lib/qb/ansible/module/response.rb +195 -0
  20. data/lib/qb/ansible/modules.rb +42 -0
  21. data/lib/qb/ansible/modules/docker/image.rb +273 -0
  22. data/lib/qb/cli.rb +5 -18
  23. data/lib/qb/cli/run.rb +2 -2
  24. data/lib/qb/data.rb +22 -0
  25. data/lib/qb/data/immutable.rb +39 -0
  26. data/lib/qb/docker.rb +2 -0
  27. data/lib/qb/docker/cli.rb +430 -0
  28. data/lib/qb/docker/image.rb +207 -0
  29. data/lib/qb/docker/image/name.rb +309 -0
  30. data/lib/qb/docker/image/tag.rb +113 -0
  31. data/lib/qb/docker/repo.rb +0 -0
  32. data/lib/qb/errors.rb +17 -3
  33. data/lib/qb/execution.rb +83 -0
  34. data/lib/qb/ipc.rb +48 -0
  35. data/lib/qb/ipc/stdio.rb +32 -0
  36. data/lib/qb/ipc/stdio/client.rb +267 -0
  37. data/lib/qb/ipc/stdio/server.rb +229 -0
  38. data/lib/qb/ipc/stdio/server/in_service.rb +18 -0
  39. data/lib/qb/ipc/stdio/server/log_service.rb +168 -0
  40. data/lib/qb/ipc/stdio/server/out_service.rb +20 -0
  41. data/lib/qb/ipc/stdio/server/service.rb +229 -0
  42. data/lib/qb/options.rb +360 -502
  43. data/lib/qb/options/option.rb +293 -115
  44. data/lib/qb/options/option/option_parser_concern.rb +228 -0
  45. data/lib/qb/options/types.rb +73 -0
  46. data/lib/qb/package.rb +0 -1
  47. data/lib/qb/package/version.rb +179 -58
  48. data/lib/qb/package/version/from.rb +192 -51
  49. data/lib/qb/package/version/leveled.rb +1 -1
  50. data/lib/qb/path.rb +3 -2
  51. data/lib/qb/repo/git.rb +9 -85
  52. data/lib/qb/role/default_dir.rb +2 -2
  53. data/lib/qb/role/errors.rb +2 -8
  54. data/lib/qb/util.rb +1 -2
  55. data/lib/qb/util/bundler.rb +73 -43
  56. data/lib/qb/util/decorators.rb +99 -0
  57. data/lib/qb/util/interop.rb +7 -8
  58. data/lib/qb/util/resource.rb +12 -13
  59. data/lib/qb/version.rb +10 -0
  60. data/library/path_facts +5 -10
  61. data/library/qb.module.rb +105 -0
  62. data/library/stream +6 -26
  63. data/load/ansible/module/autorun.rb +25 -0
  64. data/load/ansible/module/script.rb +123 -0
  65. data/load/rebundle.rb +39 -0
  66. data/plugins/filter/dict_filters.py +56 -0
  67. data/plugins/{filter_plugins/path_plugins.py → filter/path_filters.py} +0 -0
  68. data/plugins/{filter_plugins/ruby_interop_plugins.py → filter/ruby_interop_filters.py} +1 -17
  69. data/plugins/{filter_plugins/string_plugins.py → filter/string_filters.py} +1 -20
  70. data/plugins/{filter_plugins/version_plugins.py → filter/version_filters.py} +3 -18
  71. data/plugins/{lookup_plugins/every.py → lookup/every_lookups.py} +0 -0
  72. data/plugins/{lookup_plugins/resolve.py → lookup/resolve_lookups.py} +0 -0
  73. data/plugins/{lookup_plugins/version.py → lookup/version_lookups.py} +0 -16
  74. data/plugins/test/dict_tests.py +36 -0
  75. data/plugins/test/string_tests.py +36 -0
  76. data/qb.gemspec +7 -3
  77. data/roles/nrser.rb/library/set_fact_with_ruby.rb +3 -9
  78. data/roles/nrser.state_mate/library/state +3 -17
  79. data/roles/qb/call/meta/qb.yml +1 -1
  80. data/roles/qb/dev/ref/repo/git/meta/qb.yml +1 -1
  81. data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/defaults/main.yml +1 -1
  82. data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/meta/main.yml +3 -2
  83. data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/meta/qb.yml +12 -7
  84. data/roles/qb/docker/mac/kubernetes/tasks/main.yml +45 -0
  85. data/roles/qb/git/check/clean/meta/qb.yml +1 -1
  86. data/roles/qb/git/ignore/meta/qb +10 -3
  87. data/roles/qb/git/submodule/update/library/git_submodule_update +17 -27
  88. data/roles/qb/github/pages/setup/meta/qb.yml +1 -1
  89. data/roles/qb/labs/atom/apm/meta/qb.yml +1 -1
  90. data/roles/qb/osx/git/change_case/meta/qb.yml +1 -1
  91. data/roles/qb/osx/notif/meta/qb.yml +1 -1
  92. data/roles/qb/pkg/bump/library/bump +4 -16
  93. data/roles/qb/role/qb/defaults/main.yml +2 -0
  94. data/roles/qb/role/qb/meta/qb.yml +10 -5
  95. data/roles/qb/role/qb/templates/qb.yml.j2 +7 -2
  96. data/roles/qb/role/templates/library/module.rb.j2 +12 -23
  97. data/roles/qb/role/templates/meta/main.yml.j2 +14 -1
  98. data/roles/qb/ruby/bundler/meta/qb.yml +1 -1
  99. data/roles/qb/ruby/dependency/meta/qb.yml +1 -1
  100. data/roles/qb/ruby/gem/bin_stubs/meta/qb.yml +1 -1
  101. data/roles/qb/ruby/gem/bin_stubs/templates/console +8 -2
  102. data/roles/qb/ruby/gem/build/meta/qb.yml +1 -1
  103. data/roles/qb/ruby/gem/new/meta/qb.yml +1 -1
  104. data/roles/qb/ruby/nrser/rspex/generate/meta/qb.yml +5 -5
  105. data/roles/qb/ruby/nrser/rspex/issue/meta/qb.yml +1 -1
  106. data/roles/qb/ruby/yard/clean/meta/qb.yml +1 -1
  107. data/roles/qb/ruby/yard/config/library/yard.get_output_dir +5 -15
  108. data/roles/qb/ruby/yard/config/meta/qb.yml +1 -1
  109. data/roles/qb/ruby/yard/setup/meta/qb.yml +1 -1
  110. metadata +71 -22
  111. data/lib/qb/ansible_module.rb +0 -5
  112. data/lib/qb/util/stdio.rb +0 -187
  113. data/roles/qb/ruby/rspec/setup/tasks/main.yml +0 -4
@@ -1,542 +1,400 @@
1
1
  require 'optparse'
2
2
 
3
- require_relative "role/errors"
4
- require_relative "options/option"
5
- require 'qb/package/version'
3
+ require_relative "./role/errors"
4
+ require_relative './package/version'
6
5
 
7
- require 'nrser/refinements'
8
- using NRSER
6
+ require 'nrser/refinements/types'
7
+ using NRSER::Types
9
8
 
10
9
 
11
- module QB
12
- class Options
13
- # Mixins
14
- # ========================================================================
15
-
16
- include SemanticLogger::Loggable
17
-
18
-
19
- # Constants
20
- # =======================================================================
21
-
22
- # Default initial values for {#qb}.
23
- #
24
- # @return [Hash]
25
- #
26
- QB_DEFAULTS = {
27
- 'hosts' => ['localhost'].freeze,
28
- 'facts' => true,
29
- 'print' => [].freeze,
30
- 'verbose' => false,
31
- 'run' => true,
32
- 'ask' => false,
33
- }.freeze
34
-
35
-
36
- # Appended on the end of an `opts.on` call to create a newline after
37
- # the option (making the help output a bit easier to read)
38
- #
39
- # You might think the empty string would be reasonable, but OptionParser
40
- # blows up if you do that.
41
- #
42
- # @return [String]
43
- #
44
- SPACER = ' '
10
+ class QB::Options
11
+
12
+ # Sub-Tree Requirements
13
+ # ========================================================================
14
+
15
+ require_relative './options/types'
16
+ require_relative './options/option'
17
+
18
+
19
+ # Constants
20
+ # =======================================================================
21
+
22
+ # Default initial values for {#qb}.
23
+ #
24
+ # @return [Hash]
25
+ #
26
+ QB_DEFAULTS = {
27
+ 'hosts' => ['localhost'].freeze,
28
+ 'facts' => true,
29
+ 'print' => [].freeze,
30
+ 'verbose' => false,
31
+ 'run' => true,
32
+ 'ask' => false,
33
+ }.freeze
34
+
35
+
36
+ # Appended on the end of an `opts.on` call to create a newline after
37
+ # the option (making the help output a bit easier to read)
38
+ #
39
+ # You might think the empty string would be reasonable, but OptionParser
40
+ # blows up if you do that.
41
+ #
42
+ # @return [String]
43
+ #
44
+ SPACER = ' '
45
+
46
+
47
+ # Mixins
48
+ # ========================================================================
49
+
50
+ include NRSER::Log::Mixin
51
+
52
+
53
+ # Attributes
54
+ # =======================================================================
55
+
56
+ # @!attribute [r] ansible
57
+ # @return [Hash<String, String>]
58
+ # options to pass through to ansible-playbook.
59
+ attr_reader :ansible
60
+
61
+ # @!attribute [r] role_options
62
+ # @return [Hash<String, QB::Options::Option>]
63
+ # options to pass through to ansible-playbook.
64
+ attr_reader :role_options
65
+
66
+ # @!attribute [r] qb
67
+ # @return [Hash<String, *>]
68
+ # common qb-level options.
69
+ attr_reader :qb
70
+
71
+ # class methods
72
+ # =======================================================================
73
+
74
+ # turn a name into a "command line" version by replacing underscores with
75
+ # dashes.
76
+ #
77
+ # @param [String] option_name
78
+ # the input option name.
79
+ #
80
+ # @return [String]
81
+ # the CLI-ized name.
82
+ #
83
+ # @example
84
+ # QB::Options.cli_ize_name "my_var" # => "my-var"
85
+ #
86
+ def self.cli_ize_name option_name
87
+ option_name.gsub '_', '-'
88
+ end
89
+
90
+ # turn a name into a "ruby / ansible variable" version by replacing
91
+ # dashes with underscores.
92
+ #
93
+ # @param [String] option_name
94
+ # the input option name.
95
+ #
96
+ # @return [String]
97
+ # the ruby / ansible var-ized name.
98
+ #
99
+ # @example
100
+ # QB::Options.cli_ize_name "my-var" # => "my_var"
101
+ #
102
+ def self.var_ize_name option_name
103
+ option_name.gsub '-', '_'
104
+ end
105
+
106
+ def self.include_role opts, options, include_meta, include_path
107
+ role_name = include_meta['include']
108
+ role = QB::Role.require role_name
109
+ new_include_path = if include_meta.key? 'as'
110
+ case include_meta['as']
111
+ when nil, false
112
+ # include it in with the parent role's options
113
+ include_path
114
+ when String
115
+ include_path + [include_meta['as']]
116
+ else
117
+ raise QB::Role::MetadataError.new,
118
+ "bad 'as' value: #{ include_meta.inspect }"
119
+ end
120
+ else
121
+ include_path + [role.namespaceless]
122
+ end
45
123
 
124
+ QB.debug "including #{ role.name } as #{ new_include_path.join('-') }"
46
125
 
47
- # Attributes
48
- # =======================================================================
126
+ opts.separator "Options for included #{ role.name } role:"
49
127
 
50
- # @!attribute [r] ansible
51
- # @return [Hash<String, String>]
52
- # options to pass through to ansible-playbook.
53
- attr_reader :ansible
128
+ add opts, options, role, new_include_path
129
+ end
130
+
131
+
132
+ # Add the options from a role to the OptionParser
133
+ #
134
+ # @param [OptionParser] opts
135
+ # The option parser to add options to.
136
+ #
137
+ def self.add opts, options, role, include_path = []
138
+ QB.debug "adding options", "role" => role
54
139
 
55
- # @!attribute [r] role_options
56
- # @return [Hash<String, QB::Options::Option>]
57
- # options to pass through to ansible-playbook.
58
- attr_reader :role_options
140
+ role.option_metas.each do |option_meta|
141
+ if option_meta.key? 'include'
142
+ include_role opts, options, option_meta, include_path
143
+
144
+ else
145
+ # create an option
146
+ option = Option.new role, option_meta, include_path
147
+
148
+ option.option_parser_add opts, included: !include_path.empty?
149
+
150
+ options[option.cli_name] = option
151
+ end
152
+ end # each var
153
+ end # add
154
+
155
+
156
+ # Destructively removes options from `@argv` and populates ansible, role,
157
+ # and qb option hashes.
158
+ #
159
+ # @param [QB::Role] role
160
+ # the role to parse the options for.
161
+ #
162
+ # @param [Array<String>] args
163
+ # CLI args -- `ARGV` with the role arg shifted off.
164
+ #
165
+ # @return [Array<Hash<String, Option|Object>>]
166
+ # a two-element array:
167
+ #
168
+ # 1. the options for the role, hash of Option#cli_name to Option
169
+ # instances.
170
+ #
171
+ # 2. the general qb options, hash of String key to option values.
172
+ #
173
+ # @raise if bad options are found.
174
+ #
175
+ def self.parse! role, argv
176
+ options = self.new role, argv
177
+ [options.role_options, options.qb]
178
+ end
179
+
180
+
181
+ # Constructor
182
+ # =======================================================================
183
+
184
+ # @param [Role] role
185
+ # the role to parse the args for.
186
+ #
187
+ def initialize role, argv
188
+ @role = role
189
+ @argv = argv
190
+ @qb = QB_DEFAULTS.dup
59
191
 
60
- # @!attribute [r] qb
61
- # @return [Hash<String, *>]
62
- # common qb-level options.
63
- attr_reader :qb
192
+ parse!
193
+ end
194
+
195
+
196
+ # @todo Document ask? method.
197
+ #
198
+ # @param [type] arg_name
199
+ # @todo Add name param description.
200
+ #
201
+ # @return [return_type]
202
+ # @todo Document return value.
203
+ #
204
+ def ask?
205
+ @qb['ask']
206
+ end # #ask?
207
+
208
+
209
+
210
+ private
211
+ # =======================================================================
212
+
213
+ # destructively removes options from `@argv` and populates ansible, role,
214
+ # and qb option hashes.
215
+ def parse!
216
+ parse_ansible!
64
217
 
65
- # class methods
66
- # =======================================================================
67
-
68
- # turn a name into a "command line" version by replacing underscores with
69
- # dashes.
70
- #
71
- # @param [String] option_name
72
- # the input option name.
73
- #
74
- # @return [String]
75
- # the CLI-ized name.
76
- #
77
- # @example
78
- # QB::Options.cli_ize_name "my_var" # => "my-var"
79
- #
80
- def self.cli_ize_name option_name
81
- option_name.gsub '_', '-'
82
- end
218
+ @role_options = {}
83
219
 
84
- # turn a name into a "ruby / ansible variable" version by replacing
85
- # dashes with underscores.
86
- #
87
- # @param [String] option_name
88
- # the input option name.
89
- #
90
- # @return [String]
91
- # the ruby / ansible var-ized name.
92
- #
93
- # @example
94
- # QB::Options.cli_ize_name "my-var" # => "my_var"
95
- #
96
- def self.var_ize_name option_name
97
- option_name.gsub '-', '_'
220
+ if @role.meta['default_user']
221
+ @qb['user'] = @role.meta['default_user']
98
222
  end
99
223
 
100
- def self.include_role opts, options, include_meta, include_path
101
- role_name = include_meta['include']
102
- role = QB::Role.require role_name
103
- new_include_path = if include_meta.key? 'as'
104
- case include_meta['as']
105
- when nil, false
106
- # include it in with the parent role's options
107
- include_path
108
- when String
109
- include_path + [include_meta['as']]
110
- else
111
- raise QB::Role::MetadataError.new,
112
- "bad 'as' value: #{ include_meta.inspect }"
113
- end
114
- else
115
- include_path + [role.namespaceless]
224
+ opt_parser = OptionParser.new do |opts|
225
+ opts.accept(QB::Package::Version) do |string|
226
+ QB::Package::Version.from( string ).to_h
116
227
  end
117
228
 
118
- QB.debug "including #{ role.name } as #{ new_include_path.join('-') }"
229
+ opts.banner = @role.banner
119
230
 
120
- opts.separator "Options for included #{ role.name } role:"
231
+ opts.separator "Common options:"
121
232
 
122
- add opts, options, role, new_include_path
123
- end
124
-
125
- # add the options from a role to the OptionParser
126
- def self.add opts, options, role, include_path = []
127
- QB.debug "adding options", "role" => role
233
+ opts.on(
234
+ '-H',
235
+ '--HOSTS=HOSTS',
236
+ Array,
237
+ "set playbook host",
238
+ "DEFAULT: localhost",
239
+ SPACER
240
+ ) do |value|
241
+ @qb['hosts'] = value
242
+ end
128
243
 
129
- role.option_metas.each do |option_meta|
130
- if option_meta.key? 'include'
131
- include_role opts, options, option_meta, include_path
132
-
244
+ opts.on(
245
+ '-I',
246
+ '--INVENTORY=FILEPATH',
247
+ String,
248
+ "set inventory file",
249
+ SPACER
250
+ ) do |value|
251
+ @qb['inventory'] = value
252
+ end
253
+
254
+ opts.on(
255
+ '-U',
256
+ '--USER=USER',
257
+ String,
258
+ "ansible become user for the playbook",
259
+ SPACER
260
+ ) do |value|
261
+ @qb['user'] = value
262
+ end
263
+
264
+ opts.on(
265
+ '-T',
266
+ '--TAGS=TAGS',
267
+ Array,
268
+ "playbook tags",
269
+ SPACER
270
+ ) do |value|
271
+ @qb['tags'] = value
272
+ end
273
+
274
+ opts.on(
275
+ '-V[LEVEL]',
276
+ "run playbook in verbose mode. use like -VVV or -V3.",
277
+ SPACER
278
+ ) do |value|
279
+ # QB.debug "verbose", value: value
280
+
281
+ @qb['verbose'] = if value.nil?
282
+ 1
133
283
  else
134
- # create an option
135
- option = Option.new role, option_meta, include_path
136
-
137
- on_args = []
138
-
139
- if option.meta['type'] == 'boolean'
140
- # don't use short names when included (for now)
141
- if include_path.empty? && option.meta['short']
142
- on_args << "-#{ option.meta['short'] }"
143
- end
144
-
145
- on_args << "--[no-]#{ option.cli_name }"
146
-
284
+ case value
285
+ when '0'
286
+ false
287
+ when /^[1-4]$/
288
+ value.to_i
289
+ when /^[V]{1,3}$/i
290
+ value.length + 1
147
291
  else
148
- ruby_type = case option.meta['type']
149
- when nil
150
- raise QB::Role::MetadataError.squished <<-END
151
- must provide type in QB metadata for option
152
- #{ option.meta_name }
153
- END
154
-
155
- when 'string', 'str'
156
- String
157
-
158
- when 'array', 'list'
159
- Array
160
-
161
- when 'integer', 'int'
162
- Integer
163
-
164
- when 'version'
165
- QB::Package::Version
166
-
167
- when 'hash', 'dict'
168
- Class.new.tap { |klass|
169
- opts.accept(klass) { |value|
170
- value.split(',').map { |pair_str|
171
- split = pair_str.split ':'
172
- if split.length > 2
173
- raise ArgumentError.dedented <<-END
174
-
175
- Can only have a single ':' in `hash` options.
176
-
177
- Found #{ pair_str.inspect }
178
-
179
- In #{ value.inspect }
180
-
181
- END
182
- end
183
- [split[0], split[1]]
184
- }.to_h
185
- }
186
- }
187
-
188
- when 'path'
189
- String
190
- # Class.new.tap { |klass|
191
- # opts.accept(klass) { |value|
192
- #
193
- # }
194
- # }
195
-
196
- when 'glob'
197
- Class.new.tap { |klass|
198
- opts.accept(klass) { |glob|
199
- if glob.start_with? '//'
200
- glob = NRSER.git_root(Dir.getwd).
201
- join(glob[2..-1]).
202
- to_s
203
- end
204
-
205
- Dir[glob]
206
- }
207
- }
208
-
209
- when Hash
210
- if option.meta['type'].key? 'one_of'
211
- Class.new.tap { |klass|
212
- opts.accept(klass) { |value|
213
- if option.meta['type']['one_of'].include? value
214
- value
215
- else
216
- raise QB::Role::MetadataError,
217
- "option '#{ option.cli_name }' must be one of: #{ option.meta['type']['one_of'].join(', ') }"
218
- end
219
- }
220
- }
221
- else
222
- raise QB::Role::MetadataError,
223
- "bad type for option #{ option.meta_name }: #{ option.meta['type'].inspect }"
224
- end
225
- else
226
- raise QB::Role::MetadataError,
227
- "bad type for option #{ option.meta_name }: #{ option.meta['type'].inspect }"
228
- end
229
-
230
- # don't use short names when included (for now)
231
- if include_path.empty? && option.meta['short']
232
- on_args << "-#{ option.meta['short'] } #{ option.meta_name.upcase }"
233
- end
234
-
235
- if option.meta['accept_false']
236
- on_args << "--[no-]#{ option.cli_name }=#{ option.meta_name.upcase }"
237
- else
238
- on_args << "--#{ option.cli_name }=#{ option.meta_name.upcase }"
239
- end
240
-
241
-
242
- on_args << ruby_type
243
- end
244
-
245
- on_args << option.description
246
-
247
- if option.required?
248
- on_args << "REQUIRED."
249
- end
250
-
251
- if role.defaults.key? option.var_name
252
- if option.meta['type'] == 'boolean'
253
- on_args << if role.defaults[option.var_name]
254
- "DEFAULT: --#{ option.cli_name }"
255
- else
256
- "DEFAULT: --no-#{ option.cli_name }"
257
- end
258
- elsif !role.defaults[option.var_name].nil?
259
- on_args << "DEFAULT: #{ role.defaults[option.var_name] }"
260
- end
261
- end
262
-
263
- if option.has_examples?
264
- on_args << 'examples:'
265
-
266
- option.examples.each_with_index {|example, index|
267
- lines = example.lines.to_a
268
-
269
- # was this debuggin? had to be...
270
- # pp lines
271
-
272
- on_args << ((index + 1).to_s + '.').ljust(4) + lines.first.chomp
273
-
274
- lines[1..-1].each {|line|
275
- on_args << (" ".ljust(4) + line.chomp)
276
- }
277
- }
278
- end
279
-
280
- on_args << SPACER
281
-
282
- QB.debug "adding option", option: option, on_args: on_args
283
-
284
- opts.on(*on_args) do |value|
285
- QB.debug "setting option",
286
- option: option,
287
- value: value
288
-
289
- option.value = value
292
+ raise "bad verbose value: #{ value.inspect }"
290
293
  end
291
-
292
- options[option.cli_name] = option
293
294
  end
294
- end # each var
295
- end # add
296
-
297
- # destructively removes options from `@argv` and populates ansible, role,
298
- # and qb option hashes.
299
- #
300
- # @param [QB::Role] role
301
- # the role to parse the options for.
302
- #
303
- # @param [Array<String>] args
304
- # CLI args -- `ARGV` with the role arg shifted off.
305
- #
306
- # @return [Array<Hash<String, Option|Object>>]
307
- # a two-element array:
308
- #
309
- # 1. the options for the role, hash of Option#cli_name to Option
310
- # instances.
311
- #
312
- # 2. the general qb options, hash of String key to option values.
313
- #
314
- # @raise if bad options are found.
315
- #
316
- def self.parse! role, argv
317
- options = self.new role, argv
318
- [options.role_options, options.qb]
319
- end
320
-
321
- # constructor
322
- # =======================================================================
323
-
324
- # @param [Role] role
325
- # the role to parse the args for.
326
- #
327
- def initialize role, argv
328
- @role = role
329
- @argv = argv
330
- @qb = QB_DEFAULTS.dup
295
+ end
296
+
297
+ opts.on(
298
+ '--NO-FACTS',
299
+ "don't gather facts",
300
+ SPACER
301
+ ) do |value|
302
+ @qb['facts'] = false
303
+ end
304
+
305
+ opts.on(
306
+ '--PRINT=FLAGS',
307
+ Array,
308
+ "set what to print before running: options, env, cmd, playbook",
309
+ SPACER
310
+ ) do |value|
311
+ @qb['print'] = value
312
+ end
313
+
314
+ opts.on(
315
+ '--NO-RUN',
316
+ "don't run the playbook (useful to just print stuff)",
317
+ SPACER
318
+ ) do |value|
319
+ @qb['run'] = false
320
+ end
321
+
322
+ opts.on(
323
+ '-A',
324
+ '--ASK',
325
+ "interactively ask for argument and option values",
326
+ SPACER
327
+ ) do |value|
328
+ if value && !$stdin.isatty
329
+ raise ArgumentError.squished <<-END
330
+ Interactive args & options only works with TTY $stdin.
331
+ END
332
+ end
333
+
334
+ @qb['ask'] = value
335
+ end
336
+
337
+ opts.separator "Role options:"
338
+
339
+ self.class.add opts, @role_options, @role
331
340
 
332
- parse!
341
+ opts.on_tail("-h", "--help", "Show this message") do
342
+ puts opts
343
+
344
+ @role.puts_examples
345
+
346
+ exit
347
+ end
333
348
  end
334
349
 
350
+ opt_parser.parse! @argv
351
+ end # parse!
352
+
353
+
354
+ protected
355
+ # ========================================================================
335
356
 
336
-
337
- # @todo Document ask? method.
357
+ # Pull options that start with
358
+ #
359
+ # 1. `--ANSIBLE_`
360
+ # 1. `--ANSIBLE-`
361
+ # 2. `---`
338
362
  #
339
- # @param [type] arg_name
340
- # @todo Add name param description.
363
+ # out of `@argv` and stick them in `@ansible`.
341
364
  #
342
- # @return [return_type]
343
- # @todo Document return value.
365
+ # @return [nil]
366
+ # **Mutates** `@argv`.
344
367
  #
345
- def ask?
346
- @qb['ask']
347
- end # #ask?
348
-
349
-
350
-
351
- private
352
- # =======================================================================
353
-
354
- # destructively removes options from `@argv` and populates ansible, role,
355
- # and qb option hashes.
356
- def parse!
357
- parse_ansible!
368
+ def parse_ansible!
369
+ logger.debug "Parsing Ansible options...",
370
+ argv: @argv.dup
358
371
 
359
- @role_options = {}
372
+ @ansible = @role.default_ansible_options.clone
360
373
 
361
- if @role.meta['default_user']
362
- @qb['user'] = @role.meta['default_user']
363
- end
374
+ reg_exs = [
375
+ /\A\-\-ANSIBLE[\-\_]/,
376
+ /\A\-\-\-/,
377
+ ]
364
378
 
365
- opt_parser = OptionParser.new do |opts|
366
- opts.accept(QB::Package::Version) do |string|
367
- QB::Package::Version.from( string ).to_h
368
- end
369
-
370
- opts.banner = @role.banner
371
-
372
- opts.separator "Common options:"
373
-
374
- opts.on(
375
- '-H',
376
- '--HOSTS=HOSTS',
377
- Array,
378
- "set playbook host",
379
- "DEFAULT: localhost",
380
- SPACER
381
- ) do |value|
382
- @qb['hosts'] = value
383
- end
384
-
385
- opts.on(
386
- '-I',
387
- '--INVENTORY=FILEPATH',
388
- String,
389
- "set inventory file",
390
- SPACER
391
- ) do |value|
392
- @qb['inventory'] = value
393
- end
394
-
395
- opts.on(
396
- '-U',
397
- '--USER=USER',
398
- String,
399
- "ansible become user for the playbook",
400
- SPACER
401
- ) do |value|
402
- @qb['user'] = value
403
- end
404
-
405
- opts.on(
406
- '-T',
407
- '--TAGS=TAGS',
408
- Array,
409
- "playbook tags",
410
- SPACER
411
- ) do |value|
412
- @qb['tags'] = value
413
- end
414
-
415
- opts.on(
416
- '-V[LEVEL]',
417
- "run playbook in verbose mode. use like -VVV or -V3.",
418
- SPACER
419
- ) do |value|
420
- # QB.debug "verbose", value: value
379
+ @argv.reject! {|shellword|
380
+ if re = reg_exs.find {|re| re =~ shellword}
381
+ name = shellword.sub re, ''
421
382
 
422
- @qb['verbose'] = if value.nil?
423
- 1
424
- else
425
- case value
426
- when '0'
427
- false
428
- when /^[1-4]$/
429
- value.to_i
430
- when /^[V]{1,3}$/i
431
- value.length + 1
432
- else
433
- raise "bad verbose value: #{ value.inspect }"
434
- end
435
- end
436
- end
437
-
438
- opts.on(
439
- '--NO-FACTS',
440
- "don't gather facts",
441
- SPACER
442
- ) do |value|
443
- @qb['facts'] = false
444
- end
445
-
446
- opts.on(
447
- '--PRINT=FLAGS',
448
- Array,
449
- "set what to print before running: options, env, cmd, playbook",
450
- SPACER
451
- ) do |value|
452
- @qb['print'] = value
453
- end
454
-
455
- opts.on(
456
- '--NO-RUN',
457
- "don't run the playbook (useful to just print stuff)",
458
- SPACER
459
- ) do |value|
460
- @qb['run'] = false
461
- end
462
-
463
- opts.on(
464
- '-A',
465
- '--ASK',
466
- "interactively ask for argument and option values",
467
- SPACER
468
- ) do |value|
469
- if value && !$stdin.isatty
470
- raise ArgumentError.squished <<-END
471
- Interactive args & options only works with TTY $stdin.
472
- END
473
- end
383
+ value = true
474
384
 
475
- @qb['ask'] = value
476
- end
477
-
478
- opts.separator "Role options:"
479
-
480
- self.class.add opts, @role_options, @role
481
-
482
- opts.on_tail("-h", "--help", "Show this message") do
483
- puts opts
385
+ if name.include? '='
386
+ name, value = name.split('=', 2)
387
+ end
484
388
 
485
- @role.puts_examples
389
+ @ansible[name] = value
486
390
 
487
- exit
391
+ true
488
392
  end
489
- end
490
-
491
- opt_parser.parse! @argv
492
- end # parse!
493
-
494
-
495
- protected
496
- # ========================================================================
497
-
498
- # Pull options that start with
499
- #
500
- # 1. `--ANSIBLE_`
501
- # 1. `--ANSIBLE-`
502
- # 2. `---`
503
- #
504
- # out of `@argv` and stick them in `@ansible`.
505
- #
506
- # @return [nil]
507
- # **Mutates** `@argv`.
508
- #
509
- def parse_ansible!
510
- logger.debug "Parsing Ansible options...",
511
- argv: @argv.dup
512
-
513
- @ansible = @role.default_ansible_options.clone
514
-
515
- reg_exs = [
516
- /\A\-\-ANSIBLE[\-\_]/,
517
- /\A\-\-\-/,
518
- ]
519
-
520
- @argv.reject! {|shellword|
521
- if re = reg_exs.find {|re| re =~ shellword}
522
- name = shellword.sub re, ''
523
-
524
- value = true
525
-
526
- if name.include? '='
527
- name, value = name.split('=', 2)
528
- end
529
-
530
- @ansible[name] = value
531
-
532
- true
533
- end
534
- }
535
-
536
- nil
537
- end # #parse_ansible!
393
+ }
538
394
 
539
- # end protected
395
+ nil
396
+ end # #parse_ansible!
540
397
 
541
- end # Options
542
- end # QB
398
+ # end protected
399
+
400
+ end # class QB::Options