qb 0.3.25 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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