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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/ansible.cfg +10 -1
- data/exe/.qb_interop_receive +3 -10
- data/exe/qb +8 -2
- data/lib/python/qb/__init__.py +6 -0
- data/{roles/qb/ruby/rspec/setup/tasks/persistence.yml → lib/python/qb/ansible/__init__.py} +0 -0
- data/lib/python/qb/ansible/modules/__init__.py +0 -0
- data/lib/python/qb/ansible/modules/docker/__init__.py +0 -0
- data/lib/python/qb/ansible/modules/docker/client.py +177 -0
- data/lib/python/qb/ansible/modules/docker/image_manager.py +754 -0
- data/lib/python/qb/ipc/__init__.py +0 -0
- data/lib/python/qb/ipc/stdio/__init__.py +99 -0
- data/lib/python/qb/ipc/stdio/logging.py +151 -0
- data/lib/qb.rb +3 -3
- data/lib/qb/ansible/cmds/playbook.rb +5 -14
- data/lib/qb/ansible/env.rb +36 -6
- data/lib/qb/ansible/module.rb +396 -152
- data/lib/qb/ansible/module/response.rb +195 -0
- data/lib/qb/ansible/modules.rb +42 -0
- data/lib/qb/ansible/modules/docker/image.rb +273 -0
- data/lib/qb/cli.rb +5 -18
- data/lib/qb/cli/run.rb +2 -2
- data/lib/qb/data.rb +22 -0
- data/lib/qb/data/immutable.rb +39 -0
- data/lib/qb/docker.rb +2 -0
- data/lib/qb/docker/cli.rb +430 -0
- data/lib/qb/docker/image.rb +207 -0
- data/lib/qb/docker/image/name.rb +309 -0
- data/lib/qb/docker/image/tag.rb +113 -0
- data/lib/qb/docker/repo.rb +0 -0
- data/lib/qb/errors.rb +17 -3
- data/lib/qb/execution.rb +83 -0
- data/lib/qb/ipc.rb +48 -0
- data/lib/qb/ipc/stdio.rb +32 -0
- data/lib/qb/ipc/stdio/client.rb +267 -0
- data/lib/qb/ipc/stdio/server.rb +229 -0
- data/lib/qb/ipc/stdio/server/in_service.rb +18 -0
- data/lib/qb/ipc/stdio/server/log_service.rb +168 -0
- data/lib/qb/ipc/stdio/server/out_service.rb +20 -0
- data/lib/qb/ipc/stdio/server/service.rb +229 -0
- data/lib/qb/options.rb +360 -502
- data/lib/qb/options/option.rb +293 -115
- data/lib/qb/options/option/option_parser_concern.rb +228 -0
- data/lib/qb/options/types.rb +73 -0
- data/lib/qb/package.rb +0 -1
- data/lib/qb/package/version.rb +179 -58
- data/lib/qb/package/version/from.rb +192 -51
- data/lib/qb/package/version/leveled.rb +1 -1
- data/lib/qb/path.rb +3 -2
- data/lib/qb/repo/git.rb +9 -85
- data/lib/qb/role/default_dir.rb +2 -2
- data/lib/qb/role/errors.rb +2 -8
- data/lib/qb/util.rb +1 -2
- data/lib/qb/util/bundler.rb +73 -43
- data/lib/qb/util/decorators.rb +99 -0
- data/lib/qb/util/interop.rb +7 -8
- data/lib/qb/util/resource.rb +12 -13
- data/lib/qb/version.rb +10 -0
- data/library/path_facts +5 -10
- data/library/qb.module.rb +105 -0
- data/library/stream +6 -26
- data/load/ansible/module/autorun.rb +25 -0
- data/load/ansible/module/script.rb +123 -0
- data/load/rebundle.rb +39 -0
- data/plugins/filter/dict_filters.py +56 -0
- data/plugins/{filter_plugins/path_plugins.py → filter/path_filters.py} +0 -0
- data/plugins/{filter_plugins/ruby_interop_plugins.py → filter/ruby_interop_filters.py} +1 -17
- data/plugins/{filter_plugins/string_plugins.py → filter/string_filters.py} +1 -20
- data/plugins/{filter_plugins/version_plugins.py → filter/version_filters.py} +3 -18
- data/plugins/{lookup_plugins/every.py → lookup/every_lookups.py} +0 -0
- data/plugins/{lookup_plugins/resolve.py → lookup/resolve_lookups.py} +0 -0
- data/plugins/{lookup_plugins/version.py → lookup/version_lookups.py} +0 -16
- data/plugins/test/dict_tests.py +36 -0
- data/plugins/test/string_tests.py +36 -0
- data/qb.gemspec +7 -3
- data/roles/nrser.rb/library/set_fact_with_ruby.rb +3 -9
- data/roles/nrser.state_mate/library/state +3 -17
- data/roles/qb/call/meta/qb.yml +1 -1
- data/roles/qb/dev/ref/repo/git/meta/qb.yml +1 -1
- data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/defaults/main.yml +1 -1
- data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/meta/main.yml +3 -2
- data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/meta/qb.yml +12 -7
- data/roles/qb/docker/mac/kubernetes/tasks/main.yml +45 -0
- data/roles/qb/git/check/clean/meta/qb.yml +1 -1
- data/roles/qb/git/ignore/meta/qb +10 -3
- data/roles/qb/git/submodule/update/library/git_submodule_update +17 -27
- data/roles/qb/github/pages/setup/meta/qb.yml +1 -1
- data/roles/qb/labs/atom/apm/meta/qb.yml +1 -1
- data/roles/qb/osx/git/change_case/meta/qb.yml +1 -1
- data/roles/qb/osx/notif/meta/qb.yml +1 -1
- data/roles/qb/pkg/bump/library/bump +4 -16
- data/roles/qb/role/qb/defaults/main.yml +2 -0
- data/roles/qb/role/qb/meta/qb.yml +10 -5
- data/roles/qb/role/qb/templates/qb.yml.j2 +7 -2
- data/roles/qb/role/templates/library/module.rb.j2 +12 -23
- data/roles/qb/role/templates/meta/main.yml.j2 +14 -1
- data/roles/qb/ruby/bundler/meta/qb.yml +1 -1
- data/roles/qb/ruby/dependency/meta/qb.yml +1 -1
- data/roles/qb/ruby/gem/bin_stubs/meta/qb.yml +1 -1
- data/roles/qb/ruby/gem/bin_stubs/templates/console +8 -2
- data/roles/qb/ruby/gem/build/meta/qb.yml +1 -1
- data/roles/qb/ruby/gem/new/meta/qb.yml +1 -1
- data/roles/qb/ruby/nrser/rspex/generate/meta/qb.yml +5 -5
- data/roles/qb/ruby/nrser/rspex/issue/meta/qb.yml +1 -1
- data/roles/qb/ruby/yard/clean/meta/qb.yml +1 -1
- data/roles/qb/ruby/yard/config/library/yard.get_output_dir +5 -15
- data/roles/qb/ruby/yard/config/meta/qb.yml +1 -1
- data/roles/qb/ruby/yard/setup/meta/qb.yml +1 -1
- metadata +71 -22
- data/lib/qb/ansible_module.rb +0 -5
- data/lib/qb/util/stdio.rb +0 -187
- data/roles/qb/ruby/rspec/setup/tasks/main.yml +0 -4
data/lib/qb/options/option.rb
CHANGED
|
@@ -1,131 +1,309 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Requirements
|
|
5
|
+
# ========================================================================
|
|
6
|
+
|
|
7
|
+
# Deps
|
|
8
|
+
# ------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
# Need {Module#concerning}
|
|
11
|
+
require 'active_support/core_ext/module/concerning'
|
|
12
|
+
|
|
13
|
+
# Project / Package
|
|
14
|
+
# ------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
# Need additional {QB::Options::Types} for option type loading
|
|
17
|
+
require_relative './types'
|
|
18
|
+
|
|
19
|
+
# Need {OptionParserConcern} to handle fucking {OptionParser} :(
|
|
20
|
+
require_relative './option/option_parser_concern'
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Refinements
|
|
24
|
+
# ========================================================================
|
|
25
|
+
|
|
26
|
+
require 'nrser/refinements/types'
|
|
27
|
+
using NRSER::Types
|
|
28
|
+
|
|
29
|
+
require 'nrser/refinements/sugar'
|
|
30
|
+
using NRSER::Sugar
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Definitions
|
|
34
|
+
# ========================================================================
|
|
35
|
+
|
|
1
36
|
module QB
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
37
|
+
class Options
|
|
38
|
+
class Option
|
|
39
|
+
|
|
40
|
+
# Constants
|
|
41
|
+
# ========================================================================
|
|
42
|
+
|
|
43
|
+
EXAMPLES_KEYS = ['examples', 'example']
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Mixins
|
|
47
|
+
# ============================================================================
|
|
48
|
+
|
|
49
|
+
include NRSER::Log::Mixin
|
|
50
|
+
|
|
51
|
+
include OptionParserConcern
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Attributes
|
|
55
|
+
# ========================================================================
|
|
56
|
+
|
|
57
|
+
# the role that this option is for
|
|
58
|
+
attr_reader :role
|
|
59
|
+
|
|
60
|
+
# array of strings representing how this option was included
|
|
61
|
+
# empty for top-level options
|
|
62
|
+
attr_reader :include_path
|
|
63
|
+
|
|
64
|
+
# the name of the option in the qb metadata, equal to #meta['name']
|
|
65
|
+
attr_reader :meta_name
|
|
66
|
+
|
|
67
|
+
# the name that this option will be available in the cli as
|
|
68
|
+
attr_reader :cli_name
|
|
69
|
+
|
|
70
|
+
# the name that the value will be passed to ansible as
|
|
71
|
+
attr_reader :var_name
|
|
72
|
+
|
|
73
|
+
# the value of the option, or `nil` if we never assign one
|
|
74
|
+
attr_accessor :value
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# TODO document `type` attribute.
|
|
78
|
+
#
|
|
79
|
+
# @return [attr_type]
|
|
80
|
+
#
|
|
81
|
+
attr_reader :type
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# Construction
|
|
85
|
+
# ======================================================================
|
|
86
|
+
|
|
87
|
+
def initialize role, meta, include_path
|
|
88
|
+
@role = role
|
|
89
|
+
@meta = meta.with_indifferent_access
|
|
90
|
+
@include_path = include_path
|
|
91
|
+
|
|
92
|
+
@meta_name = meta.fetch 'name'
|
|
93
|
+
|
|
94
|
+
@cli_name = if @include_path.empty?
|
|
95
|
+
QB::Options.cli_ize_name @meta_name
|
|
96
|
+
else
|
|
97
|
+
QB::Options.cli_ize_name "#{ @include_path.join('-') }-#{ @meta_name }"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
@var_name = if meta[:var_name]
|
|
101
|
+
# prefer an explicit, exact variable name if provided
|
|
102
|
+
meta[:var_name]
|
|
103
|
+
elsif role.var_prefix
|
|
104
|
+
QB::Options.var_ize_name "#{ role.var_prefix }_#{ meta_name }"
|
|
105
|
+
else
|
|
106
|
+
QB::Options.var_ize_name meta_name
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Will be set when we find it out!
|
|
110
|
+
@value = nil
|
|
111
|
+
|
|
112
|
+
# Initialize `@type` var
|
|
113
|
+
init_type!
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
protected
|
|
118
|
+
# ========================================================================
|
|
119
|
+
|
|
120
|
+
# Initialize `@type` to the {NRSER::Types::Type} loaded from the option
|
|
121
|
+
# meta's `type` value.
|
|
122
|
+
#
|
|
123
|
+
# @protected
|
|
124
|
+
#
|
|
125
|
+
# @return [nil]
|
|
126
|
+
#
|
|
127
|
+
def init_type!
|
|
128
|
+
type_meta = meta[:type]
|
|
5
129
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# array of strings representing how this option was included
|
|
13
|
-
# empty for top-level options
|
|
14
|
-
attr_reader :include_path
|
|
15
|
-
|
|
16
|
-
# the name of the option in the qb metadata, equal to #meta['name']
|
|
17
|
-
attr_reader :meta_name
|
|
18
|
-
|
|
19
|
-
# the name that this option will be available in the cli as
|
|
20
|
-
attr_reader :cli_name
|
|
21
|
-
|
|
22
|
-
# the name that the value will be passed to ansible as
|
|
23
|
-
attr_reader :var_name
|
|
24
|
-
|
|
25
|
-
# the value of the option, or `nil` if we never assign one
|
|
26
|
-
attr_accessor :value
|
|
130
|
+
if type_meta.nil?
|
|
131
|
+
raise QB::Role::MetadataError.new \
|
|
132
|
+
"Option", meta_name, "for role", role.name, "missing `type`",
|
|
133
|
+
role_meta_path: role.meta_path,
|
|
134
|
+
option_meta: meta
|
|
135
|
+
end
|
|
27
136
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@meta = meta
|
|
31
|
-
@include_path = include_path
|
|
137
|
+
if t.non_empty_str === type_meta &&
|
|
138
|
+
type_meta.include?( '::' )
|
|
32
139
|
|
|
33
|
-
|
|
140
|
+
const = type_meta.safe_constantize
|
|
34
141
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
142
|
+
if const &&
|
|
143
|
+
const.is_a?( Class ) &&
|
|
144
|
+
( const < NRSER::Types::Type ||
|
|
145
|
+
const < NRSER::Props )
|
|
146
|
+
@type = const
|
|
147
|
+
return
|
|
39
148
|
end
|
|
40
149
|
|
|
41
|
-
@var_name = if @meta['var_name']
|
|
42
|
-
# prefer an explicit, exact variable name if provided
|
|
43
|
-
@meta['var_name']
|
|
44
|
-
elsif role.var_prefix
|
|
45
|
-
Options.var_ize_name "#{ role.var_prefix }_#{ @meta_name }"
|
|
46
|
-
else
|
|
47
|
-
Options.var_ize_name @meta_name
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
@value = nil
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# if the option is required in the cli
|
|
54
|
-
def required?
|
|
55
|
-
!!meta_or(['required', 'require'], false)
|
|
56
150
|
end
|
|
57
151
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def description
|
|
64
|
-
value = meta_or 'description',
|
|
65
|
-
"set the #{ @var_name } role variable"
|
|
152
|
+
message = t.match type_meta,
|
|
153
|
+
t.non_empty_str, ->( str ) {
|
|
154
|
+
NRSER::Message.new str
|
|
155
|
+
},
|
|
66
156
|
|
|
67
|
-
|
|
157
|
+
t.pair( value: (t.hash_ | t.array) ), ->( hash_pair ) {
|
|
158
|
+
name, params = hash_pair.first
|
|
68
159
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"#{ line_break }#{ @meta['type']['one_of'].join(line_break) }"
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
value
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def boolean?
|
|
78
|
-
(
|
|
79
|
-
meta['type'].is_a?(String) &&
|
|
80
|
-
['boolean', 'bool'].include?(meta['type'].downcase)
|
|
81
|
-
)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def usage
|
|
85
|
-
if boolean?
|
|
86
|
-
"--[no-]#{ cli_name }"
|
|
87
|
-
else
|
|
88
|
-
"--#{ cli_name }=#{ meta_name.upcase }"
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# test if the option has any examples.
|
|
93
|
-
#
|
|
94
|
-
# @return [Boolean]
|
|
95
|
-
#
|
|
96
|
-
def has_examples?
|
|
97
|
-
EXAMPLES_KEYS.any? {|key| meta.key? key}
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# get an array of examples for the option. returns `[]` if no examples
|
|
101
|
-
# are defined.
|
|
102
|
-
#
|
|
103
|
-
# @return [Array<String>]
|
|
104
|
-
#
|
|
105
|
-
def examples
|
|
106
|
-
value = meta_or EXAMPLES_KEYS, []
|
|
107
|
-
|
|
108
|
-
if value.is_a? String then [value] else value end
|
|
109
|
-
end
|
|
160
|
+
NRSER::Message.from( name, params ).symbolize_options
|
|
161
|
+
}
|
|
110
162
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
163
|
+
@type = [
|
|
164
|
+
QB::Options::Types,
|
|
165
|
+
t,
|
|
166
|
+
].find_map { |mod|
|
|
167
|
+
if mod.respond_to? message.symbol
|
|
168
|
+
begin
|
|
169
|
+
type = message.send_to mod
|
|
170
|
+
rescue Exception => error
|
|
171
|
+
logger.warn "Type factory failed",
|
|
172
|
+
{ message: message },
|
|
173
|
+
error
|
|
174
|
+
|
|
175
|
+
nil
|
|
176
|
+
else
|
|
177
|
+
type if type.is_a?( t::Type )
|
|
124
178
|
end
|
|
125
179
|
end
|
|
126
|
-
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if @type.nil?
|
|
183
|
+
raise QB::Role::MetadataError.new \
|
|
184
|
+
"Unable to find type factory for", type_meta,
|
|
185
|
+
role_meta_path: role.meta_path,
|
|
186
|
+
option_meta: meta,
|
|
187
|
+
message: message
|
|
127
188
|
end
|
|
128
189
|
|
|
129
|
-
end #
|
|
130
|
-
|
|
131
|
-
|
|
190
|
+
end # #init_type!
|
|
191
|
+
|
|
192
|
+
public # end protected *****************************************************
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# Instance Methods
|
|
196
|
+
# ========================================================================
|
|
197
|
+
|
|
198
|
+
def meta *keys, type: t.any, default: nil
|
|
199
|
+
return @meta if keys.empty?
|
|
200
|
+
|
|
201
|
+
keys.each do |key|
|
|
202
|
+
return type.check!( @meta[key] ) unless @meta[key].nil?
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
type.check! default
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def meta? *keys
|
|
210
|
+
keys.any? { |key| @meta.key? key }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def value_data
|
|
215
|
+
if value.respond_to? :to_data
|
|
216
|
+
value.to_data
|
|
217
|
+
else
|
|
218
|
+
value
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# Is the option is required in the CLI?
|
|
224
|
+
#
|
|
225
|
+
# @return [Boolean]
|
|
226
|
+
#
|
|
227
|
+
def required?
|
|
228
|
+
meta :required, :require, type: t.bool, default: false
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# Should we save the option value in `./.qb-options.yml`?
|
|
233
|
+
#
|
|
234
|
+
# @return [Boolean]
|
|
235
|
+
#
|
|
236
|
+
def save?
|
|
237
|
+
meta :save, type: t.bool, default: true
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# Description of the option.
|
|
242
|
+
#
|
|
243
|
+
# @return [String]
|
|
244
|
+
#
|
|
245
|
+
def description
|
|
246
|
+
meta(
|
|
247
|
+
:description,
|
|
248
|
+
default: "Set the #{ @var_name } role variable"
|
|
249
|
+
).to_s
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def boolean?
|
|
254
|
+
type == t.bool
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def usage
|
|
259
|
+
if boolean?
|
|
260
|
+
"--[no-]#{ cli_name }"
|
|
261
|
+
else
|
|
262
|
+
"--#{ cli_name }=#{ meta_name.upcase }"
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# test if the option has any examples.
|
|
268
|
+
#
|
|
269
|
+
# @return [Boolean]
|
|
270
|
+
#
|
|
271
|
+
def has_examples?
|
|
272
|
+
meta? *EXAMPLES_KEYS
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# get an array of examples for the option. returns `[]` if no examples
|
|
276
|
+
# are defined.
|
|
277
|
+
#
|
|
278
|
+
# @return [Array<String>]
|
|
279
|
+
#
|
|
280
|
+
def examples
|
|
281
|
+
Array meta( *EXAMPLES_KEYS, type: (t.nil | t.str | t.array( t.str )) )
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# Does the option accept `false` as value?
|
|
286
|
+
#
|
|
287
|
+
# If it does, and is not a boolean option, we also accept a `--no-<name>`
|
|
288
|
+
# option format to set the value to `false`.
|
|
289
|
+
#
|
|
290
|
+
# This is useful to explicitly tell QB "no, I don't want this", since we
|
|
291
|
+
# treat `nil`/`null` as the same as absent, which will cause a
|
|
292
|
+
# default value to be used (if available).
|
|
293
|
+
#
|
|
294
|
+
# This feature does not apply to {#boolean?} options themselves, only options
|
|
295
|
+
# that accept other values (though this method will of course return `true`
|
|
296
|
+
# for {#boolean?} options, since they do accept `false`).
|
|
297
|
+
#
|
|
298
|
+
# @return [Boolean]
|
|
299
|
+
#
|
|
300
|
+
def accept_false?
|
|
301
|
+
return true if meta[:accept_false]
|
|
302
|
+
|
|
303
|
+
return false if type.is_a?( Class ) && type < NRSER::Props
|
|
304
|
+
|
|
305
|
+
type.test?( false )
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
end; end; end # class QB::Options::Option
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Requirements
|
|
5
|
+
# =======================================================================
|
|
6
|
+
|
|
7
|
+
# Deps
|
|
8
|
+
# -----------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
# Need {ActiveSupport::Concern} duh
|
|
11
|
+
require 'active_support/concern'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Project / Package
|
|
15
|
+
# -----------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
require 'qb/util'
|
|
18
|
+
|
|
19
|
+
# Refinements
|
|
20
|
+
# =======================================================================
|
|
21
|
+
|
|
22
|
+
require 'nrser/refinements/types'
|
|
23
|
+
using NRSER::Types
|
|
24
|
+
|
|
25
|
+
require 'nrser/refinements/sugar'
|
|
26
|
+
using NRSER::Sugar
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Definitions
|
|
30
|
+
# =======================================================================
|
|
31
|
+
|
|
32
|
+
module QB
|
|
33
|
+
class Options
|
|
34
|
+
class Option
|
|
35
|
+
module OptionParserConcern
|
|
36
|
+
|
|
37
|
+
extend ActiveSupport::Concern
|
|
38
|
+
extend ::MethodDecorators
|
|
39
|
+
|
|
40
|
+
include NRSER::Log::Mixin
|
|
41
|
+
|
|
42
|
+
class TypeAcceptable
|
|
43
|
+
def self.name
|
|
44
|
+
if self == TypeAcceptable
|
|
45
|
+
"TypeAcceptable"
|
|
46
|
+
else
|
|
47
|
+
"TypeAcceptable<#{ type }>"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
singleton_class.send :alias_method, :to_s, :name
|
|
52
|
+
singleton_class.send :alias_method, :inspect, :name
|
|
53
|
+
|
|
54
|
+
def self.type
|
|
55
|
+
@type
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.parse string
|
|
59
|
+
type.from_s string
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def option_parser_spacer
|
|
65
|
+
' '
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def option_parser_type_acceptable
|
|
70
|
+
acceptable = Class.new TypeAcceptable
|
|
71
|
+
acceptable.instance_variable_set :@type, self.type
|
|
72
|
+
acceptable
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def option_parser_value_name
|
|
77
|
+
meta_name.upcase
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
+QB::Util::Decorators::EnumFor
|
|
82
|
+
def option_parser_format_multiline string, &block
|
|
83
|
+
lines = string.lines.to_a
|
|
84
|
+
|
|
85
|
+
lines.map do |line|
|
|
86
|
+
yield case line
|
|
87
|
+
when "\n"
|
|
88
|
+
# Need a space for {OptionParser} to respect it
|
|
89
|
+
option_parser_spacer + line
|
|
90
|
+
when /\A\s*\-\ /
|
|
91
|
+
line.sub '-', '*'
|
|
92
|
+
else
|
|
93
|
+
line
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
yield option_parser_spacer if lines.length > 1
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
+QB::Util::Decorators::EnumFor
|
|
102
|
+
def option_parser_description &block
|
|
103
|
+
option_parser_format_multiline description, &block
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
+QB::Util::Decorators::EnumFor
|
|
108
|
+
def option_parser_bool_args included:, &block
|
|
109
|
+
# Don't use short names when included (for now)
|
|
110
|
+
if !included && meta[:short]
|
|
111
|
+
yield "-#{ meta[:short] }"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
yield "--[no-]#{ cli_name }"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
+QB::Util::Decorators::EnumFor
|
|
119
|
+
def option_parser_non_bool_args included:, &block
|
|
120
|
+
# don't use short names when included (for now)
|
|
121
|
+
if !included && meta[:short]
|
|
122
|
+
yield "-#{ meta[:short] } #{ option_parser_value_name }"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# We allow options to also accept
|
|
126
|
+
if accept_false?
|
|
127
|
+
yield "--[no-]#{ cli_name }=#{ option_parser_value_name }"
|
|
128
|
+
else
|
|
129
|
+
yield "--#{ cli_name }=#{ option_parser_value_name }"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
yield option_parser_type_acceptable
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
+QB::Util::Decorators::EnumFor
|
|
137
|
+
def option_parser_default &block
|
|
138
|
+
ans_src_default = role.defaults[var_name]
|
|
139
|
+
|
|
140
|
+
# If we don't have shit in the role default Ansible source file, nothing
|
|
141
|
+
# to do here
|
|
142
|
+
return if ans_src_default.nil?
|
|
143
|
+
|
|
144
|
+
if boolean?
|
|
145
|
+
yield "DEFAULT: --#{ ans_src_default ? '' : 'no-' }#{ cli_name }"
|
|
146
|
+
else
|
|
147
|
+
# This is just the Ansible "source code", which is shitty and ugly
|
|
148
|
+
# for anything that's not a literal, but it at least gives you something
|
|
149
|
+
# to see
|
|
150
|
+
option_parser_format_multiline "DEFAULT: #{ ans_src_default }", &block
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
+QB::Util::Decorators::EnumFor
|
|
156
|
+
def option_parser_examples &block
|
|
157
|
+
return unless has_examples?
|
|
158
|
+
|
|
159
|
+
yield 'Examples:'
|
|
160
|
+
|
|
161
|
+
examples.each_with_index do |example, index|
|
|
162
|
+
lines = example.lines.to_a
|
|
163
|
+
|
|
164
|
+
yield ((index + 1).to_s + '.').ljust(4) + lines.first.chomp
|
|
165
|
+
|
|
166
|
+
lines[1..-1].each do |line|
|
|
167
|
+
yield " ".ljust(4) + line.chomp
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
+QB::Util::Decorators::EnumFor
|
|
174
|
+
def option_parser_type &block
|
|
175
|
+
option_parser_format_multiline "TYPE: #{ type }", &block
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
+QB::Util::Decorators::EnumFor
|
|
180
|
+
def option_parser_args included:, &block
|
|
181
|
+
if boolean?
|
|
182
|
+
option_parser_bool_args included: included, &block
|
|
183
|
+
else
|
|
184
|
+
option_parser_non_bool_args included: included, &block
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
option_parser_description &block
|
|
188
|
+
|
|
189
|
+
yield "REQUIRED." if required?
|
|
190
|
+
|
|
191
|
+
option_parser_type &block
|
|
192
|
+
|
|
193
|
+
option_parser_default &block
|
|
194
|
+
|
|
195
|
+
option_parser_examples &block
|
|
196
|
+
|
|
197
|
+
yield option_parser_spacer
|
|
198
|
+
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def option_parser_add option_parser, included:
|
|
203
|
+
args = option_parser_args( included: included ).to_a
|
|
204
|
+
|
|
205
|
+
args.find do |arg|
|
|
206
|
+
if arg.is_a?( Class )
|
|
207
|
+
option_parser.accept( arg ) do |value|
|
|
208
|
+
arg.parse value
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
true
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
logger.trace "Adding option to {OptionParser}",
|
|
216
|
+
option_meta_name: meta_name,
|
|
217
|
+
args: args
|
|
218
|
+
|
|
219
|
+
option_parser.on( *args ) do |value|
|
|
220
|
+
logger.debug "Setting option value",
|
|
221
|
+
option_meta_name: meta_name,
|
|
222
|
+
value: value
|
|
223
|
+
|
|
224
|
+
self.value = value
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
end; end; end; end # module QB::Options::Option::OptionParserConcern
|