ansible-ruby 1.0.3 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 59e1d73a3de56b29f57a5cd7d44cd87fc9a21c90
4
- data.tar.gz: cf89185af3770233e0b043c88976c6de41fe8006
3
+ metadata.gz: 727699f832b62d2e6870209e65cbef3d3324b27c
4
+ data.tar.gz: 9f1012dd3e2979a07227e337cf7b055a20d246b3
5
5
  SHA512:
6
- metadata.gz: 732dc45ee62ab5280092c6bcb706761a4f23a814b9c4040f50855810b38de4aad7c212c1df40968604f49aa44463eaf28ac4e07f99bf17cfb0d94302d877347a
7
- data.tar.gz: 4b30771eb0007094a2d4d47a59e6dd0950e492b39bab0ee3578aba854920c226877f1835a8ed54d1063e82fd742ac9193df549f634d307459699f014caee3fc2
6
+ metadata.gz: c44972041ab6bb679378e79288ce3e973b5c0f5c50729e1ca5629178e9521ced8f5934f47689640f438f595307a716dcd54df197f32f7bff830b9f4f0d539b4d
7
+ data.tar.gz: 25d9c8ef06bd5065d23664bf9c8d403677316d5644247fd4c804d7e3ba1f7d480dd55c2c4436ae19f01921893f8ffe21718352b5255ffb8a01a628c82d87c78c
@@ -4,14 +4,43 @@ module Ansible
4
4
  module Ruby
5
5
  module DslBuilders
6
6
  class Args < Base
7
- def initialize
8
- super
9
- @result = {}
7
+ KERNEL_METHOD_OVERRIDES = [:system, :test, :warn, :sleep].freeze
8
+
9
+ def initialize(recipient, &block)
10
+ super()
11
+ @error_handler = block
12
+ @recipient = recipient
10
13
  end
11
14
 
12
15
  def _process_method(id, *args)
16
+ setter = "#{id}=".to_sym
17
+ @error_handler[id] if @error_handler && !@recipient.respond_to?(setter)
13
18
  value = args.length == 1 ? args[0] : args
14
- @result[id] = value
19
+ value = _convert_ast_node value
20
+ @recipient.send(setter, value)
21
+ end
22
+
23
+ KERNEL_METHOD_OVERRIDES.each do |method|
24
+ define_method(method) do |*args|
25
+ _process_method method, *args
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def _convert_ast_node(value)
32
+ case value
33
+ when DslBuilders::JinjaItemNode
34
+ value.to_s
35
+ when Hash
36
+ Hash[
37
+ value.map { |key, hash_val| [key, _convert_ast_node(hash_val)] }
38
+ ]
39
+ when Array
40
+ value.map { |val| _convert_ast_node(val) }
41
+ else
42
+ value
43
+ end
15
44
  end
16
45
  end
17
46
  end
@@ -18,33 +18,23 @@ module Ansible
18
18
  "{{ #{text} }}"
19
19
  end
20
20
 
21
+ # For the DSL, don't want to defer to regular method_missing
22
+ # rubocop:disable Style/MethodMissing
21
23
  def method_missing(id, *args, &block)
22
- result = begin
23
- _process_method id, *args, &block
24
- rescue StandardError => our_error
25
- begin
26
- super
27
- rescue NameError => ruby_error
28
- matching_line = ruby_error.backtrace
29
- .map { |str| str.split ':' }
30
- .find { |arr| arr[0] == '(eval)' }[1]
31
- raise "#{our_error.message} at line #{matching_line}!"
32
- end
33
- end
24
+ result = _process_method id, *args, &block
34
25
  method_missing_return id, result, *args
35
26
  end
27
+ # rubocop:enable Style/MethodMissing
36
28
 
37
29
  private
38
30
 
39
31
  def _ansible_include(filename, &block)
40
- args = if block
41
- args_builder = Args.new
42
- args_builder.instance_eval(&block)
43
- args_builder._result
44
- else
45
- {}
46
- end
47
- Models::Inclusion.new(args.merge(file: filename))
32
+ inclusion = Models::Inclusion.new(file: filename)
33
+ if block
34
+ args_builder = Args.new inclusion
35
+ args_builder.instance_eval(&block)
36
+ end
37
+ inclusion
48
38
  end
49
39
 
50
40
  def _valid_attributes
@@ -34,6 +34,23 @@ module Ansible
34
34
  @tasks_builder.handler name, &block
35
35
  end
36
36
 
37
+ def _handled_eval(ruby_filename)
38
+ ruby_code = File.read ruby_filename
39
+ instance_eval ruby_code, ruby_filename
40
+ # error code
41
+ nil
42
+ rescue StandardError => error
43
+ only_user_code = error.backtrace_locations
44
+ .select { |trace| trace.absolute_path == ruby_filename }
45
+ .map { |trace| format_trace_line(trace) }
46
+ message = "#{error.message}\n****Error Location:****\n#{only_user_code.join("\n")}"
47
+ Exception.new message
48
+ end
49
+
50
+ def format_trace_line(trace)
51
+ "#{trace.path}:#{trace.lineno}"
52
+ end
53
+
37
54
  # any order/lazy result
38
55
  # :reek:NilCheck - when nil is the simplest way to check this
39
56
  def _result
@@ -12,7 +12,7 @@ module Ansible
12
12
 
13
13
  def respond_to_missing?(method_name, _)
14
14
  klass_name = _klass_name method_name
15
- MODULES_MOD.const_defined?(klass_name) || super
15
+ MODULES_MOD.const_defined?(klass_name)
16
16
  end
17
17
 
18
18
  private
@@ -23,44 +23,32 @@ module Ansible
23
23
 
24
24
  def _process_method(id, *module_args, &block)
25
25
  module_klass = _module_klass(id)
26
- args = _arguments(block, module_args, module_klass)
27
- @result = module_klass.new(args)
26
+ @result = module_klass.new({})
27
+ _arguments(block, module_args)
28
28
  @result.validate!
29
29
  end
30
30
 
31
- def _arguments(block, module_args, module_klass)
32
- free_form_module = module_klass.include?(Ansible::Ruby::Modules::FreeForm)
31
+ def _arguments(block, module_args)
32
+ free_form_module = @result.class.include?(Ansible::Ruby::Modules::FreeForm)
33
33
  if module_args.any? && !free_form_module
34
34
  raise "Can't use arguments #{module_args} on this type of module"
35
35
  end
36
36
  if !free_form_module && !block
37
37
  raise 'You must supply a block when using this type of module'
38
38
  end
39
- args = {}
40
39
  free_form = free_form_module && _free_form_arg(module_args)
41
- args.merge! _block_args(&block)
42
- args[:free_form] = free_form if free_form
43
- _jinja_nodes(args)
44
- end
45
-
46
- def _jinja_nodes(args)
47
- Hash[args.map do |key, value|
48
- [key, _convert_ast_node(value)]
49
- end]
40
+ args_builder = Args.new @result do |attribute|
41
+ # More user friendly to get rid of = mutators
42
+ valid = _valid_module_attrib
43
+ raise "Unknown attribute '#{attribute}' for #{@result.class.name}.\n\nValid attributes are: #{valid}\n"
44
+ end
45
+ _block_args(args_builder, &block)
46
+ args_builder.free_form free_form if free_form
50
47
  end
51
48
 
52
- def _convert_ast_node(value)
53
- case value
54
- when DslBuilders::JinjaItemNode
55
- value.to_s
56
- when Hash
57
- Hash[
58
- value.map { |key, hash_val| [key, _convert_ast_node(hash_val)] }
59
- ]
60
- when Array
61
- value.map { |val| _convert_ast_node(val) }
62
- else
63
- value
49
+ def _valid_module_attrib
50
+ (@result.methods - Modules::Base.instance_methods).reject do |method|
51
+ method.to_s.end_with?('=') || method == :free_form
64
52
  end
65
53
  end
66
54
 
@@ -69,12 +57,10 @@ module Ansible
69
57
  MODULES_MOD.const_get _klass_name(id)
70
58
  end
71
59
 
72
- def _block_args(&block)
60
+ def _block_args(args_builder, &block)
73
61
  return {} unless block
74
62
  # Delegate everything to the args builder and apply it to the module class we located
75
- args_builder = Args.new
76
63
  args_builder.instance_eval(&block)
77
- args_builder._result
78
64
  end
79
65
 
80
66
  def _free_form_arg(module_args)
@@ -36,6 +36,20 @@ module Ansible
36
36
  @play_args[:gather_facts] = value
37
37
  end
38
38
 
39
+ def become(*args)
40
+ value = _implicit_bool args
41
+ @play_args[:become] = value
42
+ end
43
+
44
+ def become_user(value)
45
+ @play_args[:become_user] = value
46
+ end
47
+
48
+ def ignore_errors(*args)
49
+ value = _implicit_bool args
50
+ @play_args[:ignore_errors] = value
51
+ end
52
+
39
53
  def local_host
40
54
  hosts 'localhost'
41
55
  connection :local
@@ -69,20 +69,26 @@ module Ansible
69
69
  private
70
70
 
71
71
  def _process_method(id, *args, &block)
72
- if id == :ansible_include
73
- if @context == Models::Handler
74
- raise "Can't call inclusion inside a handler(yet), only in plays/handlers"
75
- else
76
- raise "Can't call inclusion inside a task, only in plays/handlers"
77
- end
78
- end
79
- # only 1 module, so don't try and do this again
80
- no_method_error id, "Only valid options are #{_valid_attributes}" if @module
72
+ _check_context if id == :ansible_include
81
73
  mcb = ModuleCall.new
74
+ if @module && mcb.respond_to?(id)
75
+ # only 1 module allowed per task, give a good error message
76
+ raise "Invalid module call `#{id}' since `#{@module.ansible_name}' module has already been used in this task. Only valid options are #{_valid_attributes}"
77
+ elsif @module
78
+ no_method_error id, "Only valid options are #{_valid_attributes}"
79
+ end
82
80
  mcb.send(id, *args, &block)
83
81
  @module = mcb._result
84
82
  end
85
83
 
84
+ def _check_context
85
+ if @context == Models::Handler
86
+ raise "Can't call inclusion inside a handler(yet), only in plays/handlers"
87
+ else
88
+ raise "Can't call inclusion inside a task, only in plays/handlers"
89
+ end
90
+ end
91
+
86
92
  def method_missing_return(_id, _result, *_args)
87
93
  # method_missing only used for modules here
88
94
  # Keep our register variables unique
@@ -11,8 +11,8 @@ module Ansible
11
11
  include ActiveModel::Validations
12
12
 
13
13
  def initialize(args = {})
14
+ @set_vars = {}
14
15
  super
15
- @set_vars = args.keys
16
16
  end
17
17
 
18
18
  class << self
@@ -25,7 +25,13 @@ module Ansible
25
25
  end
26
26
 
27
27
  def attribute(name, options = {})
28
- attr_accessor name
28
+ attr_reader name
29
+ # Want to keep track of what we set (avoid default issues)
30
+ ivar = "@#{name}".to_sym
31
+ define_method("#{name}=".to_sym) do |value|
32
+ @set_vars[name] = true
33
+ instance_variable_set ivar, value
34
+ end
29
35
  for_name = attr_options[name] ||= {}
30
36
  for_name.merge! options
31
37
  end
@@ -51,7 +57,7 @@ module Ansible
51
57
  def to_h
52
58
  validate!
53
59
  Hash[
54
- @set_vars.map do |key|
60
+ @set_vars.map do |key, _|
55
61
  value = send key
56
62
  options = self.class.attr_option(key)
57
63
  value = hashify value
@@ -7,6 +7,12 @@ module Ansible
7
7
  class Play < Base
8
8
  attribute :hosts
9
9
  validates :hosts, presence: true, type: TypeGeneric.new(String)
10
+ attribute :become
11
+ validates :become, type: MultipleTypes.new(TrueClass, FalseClass)
12
+ attribute :become_user
13
+ validates :become_user, type: String
14
+ attribute :ignore_errors
15
+ validates :ignore_errors, type: MultipleTypes.new(TrueClass, FalseClass)
10
16
  attribute :name
11
17
  validates :name, type: String
12
18
  attribute :tasks
@@ -6,9 +6,13 @@ module Ansible
6
6
  class Base < Models::Base
7
7
  def to_h
8
8
  {
9
- self.class.name.demodulize.underscore.to_sym => super
9
+ ansible_name.to_sym => super
10
10
  }
11
11
  end
12
+
13
+ def ansible_name
14
+ self.class.name.demodulize.underscore
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -28,10 +28,11 @@ module Ansible
28
28
  return if @rule_done
29
29
  ::Rake.application.create_rule '.yml' => '.rb' do |filename|
30
30
  puts "Updating Ansible file #{filename.name} from #{filename.source}..."
31
- ruby = File.read filename.source
32
- playbook_builder = Ansible::Ruby::DslBuilders::FileLevel.new
33
- playbook_builder.instance_eval ruby
34
- playbook = playbook_builder._result
31
+ file_builder = Ansible::Ruby::DslBuilders::FileLevel.new
32
+ exception = file_builder._handled_eval filename.source
33
+ # Avoid lengthy stack trace
34
+ raise exception if exception
35
+ playbook = file_builder._result
35
36
  yml = Ansible::Ruby::Serializer.serialize playbook.to_h
36
37
  File.write filename.name, yml
37
38
  end
@@ -1,5 +1,5 @@
1
1
  module Ansible
2
2
  module Ruby
3
- VERSION = '1.0.3'.freeze
3
+ VERSION = '1.0.4'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ansible-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brady Wied
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-27 00:00:00.000000000 Z
11
+ date: 2016-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake