ruby-terraform 1.7.0.pre.5 → 1.7.0.pre.8
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/Gemfile.lock +4 -4
- data/lib/ruby_terraform/models/known_value.rb +4 -0
- data/lib/ruby_terraform/models/list.rb +14 -0
- data/lib/ruby_terraform/models/map.rb +16 -1
- data/lib/ruby_terraform/models/objects.rb +67 -82
- data/lib/ruby_terraform/models/omitted_value.rb +41 -0
- data/lib/ruby_terraform/models/path.rb +160 -0
- data/lib/ruby_terraform/models/path_set.rb +137 -0
- data/lib/ruby_terraform/models/unknown_value.rb +4 -0
- data/lib/ruby_terraform/models/values.rb +5 -0
- data/lib/ruby_terraform/version.rb +1 -1
- data/lib/ruby_terraform.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29d107877da7868db24f108a46175dcc3f72b92baa17453cfd588784ecadbbe5
|
|
4
|
+
data.tar.gz: 4c3f6114288c1428313eb48c08a48d48ef1c824dbdcaf3c1f770c45a694687bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ef8aa4827093bdd287a3473ba0d61ce2812152812e3f60b8836b4aff306992ca77d5c619da0f591bf5f05c5f8b5a77181bb535e0f10a80adc924cbf8251264b9
|
|
7
|
+
data.tar.gz: 72f79d40b6d54ec9d5ad5998e953633b856778e1d3d565fddcac05ae8a7b0dd299de73a575624342c394f4e3bc39ac16bb2c492ae7717f3ced03bf9962dade25
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
ruby-terraform (1.7.0.pre.
|
|
4
|
+
ruby-terraform (1.7.0.pre.8)
|
|
5
5
|
immutable-struct (~> 2.4)
|
|
6
6
|
lino (~> 3.0)
|
|
7
7
|
|
|
@@ -115,17 +115,17 @@ GEM
|
|
|
115
115
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
116
116
|
rspec-support (~> 3.11.0)
|
|
117
117
|
rspec-support (3.11.0)
|
|
118
|
-
rubocop (1.
|
|
118
|
+
rubocop (1.32.0)
|
|
119
119
|
json (~> 2.3)
|
|
120
120
|
parallel (~> 1.10)
|
|
121
121
|
parser (>= 3.1.0.0)
|
|
122
122
|
rainbow (>= 2.2.2, < 4.0)
|
|
123
123
|
regexp_parser (>= 1.8, < 3.0)
|
|
124
124
|
rexml (>= 3.2.5, < 4.0)
|
|
125
|
-
rubocop-ast (>= 1.
|
|
125
|
+
rubocop-ast (>= 1.19.1, < 2.0)
|
|
126
126
|
ruby-progressbar (~> 1.7)
|
|
127
127
|
unicode-display_width (>= 1.4.0, < 3.0)
|
|
128
|
-
rubocop-ast (1.
|
|
128
|
+
rubocop-ast (1.19.1)
|
|
129
129
|
parser (>= 3.1.1.0)
|
|
130
130
|
rubocop-rake (0.6.0)
|
|
131
131
|
rubocop (~> 1.0)
|
|
@@ -51,6 +51,19 @@ module RubyTerraform
|
|
|
51
51
|
@sensitive
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
def render(level: 0, indent: ' ')
|
|
55
|
+
return '[]' if empty?
|
|
56
|
+
|
|
57
|
+
opts = { level: level + 1, indent: indent }
|
|
58
|
+
extra = level.times.collect { |_| indent }.join
|
|
59
|
+
lines =
|
|
60
|
+
value
|
|
61
|
+
.collect { |i| "#{extra}#{indent}#{i.render(opts)}" }
|
|
62
|
+
.join(",\n")
|
|
63
|
+
|
|
64
|
+
"[\n#{lines}\n#{extra}]"
|
|
65
|
+
end
|
|
66
|
+
|
|
54
67
|
def state
|
|
55
68
|
[@value, @sensitive]
|
|
56
69
|
end
|
|
@@ -59,6 +72,7 @@ module RubyTerraform
|
|
|
59
72
|
sensitive = sensitive? ? 'sensitive' : 'non-sensitive'
|
|
60
73
|
"#{value.inspect} (#{sensitive})"
|
|
61
74
|
end
|
|
75
|
+
|
|
62
76
|
alias to_s inspect
|
|
63
77
|
end
|
|
64
78
|
end
|
|
@@ -29,7 +29,7 @@ module RubyTerraform
|
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
def initialize(value, sensitive: false)
|
|
32
|
-
@value = value
|
|
32
|
+
@value = value.transform_keys(&:to_sym)
|
|
33
33
|
@sensitive = sensitive
|
|
34
34
|
end
|
|
35
35
|
|
|
@@ -47,6 +47,21 @@ module RubyTerraform
|
|
|
47
47
|
@sensitive
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def render(bare: false, level: 0, indent: ' ')
|
|
51
|
+
return '{}' if empty?
|
|
52
|
+
|
|
53
|
+
next_level = bare ? level : level + 1
|
|
54
|
+
self_indent = bare ? '' : indent
|
|
55
|
+
opts = { level: next_level, indent: indent }
|
|
56
|
+
extra = level.times.collect { |_| indent }.join
|
|
57
|
+
lines =
|
|
58
|
+
value
|
|
59
|
+
.collect { |k, v| "#{extra}#{self_indent}#{k} = #{v.render(opts)}" }
|
|
60
|
+
.join("\n")
|
|
61
|
+
|
|
62
|
+
bare ? lines : "{\n#{lines}\n#{extra}}"
|
|
63
|
+
end
|
|
64
|
+
|
|
50
65
|
def state
|
|
51
66
|
[@value, @sensitive]
|
|
52
67
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative './values'
|
|
4
|
+
require_relative './path_set'
|
|
4
5
|
|
|
5
6
|
module RubyTerraform
|
|
6
7
|
module Models
|
|
@@ -8,142 +9,121 @@ module RubyTerraform
|
|
|
8
9
|
module Objects
|
|
9
10
|
class << self
|
|
10
11
|
# rubocop:disable Style/RedundantAssignment
|
|
12
|
+
# rubocop:disable Metrics/MethodLength
|
|
11
13
|
def box(object, unknown: nil, sensitive: nil)
|
|
12
14
|
initial = boxed_empty_by_value(object)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
object = symbolise(object)
|
|
16
|
+
unknown = symbolised_or_native_empty(unknown, object)
|
|
17
|
+
sensitive = symbolised_or_native_empty(sensitive, object)
|
|
15
18
|
|
|
16
19
|
return Values.unknown(sensitive: sensitive) if unknown == true
|
|
17
20
|
|
|
21
|
+
unless object.is_a?(Hash) || object.is_a?(Array)
|
|
22
|
+
return Values.known(object, sensitive: sensitive)
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
boxed_unknown =
|
|
19
26
|
box_unknown(unknown, sensitive: sensitive, initial: initial)
|
|
27
|
+
|
|
20
28
|
boxed_object =
|
|
21
29
|
box_known(object, sensitive: sensitive, initial: boxed_unknown)
|
|
22
30
|
|
|
23
31
|
boxed_object
|
|
24
32
|
end
|
|
25
|
-
|
|
33
|
+
# rubocop:enable Metrics/MethodLength
|
|
26
34
|
# rubocop:enable Style/RedundantAssignment
|
|
27
35
|
|
|
28
|
-
def paths(object
|
|
29
|
-
|
|
30
|
-
if normalised.is_a?(Enumerable)
|
|
31
|
-
normalised.inject(accumulator) do |a, e|
|
|
32
|
-
paths(e[0], current + [e[1]], a)
|
|
33
|
-
end
|
|
34
|
-
else
|
|
35
|
-
accumulator + [current]
|
|
36
|
-
end
|
|
36
|
+
def paths(object)
|
|
37
|
+
PathSet.extract_from(object)
|
|
37
38
|
end
|
|
38
39
|
|
|
39
|
-
def known_values(
|
|
40
|
-
paths.map do |path|
|
|
41
|
-
resolved =
|
|
42
|
-
resolved_sensitive =
|
|
40
|
+
def known_values(path_set, object: {}, sensitive: {})
|
|
41
|
+
path_set.paths.map do |path|
|
|
42
|
+
resolved = path.read(object)
|
|
43
|
+
resolved_sensitive = path.read(sensitive) == true
|
|
43
44
|
|
|
44
45
|
Values.known(resolved, sensitive: resolved_sensitive)
|
|
45
46
|
end
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
def unknown_values(
|
|
49
|
-
paths.map do |path|
|
|
50
|
-
resolved =
|
|
51
|
-
resolved_sensitive =
|
|
49
|
+
def unknown_values(path_set, unknown: {}, sensitive: {})
|
|
50
|
+
path_set.paths.map do |path|
|
|
51
|
+
resolved = path.read(unknown)
|
|
52
|
+
resolved_sensitive = path.read(sensitive) == true
|
|
52
53
|
|
|
53
54
|
resolved ? Values.unknown(sensitive: resolved_sensitive) : nil
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
57
|
|
|
58
|
+
def object(path_set, values,
|
|
59
|
+
sensitive: {},
|
|
60
|
+
initial: Values.empty_map,
|
|
61
|
+
filler: Values.omitted)
|
|
62
|
+
gaps = path_set.gaps
|
|
63
|
+
extra_values = gaps.paths.collect { |p| [p, filler] }
|
|
64
|
+
|
|
65
|
+
path_values = path_set.paths.zip(values) + extra_values
|
|
66
|
+
path_values = sort_by_path(path_values)
|
|
67
|
+
|
|
68
|
+
update_all(initial, path_values, sensitive)
|
|
69
|
+
end
|
|
70
|
+
|
|
57
71
|
private
|
|
58
72
|
|
|
59
|
-
# rubocop:disable Metrics/MethodLength
|
|
60
73
|
def box_unknown(unknown, sensitive: {}, initial: Values.empty_map)
|
|
61
|
-
|
|
62
|
-
if root_path(unknown_paths)
|
|
63
|
-
return Values.unknown(sensitive: sensitive)
|
|
64
|
-
end
|
|
65
|
-
|
|
74
|
+
path_set = paths(unknown)
|
|
66
75
|
unknown_values = unknown_values(
|
|
67
|
-
|
|
76
|
+
path_set, unknown: unknown, sensitive: sensitive
|
|
68
77
|
)
|
|
69
|
-
|
|
70
78
|
object(
|
|
71
|
-
|
|
72
|
-
sensitive: sensitive, initial: initial
|
|
79
|
+
path_set, unknown_values, sensitive: sensitive, initial: initial
|
|
73
80
|
)
|
|
74
81
|
end
|
|
75
|
-
# rubocop:enable Metrics/MethodLength
|
|
76
82
|
|
|
77
|
-
# rubocop:disable Metrics/MethodLength
|
|
78
83
|
def box_known(object, sensitive: {}, initial: Values.empty_map)
|
|
79
|
-
|
|
80
|
-
if root_path(object_paths)
|
|
81
|
-
return Values.known(object, sensitive: sensitive)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
+
path_set = paths(object)
|
|
84
85
|
object_values = known_values(
|
|
85
|
-
|
|
86
|
+
path_set, object: object, sensitive: sensitive
|
|
86
87
|
)
|
|
87
|
-
|
|
88
88
|
object(
|
|
89
|
-
|
|
90
|
-
sensitive: sensitive, initial: initial
|
|
89
|
+
path_set, object_values, sensitive: sensitive, initial: initial
|
|
91
90
|
)
|
|
92
91
|
end
|
|
93
|
-
# rubocop:enable Metrics/MethodLength
|
|
94
92
|
|
|
95
|
-
def object
|
|
96
|
-
|
|
97
|
-
.zip(values)
|
|
98
|
-
.each_with_object(initial) do |path_value, object|
|
|
93
|
+
def update_all(object, path_values, sensitive = {})
|
|
94
|
+
path_values.each_with_object(object) do |path_value, obj|
|
|
99
95
|
path, value = path_value
|
|
100
|
-
update_in(
|
|
96
|
+
update_in(obj, path, value, sensitive: sensitive)
|
|
101
97
|
end
|
|
102
98
|
end
|
|
103
99
|
|
|
104
100
|
def update_in(object, path, value, sensitive: {})
|
|
105
|
-
path.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
update_object_for_step(object, pointer, value, sensitive: sensitive)
|
|
110
|
-
update_context_for_step(pointer)
|
|
101
|
+
path.traverse(object) do |obj, step|
|
|
102
|
+
update_object_for_step(
|
|
103
|
+
obj, step, value, sensitive: sensitive
|
|
104
|
+
)
|
|
111
105
|
end
|
|
112
|
-
object
|
|
113
106
|
end
|
|
114
107
|
|
|
115
108
|
# rubocop:disable Metrics/MethodLength
|
|
116
|
-
def update_object_for_step(object,
|
|
117
|
-
|
|
109
|
+
def update_object_for_step(object, step, value, sensitive: {})
|
|
110
|
+
parent = step.seen.read(object, default: object)
|
|
111
|
+
upcoming = step.remaining.first
|
|
118
112
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
resolved_sensitive = try_dig(sensitive, seen + [step]) == true
|
|
113
|
+
found_sensitive = step.seen.append(step.element).read(sensitive)
|
|
114
|
+
resolved_sensitive = found_sensitive == true
|
|
123
115
|
resolved =
|
|
124
|
-
if remaining.empty?
|
|
116
|
+
if step.remaining.empty?
|
|
125
117
|
value
|
|
126
118
|
else
|
|
127
119
|
boxed_empty_by_key(upcoming, sensitive: resolved_sensitive)
|
|
128
120
|
end
|
|
129
121
|
|
|
130
|
-
parent[step] ||= resolved
|
|
131
|
-
end
|
|
132
|
-
# rubocop:enable Metrics/MethodLength
|
|
133
|
-
|
|
134
|
-
def update_context_for_step(pointer)
|
|
135
|
-
seen, step, remaining = pointer
|
|
136
|
-
[seen + [step], remaining.drop(1)]
|
|
137
|
-
end
|
|
122
|
+
parent[step.element] ||= resolved
|
|
138
123
|
|
|
139
|
-
|
|
140
|
-
return default if path.empty?
|
|
141
|
-
|
|
142
|
-
result = object.dig(*path)
|
|
143
|
-
result.nil? ? default : result
|
|
144
|
-
rescue NoMethodError, TypeError
|
|
145
|
-
default
|
|
124
|
+
object
|
|
146
125
|
end
|
|
126
|
+
# rubocop:enable Metrics/MethodLength
|
|
147
127
|
|
|
148
128
|
def boxed_empty_by_key(key, sensitive: false)
|
|
149
129
|
if key.is_a?(Numeric)
|
|
@@ -168,16 +148,21 @@ module RubyTerraform
|
|
|
168
148
|
end
|
|
169
149
|
end
|
|
170
150
|
|
|
171
|
-
def
|
|
151
|
+
def symbolise(object)
|
|
172
152
|
case object
|
|
173
|
-
when
|
|
174
|
-
|
|
175
|
-
else
|
|
153
|
+
when Hash
|
|
154
|
+
object.to_h { |key, value| [key.to_sym, symbolise(value)] }
|
|
155
|
+
else
|
|
156
|
+
object
|
|
176
157
|
end
|
|
177
158
|
end
|
|
178
159
|
|
|
179
|
-
def
|
|
180
|
-
|
|
160
|
+
def symbolised_or_native_empty(object, target)
|
|
161
|
+
object ? symbolise(object) : native_empty_by_value(target)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def sort_by_path(path_values)
|
|
165
|
+
path_values.sort { |a, b| a[0] <=> b[0] }
|
|
181
166
|
end
|
|
182
167
|
end
|
|
183
168
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../value_equality'
|
|
4
|
+
|
|
5
|
+
module RubyTerraform
|
|
6
|
+
module Models
|
|
7
|
+
class OmittedValue
|
|
8
|
+
include ValueEquality
|
|
9
|
+
|
|
10
|
+
def initialize(sensitive: false)
|
|
11
|
+
@sensitive = sensitive
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def value
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
alias unbox value
|
|
18
|
+
|
|
19
|
+
def known?
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def sensitive?
|
|
24
|
+
@sensitive
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def render(**_)
|
|
28
|
+
'...'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def state
|
|
32
|
+
[@sensitive]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def inspect
|
|
36
|
+
sensitive = sensitive? ? 'sensitive' : 'non-sensitive'
|
|
37
|
+
"... (unknown, #{sensitive})"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../value_equality'
|
|
4
|
+
|
|
5
|
+
module RubyTerraform
|
|
6
|
+
module Models
|
|
7
|
+
# rubocop:disable Metrics/ClassLength
|
|
8
|
+
class Path
|
|
9
|
+
class << self
|
|
10
|
+
def empty
|
|
11
|
+
new([])
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
extend Forwardable
|
|
16
|
+
|
|
17
|
+
include Comparable
|
|
18
|
+
include ValueEquality
|
|
19
|
+
|
|
20
|
+
def_delegators(:@elements, :first, :last, :length, :empty?)
|
|
21
|
+
|
|
22
|
+
attr_reader(:elements)
|
|
23
|
+
|
|
24
|
+
def initialize(elements)
|
|
25
|
+
@elements = elements.compact
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def references_any_lists?
|
|
29
|
+
elements.any? { |e| e.is_a?(Numeric) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def references_any_maps?
|
|
33
|
+
elements.any? { |e| e.is_a?(Symbol) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def same_parent_collection?(other)
|
|
37
|
+
return true if self == other
|
|
38
|
+
|
|
39
|
+
left, right = diff(other)
|
|
40
|
+
left.length == 1 && right.length == 1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def list_indices
|
|
44
|
+
elements.each_with_index.inject([]) do |acc, element_index|
|
|
45
|
+
element, index = element_index
|
|
46
|
+
element.is_a?(Numeric) ? acc + [[index, element]] : acc
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_location(index)
|
|
51
|
+
return self.class.new([]) if index.negative?
|
|
52
|
+
|
|
53
|
+
self.class.new(elements[0..index])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def before_location(index)
|
|
57
|
+
return self.class.new([]) if index.negative?
|
|
58
|
+
|
|
59
|
+
self.class.new(elements[0...index])
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def append(element)
|
|
63
|
+
self.class.new(elements + [element])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def drop(count = 1)
|
|
67
|
+
self.class.new(elements.drop(count))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def diff(other)
|
|
71
|
+
left, right = match_lengths(elements, other.elements)
|
|
72
|
+
pairwise = left.zip(right)
|
|
73
|
+
difference = pairwise.drop_while { |e| e[0] == e[1] }
|
|
74
|
+
difference = difference.empty? ? [[], []] : difference.transpose
|
|
75
|
+
difference.map { |e| self.class.new(e) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def traverse(initial, &block)
|
|
79
|
+
initial_context = initial_traversal_context(initial)
|
|
80
|
+
final_context = elements.inject(initial_context) do |context, element|
|
|
81
|
+
state = block.call(context[:state], context[:step])
|
|
82
|
+
next_traversal_context(state, context[:step], element)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
final_context[:state]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def read(object, default: nil)
|
|
89
|
+
return default if empty?
|
|
90
|
+
|
|
91
|
+
result = object.dig(*elements)
|
|
92
|
+
result.nil? ? default : result
|
|
93
|
+
rescue NoMethodError, TypeError
|
|
94
|
+
default
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def <=>(other)
|
|
98
|
+
return 0 if self == other
|
|
99
|
+
|
|
100
|
+
left, right = diff(other)
|
|
101
|
+
return -1 if left.empty?
|
|
102
|
+
return 1 if right.empty?
|
|
103
|
+
|
|
104
|
+
compare_numbers_before_symbols(left.first, right.first)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def state
|
|
108
|
+
[elements]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
class TraversalStep
|
|
114
|
+
attr_reader(:seen, :element, :remaining)
|
|
115
|
+
|
|
116
|
+
def initialize(seen, element, remaining)
|
|
117
|
+
@seen = seen
|
|
118
|
+
@element = element
|
|
119
|
+
@remaining = remaining
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def initial_traversal_context(state)
|
|
124
|
+
{
|
|
125
|
+
state: state,
|
|
126
|
+
step: TraversalStep.new(self.class.empty, first, drop(1))
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def next_traversal_context(state, position, step)
|
|
131
|
+
{
|
|
132
|
+
state: state,
|
|
133
|
+
step: TraversalStep.new(position.seen.append(step),
|
|
134
|
+
position.remaining.first,
|
|
135
|
+
position.remaining.drop(1))
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def compare_numbers_before_symbols(left, right)
|
|
140
|
+
return -1 if left.is_a?(Numeric) && right.is_a?(Symbol)
|
|
141
|
+
return 1 if left.is_a?(Symbol) && right.is_a?(Numeric)
|
|
142
|
+
|
|
143
|
+
left <=> right
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def match_lengths(left, right)
|
|
147
|
+
max_length = [left.count, right.count].max
|
|
148
|
+
[
|
|
149
|
+
pad_to_length(left, max_length),
|
|
150
|
+
pad_to_length(right, max_length)
|
|
151
|
+
]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def pad_to_length(array, target_length)
|
|
155
|
+
array.clone.fill(nil, array.count, target_length - array.count)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
# rubocop:enable Metrics/ClassLength
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../value_equality'
|
|
4
|
+
|
|
5
|
+
module RubyTerraform
|
|
6
|
+
module Models
|
|
7
|
+
class PathSet
|
|
8
|
+
class << self
|
|
9
|
+
def empty
|
|
10
|
+
new([])
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def extract_from(object)
|
|
14
|
+
empty.add_paths_from(object)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
extend Forwardable
|
|
19
|
+
|
|
20
|
+
include ValueEquality
|
|
21
|
+
|
|
22
|
+
def_delegators(:@paths, :empty?)
|
|
23
|
+
|
|
24
|
+
attr_reader(:paths)
|
|
25
|
+
|
|
26
|
+
def initialize(paths)
|
|
27
|
+
@paths = paths
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def add_paths_from(object)
|
|
31
|
+
self.class.new(paths + extract_paths_from(object))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def gaps
|
|
35
|
+
initial_context = { last: Path.new([]), complete: [] }
|
|
36
|
+
result = paths.sort.inject(initial_context) do |acc, path|
|
|
37
|
+
current_path = path
|
|
38
|
+
last_path = acc[:last]
|
|
39
|
+
missing_paths = determine_missing_paths(last_path, current_path)
|
|
40
|
+
updated_paths = acc[:complete] + missing_paths
|
|
41
|
+
|
|
42
|
+
{ last: current_path, complete: updated_paths }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
self.class.new(result[:complete])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def state
|
|
49
|
+
[paths]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def extract_paths_from(
|
|
55
|
+
object,
|
|
56
|
+
current = Path.new([]),
|
|
57
|
+
accumulator = []
|
|
58
|
+
)
|
|
59
|
+
normalised = normalise(object)
|
|
60
|
+
if normalised.is_a?(Enumerable)
|
|
61
|
+
normalised.inject(accumulator) do |a, e|
|
|
62
|
+
extract_paths_from(e[0], current.append(e[1]), a)
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
accumulator + [current]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def normalise(object)
|
|
70
|
+
case object
|
|
71
|
+
when Array then object.each_with_index.to_a
|
|
72
|
+
when Hash
|
|
73
|
+
object.to_a.map do |e|
|
|
74
|
+
[e[1], e[0].to_sym]
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
object
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# rubocop:disable Metrics/MethodLength
|
|
82
|
+
def determine_missing_paths(last_path, current_path)
|
|
83
|
+
last_indices = resolve_last_indices(last_path, current_path)
|
|
84
|
+
current_indices = current_path.list_indices
|
|
85
|
+
|
|
86
|
+
current_indices.inject([]) do |acc, current_index|
|
|
87
|
+
current_location, current_element = current_index
|
|
88
|
+
last_index =
|
|
89
|
+
last_indices.find { |index| index[0] == current_location }
|
|
90
|
+
last_element = last_index[1]
|
|
91
|
+
|
|
92
|
+
next(acc) unless current_element.positive?
|
|
93
|
+
|
|
94
|
+
start_element = last_element.nil? ? 0 : last_element + 1
|
|
95
|
+
next(acc) if start_element == current_element
|
|
96
|
+
|
|
97
|
+
acc + create_missing_paths(
|
|
98
|
+
start_element, current_element, current_path, current_location
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
# rubocop:enable Metrics/MethodLength
|
|
103
|
+
|
|
104
|
+
# rubocop:disable Metrics/MethodLength
|
|
105
|
+
def resolve_last_indices(last_path, current_path)
|
|
106
|
+
last_indices = last_path.list_indices
|
|
107
|
+
current_indices = current_path.list_indices
|
|
108
|
+
|
|
109
|
+
current_indices.collect do |current_entry|
|
|
110
|
+
location, current_element = current_entry
|
|
111
|
+
last_entry = last_indices.find { |index| index[0] == location }
|
|
112
|
+
last_element = last_entry&.slice(1)
|
|
113
|
+
reset_entry = [location, nil]
|
|
114
|
+
|
|
115
|
+
next(reset_entry) unless last_element
|
|
116
|
+
next(reset_entry) if current_element < last_element
|
|
117
|
+
|
|
118
|
+
current_sub_path = current_path.to_location(location)
|
|
119
|
+
last_sub_path = last_path.to_location(location)
|
|
120
|
+
|
|
121
|
+
unless current_sub_path.same_parent_collection?(last_sub_path)
|
|
122
|
+
next(reset_entry)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
last_entry
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
# rubocop:enable Metrics/MethodLength
|
|
129
|
+
|
|
130
|
+
def create_missing_paths(from, to, path, location)
|
|
131
|
+
(from...to).collect do |element|
|
|
132
|
+
path.before_location(location).append(element)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -4,6 +4,7 @@ require_relative './list'
|
|
|
4
4
|
require_relative './map'
|
|
5
5
|
require_relative './known_value'
|
|
6
6
|
require_relative './unknown_value'
|
|
7
|
+
require_relative './omitted_value'
|
|
7
8
|
|
|
8
9
|
module RubyTerraform
|
|
9
10
|
module Models
|
|
@@ -17,6 +18,10 @@ module RubyTerraform
|
|
|
17
18
|
UnknownValue.new(sensitive: sensitive)
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
def omitted(sensitive: false)
|
|
22
|
+
OmittedValue.new(sensitive: sensitive)
|
|
23
|
+
end
|
|
24
|
+
|
|
20
25
|
def list(value, sensitive: false)
|
|
21
26
|
List.new(value, sensitive: sensitive)
|
|
22
27
|
end
|
data/lib/ruby_terraform.rb
CHANGED
|
@@ -601,7 +601,7 @@ module RubyTerraform
|
|
|
601
601
|
# actions.
|
|
602
602
|
#
|
|
603
603
|
# You can optionally save the plan to a file, which you can then pass to
|
|
604
|
-
# the {#
|
|
604
|
+
# the {#read} command to perform exactly the actions described in the plan.
|
|
605
605
|
#
|
|
606
606
|
# @param parameters The parameters used to invoke the command
|
|
607
607
|
# @option parameters [String] :plan The path to a directory containing
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-terraform
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.0.pre.
|
|
4
|
+
version: 1.7.0.pre.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- InfraBlocks Maintainers
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-07-
|
|
11
|
+
date: 2022-07-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: immutable-struct
|
|
@@ -323,6 +323,9 @@ files:
|
|
|
323
323
|
- lib/ruby_terraform/models/list.rb
|
|
324
324
|
- lib/ruby_terraform/models/map.rb
|
|
325
325
|
- lib/ruby_terraform/models/objects.rb
|
|
326
|
+
- lib/ruby_terraform/models/omitted_value.rb
|
|
327
|
+
- lib/ruby_terraform/models/path.rb
|
|
328
|
+
- lib/ruby_terraform/models/path_set.rb
|
|
326
329
|
- lib/ruby_terraform/models/plan.rb
|
|
327
330
|
- lib/ruby_terraform/models/resource_change.rb
|
|
328
331
|
- lib/ruby_terraform/models/unknown_value.rb
|