qb 0.3.25 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/util/resource.rb
CHANGED
@@ -5,13 +5,7 @@
|
|
5
5
|
# -----------------------------------------------------------------------
|
6
6
|
|
7
7
|
require 'nrser'
|
8
|
-
|
9
|
-
|
10
|
-
# Refinements
|
11
|
-
# =======================================================================
|
12
|
-
|
13
|
-
require 'nrser/refinements'
|
14
|
-
using NRSER
|
8
|
+
require 'nrser/props/immutable/instance_variables'
|
15
9
|
|
16
10
|
|
17
11
|
# Declarations
|
@@ -27,10 +21,15 @@ module QB::Util; end
|
|
27
21
|
# Base class for QB "resources" - object representations of outside structures
|
28
22
|
# and concepts: things that live on disk, in remote systems or other runtimes.
|
29
23
|
#
|
30
|
-
|
31
|
-
|
32
|
-
#
|
33
|
-
#
|
34
|
-
|
35
|
-
|
24
|
+
class QB::Util::Resource
|
25
|
+
|
26
|
+
# Mixins
|
27
|
+
# =====================================================================
|
28
|
+
|
29
|
+
include NRSER::Props::Immutable::InstanceVariables
|
30
|
+
|
31
|
+
|
32
|
+
def initialize values = {}
|
33
|
+
initialize_props values
|
34
|
+
end # #initialize
|
36
35
|
end # class QB::Util::Resource
|
data/lib/qb/version.rb
CHANGED
@@ -34,6 +34,16 @@ module QB
|
|
34
34
|
# Class Methods
|
35
35
|
# =====================================================================
|
36
36
|
|
37
|
+
# Are we running in local development? Looks for the `//dev` directory's
|
38
|
+
# presence.
|
39
|
+
#
|
40
|
+
# @return [Boolean]
|
41
|
+
#
|
42
|
+
def self.local_dev?
|
43
|
+
(QB::ROOT / 'dev').directory?
|
44
|
+
end
|
45
|
+
|
46
|
+
|
37
47
|
def self.gemspec
|
38
48
|
Gem.loaded_specs[GEM_NAME]
|
39
49
|
end
|
data/library/path_facts
CHANGED
@@ -1,19 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# WANT_JSON
|
3
3
|
|
4
|
-
#
|
5
|
-
if ENV['
|
6
|
-
|
7
|
-
if k.start_with? 'QB_DEV_ENV_'
|
8
|
-
ENV[k.sub('QB_DEV_ENV_', '')] = v
|
9
|
-
end
|
10
|
-
}
|
11
|
-
require 'bundler/setup'
|
12
|
-
end
|
4
|
+
# Reinstate Bundler ENV vars if they have been moved
|
5
|
+
load ENV['QB_REBUNDLE_PATH'] if ENV['QB_REBUNDLE_PATH']
|
6
|
+
|
13
7
|
|
14
8
|
require 'ostruct'
|
15
9
|
|
16
10
|
require 'qb'
|
11
|
+
require 'qb/ansible/module'
|
17
12
|
require 'qb/package/version'
|
18
13
|
require 'cmds'
|
19
14
|
require 'pathname'
|
@@ -283,4 +278,4 @@ class PathFacts < QB::Ansible::Module
|
|
283
278
|
end
|
284
279
|
end
|
285
280
|
|
286
|
-
PathFacts.
|
281
|
+
PathFacts.run!
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# WANT_JSON
|
3
|
+
|
4
|
+
# Reinstate Bundler ENV vars if they have been moved
|
5
|
+
load ENV['QB_REBUNDLE_PATH'] if ENV['QB_REBUNDLE_PATH']
|
6
|
+
|
7
|
+
require 'qb/ansible/module'
|
8
|
+
|
9
|
+
require 'nrser'
|
10
|
+
require 'nrser/core_ext/string'
|
11
|
+
require 'nrser/types'
|
12
|
+
|
13
|
+
def t; NRSER::Types; end
|
14
|
+
|
15
|
+
QB::Ansible::Module.setup_io!
|
16
|
+
|
17
|
+
class QB_Ansible_Module_Runner < QB::Ansible::Module
|
18
|
+
|
19
|
+
|
20
|
+
# @!attribute [r] name
|
21
|
+
# Name of module to run (relative path from `//lib/qb/ansible/modules`)
|
22
|
+
#
|
23
|
+
# @return [PropRubyType]
|
24
|
+
#
|
25
|
+
arg :module_name,
|
26
|
+
type: t.non_empty_str,
|
27
|
+
aliases: [ :name ],
|
28
|
+
reader: { name: false }
|
29
|
+
|
30
|
+
arg :module_require,
|
31
|
+
type: (
|
32
|
+
t.nil | # Guess and try the require path
|
33
|
+
t.false | # Don't require anything; module class must already be loaded
|
34
|
+
t.non_empty_str | # String to require
|
35
|
+
t.list( t.non_empty_str ) # List of strings to require
|
36
|
+
),
|
37
|
+
aliases: [ :require ],
|
38
|
+
reader: { require: false }
|
39
|
+
|
40
|
+
arg :module_args,
|
41
|
+
type: t.map,
|
42
|
+
aliases: [ :args ],
|
43
|
+
reader: { args: false },
|
44
|
+
default: ->{ {} }
|
45
|
+
|
46
|
+
def main
|
47
|
+
class_name = module_name.camelize
|
48
|
+
class_path = module_name.underscore
|
49
|
+
|
50
|
+
logger.trace "Received module argument",
|
51
|
+
module_name: module_name,
|
52
|
+
class_name: class_name,
|
53
|
+
class_path: class_path,
|
54
|
+
module_require: module_require
|
55
|
+
|
56
|
+
unless class_name.start_with? '::'
|
57
|
+
class_name = "QB::Ansible::Modules::#{ class_name }"
|
58
|
+
end
|
59
|
+
|
60
|
+
require_paths = case module_require
|
61
|
+
when nil
|
62
|
+
if class_path.start_with? '/'
|
63
|
+
[ class_path[1..-1] ]
|
64
|
+
else
|
65
|
+
[ "qb/ansible/modules/#{ class_path }" ]
|
66
|
+
end
|
67
|
+
when false
|
68
|
+
[]
|
69
|
+
when String
|
70
|
+
[ module_require ]
|
71
|
+
when Array
|
72
|
+
module_require
|
73
|
+
end
|
74
|
+
|
75
|
+
if require_paths.empty?
|
76
|
+
logger.trace "No requiring any paths"
|
77
|
+
else
|
78
|
+
logger.trace "Requiring paths...",
|
79
|
+
require_paths: require_paths
|
80
|
+
|
81
|
+
require_paths.each do |require_path|
|
82
|
+
begin
|
83
|
+
require require_path
|
84
|
+
rescue LoadError => error
|
85
|
+
logger.warn "Failed to require #{ require_path.inspect }", error
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
module_class = class_name.to_const!
|
91
|
+
|
92
|
+
logger.trace "Loaded class",
|
93
|
+
module_class: module_class.to_s
|
94
|
+
|
95
|
+
instance = module_class.from_data module_args
|
96
|
+
instance.args_source = args_source
|
97
|
+
instance.args = args['args'] || args['module_args'] || {}
|
98
|
+
|
99
|
+
instance.run!
|
100
|
+
end
|
101
|
+
|
102
|
+
end # class QB_Ansible_Module_Runner
|
103
|
+
|
104
|
+
|
105
|
+
QB_Ansible_Module_Runner.run!
|
data/library/stream
CHANGED
@@ -1,29 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# WANT_JSON
|
3
3
|
|
4
|
-
#
|
5
|
-
|
6
|
-
# HACK Keep track of the ENV vars we overwrite so we can swap them back in
|
7
|
-
# later when we need to run the command.
|
8
|
-
#
|
9
|
-
$replaced_env_vars = {}
|
10
|
-
|
11
|
-
if ENV['QB_DEV_ENV']
|
12
|
-
ENV.each {|k, v|
|
13
|
-
if k.start_with? 'QB_DEV_ENV_'
|
14
|
-
key = k.sub('QB_DEV_ENV_', '')
|
15
|
-
$replaced_env_vars[key] = [ENV[key], v]
|
16
|
-
ENV[key] = v
|
17
|
-
end
|
18
|
-
}
|
19
|
-
require 'bundler/setup'
|
20
|
-
end
|
4
|
+
# Reinstate Bundler ENV vars if they have been moved
|
5
|
+
load ENV['QB_REBUNDLE_PATH'] if ENV['QB_REBUNDLE_PATH']
|
21
6
|
|
7
|
+
require 'nrser'
|
22
8
|
require 'qb'
|
9
|
+
require 'qb/ansible/module'
|
23
10
|
require 'cmds'
|
24
11
|
|
25
|
-
using NRSER
|
26
|
-
|
27
12
|
class Stream < QB::Ansible::Module
|
28
13
|
def main
|
29
14
|
template = @args['template'] || @args['cmd']
|
@@ -71,15 +56,10 @@ class Stream < QB::Ansible::Module
|
|
71
56
|
END
|
72
57
|
end
|
73
58
|
|
74
|
-
|
75
|
-
$replaced_env_vars.each do |key, (original, replacement)|
|
76
|
-
ENV[key] = original
|
77
|
-
end
|
78
|
-
|
79
|
-
cmd.stream!
|
59
|
+
qb_unbundle! { cmd.stream! }
|
80
60
|
|
81
61
|
changed!
|
82
62
|
end
|
83
63
|
end
|
84
64
|
|
85
|
-
Stream.
|
65
|
+
Stream.run!
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
# Reinstate Bundler ENV vars if they have been moved
|
3
|
+
load ENV['QB_REBUNDLE_PATH'] if ENV['QB_REBUNDLE_PATH']
|
4
|
+
|
5
|
+
require 'active_support/core_ext/class/subclasses'
|
6
|
+
require 'qb/ansible/module'
|
7
|
+
|
8
|
+
require 'nrser'
|
9
|
+
require 'nrser/types'
|
10
|
+
|
11
|
+
def t; NRSER::Types; end
|
12
|
+
|
13
|
+
QB::Ansible::Module.setup_io!
|
14
|
+
|
15
|
+
at_exit do
|
16
|
+
if $!
|
17
|
+
QB::Ansible::Module.logger.fatal "Error raised pre-execution", $!
|
18
|
+
else
|
19
|
+
QB::Ansible::Module.descendants.find_only { |klass|
|
20
|
+
begin
|
21
|
+
klass.instance_method( :main ).source_location[0] == $0
|
22
|
+
rescue; end
|
23
|
+
}.run!
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
|
2
|
+
# Reinstate Bundler ENV vars if they have been moved
|
3
|
+
load ENV['QB_REBUNDLE_PATH'] if ENV['QB_REBUNDLE_PATH']
|
4
|
+
|
5
|
+
require 'qb/ansible/module'
|
6
|
+
require 'nrser/types'
|
7
|
+
require 'nrser/core_ext/exception'
|
8
|
+
|
9
|
+
|
10
|
+
# Constants
|
11
|
+
# ========================================================================
|
12
|
+
|
13
|
+
MAIN = self
|
14
|
+
NAME = File.basename( $0 ).gsub( '.', '/' ).camelize
|
15
|
+
LOGGER = NRSER::Log[ NAME ]
|
16
|
+
RAW_ARGS, ARGS_SOURCE = QB::Ansible::Module.load_args
|
17
|
+
ARG_DEFS = {}
|
18
|
+
ARGS = {}
|
19
|
+
|
20
|
+
|
21
|
+
# Global Variables
|
22
|
+
# ============================================================================
|
23
|
+
|
24
|
+
$response = QB::Ansible::Module::Response.new
|
25
|
+
|
26
|
+
|
27
|
+
# Global Methods
|
28
|
+
# ============================================================================
|
29
|
+
|
30
|
+
# Constant Readers
|
31
|
+
# ----------------------------------------------------------------------------
|
32
|
+
#
|
33
|
+
# Just to make 'em feel familiar...
|
34
|
+
#
|
35
|
+
|
36
|
+
def logger; LOGGER; end
|
37
|
+
def t; NRSER::Types; end
|
38
|
+
def name; NAME; end
|
39
|
+
def raw_args; RAW_ARGS; end
|
40
|
+
def arg_defs; ARG_DEFS; end
|
41
|
+
def args; ARGS; end
|
42
|
+
def response; $response; end
|
43
|
+
|
44
|
+
|
45
|
+
def arg name, **opts
|
46
|
+
t.non_empty_sym.check! name
|
47
|
+
|
48
|
+
prop = NRSER::Props::Prop.new \
|
49
|
+
MAIN,
|
50
|
+
name,
|
51
|
+
reader: true,
|
52
|
+
writer: false, **opts
|
53
|
+
|
54
|
+
arg_defs[name] = prop
|
55
|
+
|
56
|
+
args[prop.name] = if raw_args.key? prop.name
|
57
|
+
prop.check! raw_args[prop.name]
|
58
|
+
else
|
59
|
+
prop.default **args
|
60
|
+
end
|
61
|
+
|
62
|
+
prop.names.each do |name|
|
63
|
+
MAIN.send :define_method, name do
|
64
|
+
args[prop.name]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def fail! msg, **values
|
71
|
+
$response = response.to_failure \
|
72
|
+
msg: msg,
|
73
|
+
**values
|
74
|
+
|
75
|
+
exit false
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def response_sent?
|
80
|
+
!!$response_sent
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def send_response!
|
85
|
+
if response_sent?
|
86
|
+
logger.warn "Response has already been sent, ignoring..."
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
# NOTE *Need* to assign here or it disappears after the `logger.fatal`
|
91
|
+
# call!
|
92
|
+
if (error = $!) && !error.is_a?( SystemExit )
|
93
|
+
# We failed!
|
94
|
+
|
95
|
+
# Log it
|
96
|
+
logger.fatal error
|
97
|
+
|
98
|
+
# Create a new response; don't want to carry whatever the current one
|
99
|
+
# has in it back? Maybe we do? Ans'y doesn't set facts when modules fail,
|
100
|
+
# it seems, so might not hurt...
|
101
|
+
$response = response.to_failure \
|
102
|
+
msg: error.to_s,
|
103
|
+
exception: error.format
|
104
|
+
end
|
105
|
+
|
106
|
+
response_data = response.to_data( add_class: false ).compact
|
107
|
+
|
108
|
+
logger.debug "Responding", response_data
|
109
|
+
STDOUT.print JSON.pretty_generate( response_data )
|
110
|
+
|
111
|
+
exit !response.failed
|
112
|
+
rescue SystemExit
|
113
|
+
raise
|
114
|
+
rescue Exception => error
|
115
|
+
logger.error "Internal QB Error: Failed to send response", error
|
116
|
+
exit false
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
at_exit { send_response! unless response_sent? }
|
121
|
+
|
122
|
+
|
123
|
+
QB::Ansible::Module.setup_io!
|
data/load/rebundle.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Restores Bundler ENV vars that were moved when spawning the Ansible process.
|
2
|
+
#
|
3
|
+
# See `//lib/qb/util/bundler.rb` for documentation on how and why we do this.
|
4
|
+
#
|
5
|
+
|
6
|
+
# Keep track of the ENV vars we overwrite so we can swap them back in
|
7
|
+
# later when we need to do things like shell out.
|
8
|
+
#
|
9
|
+
$qb_replaced_env_vars = {}
|
10
|
+
|
11
|
+
|
12
|
+
def qb_rebundle!
|
13
|
+
ENV.each do |k, v|
|
14
|
+
if k.start_with? 'QB_BUNDLER_ENV_'
|
15
|
+
key = k.sub 'QB_BUNDLER_ENV_', ''
|
16
|
+
$qb_replaced_env_vars[key] = [ENV[key], v]
|
17
|
+
ENV[key] = v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def qb_unbundle! &block
|
24
|
+
$qb_replaced_env_vars.each do |key, (original, replacement)|
|
25
|
+
ENV[key] = original
|
26
|
+
end
|
27
|
+
|
28
|
+
$qb_replaced_env_vars = {}
|
29
|
+
|
30
|
+
if block
|
31
|
+
block.call.tap { qb_rebundle! }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
qb_rebundle!
|
37
|
+
|
38
|
+
|
39
|
+
require 'bundler/setup'
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Imports
|
2
|
+
# ============================================================================
|
3
|
+
|
4
|
+
from __future__ import (absolute_import, division, print_function)
|
5
|
+
__metaclass__ = type
|
6
|
+
|
7
|
+
import sys
|
8
|
+
import re
|
9
|
+
import os
|
10
|
+
|
11
|
+
from ansible.errors import AnsibleError
|
12
|
+
from jinja2.filters import contextfilter
|
13
|
+
|
14
|
+
def to_dict( value ):
|
15
|
+
'''Call Python's built-in `dict()` on the value.
|
16
|
+
|
17
|
+
Can't believe this shit isn't built-in to Jinja/Ansible :/
|
18
|
+
'''
|
19
|
+
|
20
|
+
return dict( value )
|
21
|
+
|
22
|
+
|
23
|
+
@contextfilter
|
24
|
+
def select_by_keys( context, dct, test_name, *args, **kwds ):
|
25
|
+
# raise StandardError(
|
26
|
+
# "args: {}, kwds: {}".format( args, kwds )
|
27
|
+
# )
|
28
|
+
|
29
|
+
test = lambda key: context.environment.call_test(
|
30
|
+
test_name, key, args, kwds
|
31
|
+
)
|
32
|
+
|
33
|
+
new_dct = {}
|
34
|
+
|
35
|
+
for key, value in dct.iteritems():
|
36
|
+
if test( key ):
|
37
|
+
new_dct[key] = value
|
38
|
+
|
39
|
+
return new_dct
|
40
|
+
|
41
|
+
|
42
|
+
class FilterModule(object):
|
43
|
+
'''Some dict filters'''
|
44
|
+
|
45
|
+
def filters(self):
|
46
|
+
return {
|
47
|
+
'dict': to_dict,
|
48
|
+
'select_by_keys': select_by_keys,
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
# testing - call camel_case on first cli arg and print result
|
53
|
+
if __name__ == '__main__':
|
54
|
+
import doctest
|
55
|
+
doctest.testmod()
|
56
|
+
|